refactor(windows): re-apply guidance with minimal formatting changes

Addresses feedback about formatting noise by reverting system-prompt.ts and re-applying logic minimally. PR template removed (moved to separate PR).
This commit is contained in:
Nathan Hangen 2026-01-28 19:33:13 -05:00
parent e3f4194e94
commit 38f91f875b
3 changed files with 113 additions and 95 deletions

View File

@ -14,6 +14,8 @@ describe("isFailoverErrorMessage", () => {
const samples = [
"invalid api key",
"429 rate limit exceeded",
"No available auth profile for openai-codex (all in cooldown or unavailable).",
"Provider openai-codex is in cooldown (all profiles unavailable)",
"Your credit balance is too low",
"request timed out",
"invalid request format",

View File

@ -362,6 +362,10 @@ const ERROR_PATTERNS = {
"quota exceeded",
"resource_exhausted",
"usage limit",
// Auth-profile selection can fail due to provider-wide cooldown after repeated rate limits.
// Treat as rate_limit so model fallback can engage even before a request is sent.
/all in cooldown/i,
/in cooldown \(all profiles unavailable\)/i,
],
overloaded: [/overloaded_error|"type"\s*:\s*"overloaded_error"/i, "overloaded"],
timeout: ["timeout", "timed out", "deadline exceeded", "context deadline exceeded"],
@ -388,6 +392,8 @@ const ERROR_PATTERNS = {
/\b403\b/,
"no credentials found",
"no api key found",
// Agent can fail before request if no usable auth profile exists.
/no available auth profile/i,
],
format: [
"string should match pattern",

View File

@ -83,21 +83,21 @@ function buildMessagingSection(params: {
"- Never use exec/curl for provider messaging; Moltbot handles all routing internally.",
params.availableTools.has("message")
? [
"",
"### message tool",
"- Use `message` for proactive sends + channel actions (polls, reactions, etc.).",
"- For `action=send`, include `to` and `message`.",
`- If multiple channels are configured, pass \`channel\` (${params.messageChannelOptions}).`,
`- If you use \`message\` (\`action=send\`) to deliver your user-visible reply, respond with ONLY: ${SILENT_REPLY_TOKEN} (avoid duplicate replies).`,
params.inlineButtonsEnabled
? "- Inline buttons supported. Use `action=send` with `buttons=[[{text,callback_data}]]` (callback_data routes back as a user message)."
: params.runtimeChannel
? `- Inline buttons not enabled for ${params.runtimeChannel}. If you need them, ask to set ${params.runtimeChannel}.capabilities.inlineButtons ("dm"|"group"|"all"|"allowlist").`
: "",
...(params.messageToolHints ?? []),
]
.filter(Boolean)
.join("\n")
"",
"### message tool",
"- Use `message` for proactive sends + channel actions (polls, reactions, etc.).",
"- For `action=send`, include `to` and `message`.",
`- If multiple channels are configured, pass \`channel\` (${params.messageChannelOptions}).`,
`- If you use \`message\` (\`action=send\`) to deliver your user-visible reply, respond with ONLY: ${SILENT_REPLY_TOKEN} (avoid duplicate replies).`,
params.inlineButtonsEnabled
? "- Inline buttons supported. Use `action=send` with `buttons=[[{text,callback_data}]]` (callback_data routes back as a user message)."
: params.runtimeChannel
? `- Inline buttons not enabled for ${params.runtimeChannel}. If you need them, ask to set ${params.runtimeChannel}.capabilities.inlineButtons ("dm"|"group"|"all"|"allowlist").`
: "",
...(params.messageToolHints ?? []),
]
.filter(Boolean)
.join("\n")
: "",
"",
];
@ -282,15 +282,15 @@ export function buildAgentSystemPrompt(params: {
: undefined;
const reasoningHint = params.reasoningTagHint
? [
"ALL internal reasoning MUST be inside <think>...</think>.",
"Do not output any analysis outside <think>.",
"Format every reply as <think>...</think> then <final>...</final>, with no other text.",
"Only the final user-visible reply may appear inside <final>.",
"Only text inside <final> is shown to the user; everything else is discarded and never seen by the user.",
"Example:",
"<think>Short internal reasoning.</think>",
"<final>Hey there! What would you like to do next?</final>",
].join(" ")
"ALL internal reasoning MUST be inside <think>...</think>.",
"Do not output any analysis outside <think>.",
"Format every reply as <think>...</think> then <final>...</final>, with no other text.",
"Only the final user-visible reply may appear inside <final>.",
"Only text inside <final> is shown to the user; everything else is discarded and never seen by the user.",
"Example:",
"<think>Short internal reasoning.</think>",
"<final>Hey there! What would you like to do next?</final>",
].join(" ")
: undefined;
const reasoningLevel = params.reasoningLevel ?? "off";
const userTimezone = params.userTimezone?.trim();
@ -336,21 +336,21 @@ export function buildAgentSystemPrompt(params: {
toolLines.length > 0
? toolLines.join("\n")
: [
"Pi lists the standard tools above. This runtime enables:",
"- grep: search file contents for patterns",
"- find: find files by glob pattern",
"- ls: list directory contents",
"- apply_patch: apply multi-file patches",
`- ${execToolName}: run shell commands (supports background via yieldMs/background)`,
`- ${processToolName}: manage background exec sessions`,
"- browser: control clawd's dedicated browser",
"- canvas: present/eval/snapshot the Canvas",
"- nodes: list/describe/notify/camera/screen on paired nodes",
"- cron: manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
"- sessions_list: list sessions",
"- sessions_history: fetch session history",
"- sessions_send: send to another session",
].join("\n"),
"Pi lists the standard tools above. This runtime enables:",
"- grep: search file contents for patterns",
"- find: find files by glob pattern",
"- ls: list directory contents",
"- apply_patch: apply multi-file patches",
`- ${execToolName}: run shell commands (supports background via yieldMs/background)`,
`- ${processToolName}: manage background exec sessions`,
"- browser: control clawd's dedicated browser",
"- canvas: present/eval/snapshot the Canvas",
"- nodes: list/describe/notify/camera/screen on paired nodes",
"- cron: manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
"- sessions_list: list sessions",
"- sessions_history: fetch session history",
"- sessions_send: send to another session",
].join("\n"),
"TOOLS.md does not control tool availability; it is user guidance for how to use external tools.",
"If a task is more complex or takes longer, spawn a sub-agent. It will do the work for you and ping you when it's done. You can always check up on it.",
"",
@ -375,11 +375,11 @@ export function buildAgentSystemPrompt(params: {
hasGateway && !isMinimal ? "## Moltbot Self-Update" : "",
hasGateway && !isMinimal
? [
"Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
"Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
"Actions: config.get, config.schema, config.apply (validate + write full config, then restart), update.run (update deps or git, then restart).",
"After restart, Moltbot pings the last active session automatically.",
].join("\n")
"Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
"Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
"Actions: config.get, config.schema, config.apply (validate + write full config, then restart), update.run (update deps or git, then restart).",
"After restart, Moltbot pings the last active session automatically.",
].join("\n")
: "",
hasGateway && !isMinimal ? "" : "",
"",
@ -399,47 +399,57 @@ export function buildAgentSystemPrompt(params: {
"Treat this directory as the single global workspace for file operations unless explicitly instructed otherwise.",
...workspaceNotes,
"",
...(runtimeInfo?.os?.toLowerCase().includes("windows")
? [
"## Windows Shell Guidance",
"You are running on Windows (PowerShell).",
"- Use PowerShell syntax (e.g. `$env:VAR` instead of `%VAR%` or `$VAR`).",
"- Do NOT use Unix commands like `grep`, `sed`, `awk`, `head`, `tail` in exec/shell (PowerShell) commands unless you are sure they are installed. Pi's built-in tools named `grep`, `find`, and `ls` are safe to use.",
"- Use `findstr` or `Select-String` instead of `grep`.",
"- Use `Get-ChildItem` (dir/ls) with `-Recurse` instead of `find`.",
"",
]
: []),
...docsSection,
params.sandboxInfo?.enabled ? "## Sandbox" : "",
params.sandboxInfo?.enabled
? [
"You are running in a sandboxed runtime (tools execute in Docker).",
"Some tools may be unavailable due to sandbox policy.",
"Sub-agents stay sandboxed (no elevated/host access). Need outside-sandbox read/write? Don't spawn; ask first.",
params.sandboxInfo.workspaceDir
? `Sandbox workspace: ${params.sandboxInfo.workspaceDir}`
"You are running in a sandboxed runtime (tools execute in Docker).",
"Some tools may be unavailable due to sandbox policy.",
"Sub-agents stay sandboxed (no elevated/host access). Need outside-sandbox read/write? Don't spawn; ask first.",
params.sandboxInfo.workspaceDir
? `Sandbox workspace: ${params.sandboxInfo.workspaceDir}`
: "",
params.sandboxInfo.workspaceAccess
? `Agent workspace access: ${params.sandboxInfo.workspaceAccess}${params.sandboxInfo.agentWorkspaceMount
? ` (mounted at ${params.sandboxInfo.agentWorkspaceMount})`
: ""
}`
: "",
params.sandboxInfo.browserBridgeUrl ? "Sandbox browser: enabled." : "",
params.sandboxInfo.browserNoVncUrl
? `Sandbox browser observer (noVNC): ${params.sandboxInfo.browserNoVncUrl}`
: "",
params.sandboxInfo.hostBrowserAllowed === true
? "Host browser control: allowed."
: params.sandboxInfo.hostBrowserAllowed === false
? "Host browser control: blocked."
: "",
params.sandboxInfo.workspaceAccess
? `Agent workspace access: ${params.sandboxInfo.workspaceAccess}${
params.sandboxInfo.agentWorkspaceMount
? ` (mounted at ${params.sandboxInfo.agentWorkspaceMount})`
: ""
}`
: "",
params.sandboxInfo.browserBridgeUrl ? "Sandbox browser: enabled." : "",
params.sandboxInfo.browserNoVncUrl
? `Sandbox browser observer (noVNC): ${params.sandboxInfo.browserNoVncUrl}`
: "",
params.sandboxInfo.hostBrowserAllowed === true
? "Host browser control: allowed."
: params.sandboxInfo.hostBrowserAllowed === false
? "Host browser control: blocked."
: "",
params.sandboxInfo.elevated?.allowed
? "Elevated exec is available for this session."
: "",
params.sandboxInfo.elevated?.allowed
? "User can toggle with /elevated on|off|ask|full."
: "",
params.sandboxInfo.elevated?.allowed
? "You may also send /elevated on|off|ask|full when needed."
: "",
params.sandboxInfo.elevated?.allowed
? `Current elevated level: ${params.sandboxInfo.elevated.defaultLevel} (ask runs exec on host with approvals; full auto-approves).`
: "",
]
.filter(Boolean)
.join("\n")
params.sandboxInfo.elevated?.allowed
? "Elevated exec is available for this session."
: "",
params.sandboxInfo.elevated?.allowed
? "User can toggle with /elevated on|off|ask|full."
: "",
params.sandboxInfo.elevated?.allowed
? "You may also send /elevated on|off|ask|full when needed."
: "",
params.sandboxInfo.elevated?.allowed
? `Current elevated level: ${params.sandboxInfo.elevated.defaultLevel} (ask runs exec on host with approvals; full auto-approves).`
: "",
]
.filter(Boolean)
.join("\n")
: "",
params.sandboxInfo?.enabled ? "" : "",
...buildUserIdentitySection(ownerLine, isMinimal),
@ -472,22 +482,22 @@ export function buildAgentSystemPrompt(params: {
const guidanceText =
level === "minimal"
? [
`Reactions are enabled for ${channel} in MINIMAL mode.`,
"React ONLY when truly relevant:",
"- Acknowledge important user requests or confirmations",
"- Express genuine sentiment (humor, appreciation) sparingly",
"- Avoid reacting to routine messages or your own replies",
"Guideline: at most 1 reaction per 5-10 exchanges.",
].join("\n")
`Reactions are enabled for ${channel} in MINIMAL mode.`,
"React ONLY when truly relevant:",
"- Acknowledge important user requests or confirmations",
"- Express genuine sentiment (humor, appreciation) sparingly",
"- Avoid reacting to routine messages or your own replies",
"Guideline: at most 1 reaction per 5-10 exchanges.",
].join("\n")
: [
`Reactions are enabled for ${channel} in EXTENSIVE mode.`,
"Feel free to react liberally:",
"- Acknowledge messages with appropriate emojis",
"- Express sentiment and personality through reactions",
"- React to interesting content, humor, or notable events",
"- Use reactions to confirm understanding or agreement",
"Guideline: react whenever it feels natural.",
].join("\n");
`Reactions are enabled for ${channel} in EXTENSIVE mode.`,
"Feel free to react liberally:",
"- Acknowledge messages with appropriate emojis",
"- Express sentiment and personality through reactions",
"- React to interesting content, humor, or notable events",
"- Use reactions to confirm understanding or agreement",
"Guideline: react whenever it feels natural.",
].join("\n");
lines.push("## Reactions", guidanceText, "");
}
if (reasoningHint) {