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 = [ const samples = [
"invalid api key", "invalid api key",
"429 rate limit exceeded", "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", "Your credit balance is too low",
"request timed out", "request timed out",
"invalid request format", "invalid request format",

View File

@ -362,6 +362,10 @@ const ERROR_PATTERNS = {
"quota exceeded", "quota exceeded",
"resource_exhausted", "resource_exhausted",
"usage limit", "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"], overloaded: [/overloaded_error|"type"\s*:\s*"overloaded_error"/i, "overloaded"],
timeout: ["timeout", "timed out", "deadline exceeded", "context deadline exceeded"], timeout: ["timeout", "timed out", "deadline exceeded", "context deadline exceeded"],
@ -388,6 +392,8 @@ const ERROR_PATTERNS = {
/\b403\b/, /\b403\b/,
"no credentials found", "no credentials found",
"no api key found", "no api key found",
// Agent can fail before request if no usable auth profile exists.
/no available auth profile/i,
], ],
format: [ format: [
"string should match pattern", "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.", "- Never use exec/curl for provider messaging; Moltbot handles all routing internally.",
params.availableTools.has("message") params.availableTools.has("message")
? [ ? [
"", "",
"### message tool", "### message tool",
"- Use `message` for proactive sends + channel actions (polls, reactions, etc.).", "- Use `message` for proactive sends + channel actions (polls, reactions, etc.).",
"- For `action=send`, include `to` and `message`.", "- For `action=send`, include `to` and `message`.",
`- If multiple channels are configured, pass \`channel\` (${params.messageChannelOptions}).`, `- 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).`, `- If you use \`message\` (\`action=send\`) to deliver your user-visible reply, respond with ONLY: ${SILENT_REPLY_TOKEN} (avoid duplicate replies).`,
params.inlineButtonsEnabled params.inlineButtonsEnabled
? "- Inline buttons supported. Use `action=send` with `buttons=[[{text,callback_data}]]` (callback_data routes back as a user message)." ? "- Inline buttons supported. Use `action=send` with `buttons=[[{text,callback_data}]]` (callback_data routes back as a user message)."
: params.runtimeChannel : params.runtimeChannel
? `- Inline buttons not enabled for ${params.runtimeChannel}. If you need them, ask to set ${params.runtimeChannel}.capabilities.inlineButtons ("dm"|"group"|"all"|"allowlist").` ? `- Inline buttons not enabled for ${params.runtimeChannel}. If you need them, ask to set ${params.runtimeChannel}.capabilities.inlineButtons ("dm"|"group"|"all"|"allowlist").`
: "", : "",
...(params.messageToolHints ?? []), ...(params.messageToolHints ?? []),
] ]
.filter(Boolean) .filter(Boolean)
.join("\n") .join("\n")
: "", : "",
"", "",
]; ];
@ -282,15 +282,15 @@ export function buildAgentSystemPrompt(params: {
: undefined; : undefined;
const reasoningHint = params.reasoningTagHint const reasoningHint = params.reasoningTagHint
? [ ? [
"ALL internal reasoning MUST be inside <think>...</think>.", "ALL internal reasoning MUST be inside <think>...</think>.",
"Do not output any analysis outside <think>.", "Do not output any analysis outside <think>.",
"Format every reply as <think>...</think> then <final>...</final>, with no other text.", "Format every reply as <think>...</think> then <final>...</final>, with no other text.",
"Only the final user-visible reply may appear inside <final>.", "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.", "Only text inside <final> is shown to the user; everything else is discarded and never seen by the user.",
"Example:", "Example:",
"<think>Short internal reasoning.</think>", "<think>Short internal reasoning.</think>",
"<final>Hey there! What would you like to do next?</final>", "<final>Hey there! What would you like to do next?</final>",
].join(" ") ].join(" ")
: undefined; : undefined;
const reasoningLevel = params.reasoningLevel ?? "off"; const reasoningLevel = params.reasoningLevel ?? "off";
const userTimezone = params.userTimezone?.trim(); const userTimezone = params.userTimezone?.trim();
@ -336,21 +336,21 @@ export function buildAgentSystemPrompt(params: {
toolLines.length > 0 toolLines.length > 0
? toolLines.join("\n") ? toolLines.join("\n")
: [ : [
"Pi lists the standard tools above. This runtime enables:", "Pi lists the standard tools above. This runtime enables:",
"- grep: search file contents for patterns", "- grep: search file contents for patterns",
"- find: find files by glob pattern", "- find: find files by glob pattern",
"- ls: list directory contents", "- ls: list directory contents",
"- apply_patch: apply multi-file patches", "- apply_patch: apply multi-file patches",
`- ${execToolName}: run shell commands (supports background via yieldMs/background)`, `- ${execToolName}: run shell commands (supports background via yieldMs/background)`,
`- ${processToolName}: manage background exec sessions`, `- ${processToolName}: manage background exec sessions`,
"- browser: control clawd's dedicated browser", "- browser: control clawd's dedicated browser",
"- canvas: present/eval/snapshot the Canvas", "- canvas: present/eval/snapshot the Canvas",
"- nodes: list/describe/notify/camera/screen on paired nodes", "- 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)", "- 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_list: list sessions",
"- sessions_history: fetch session history", "- sessions_history: fetch session history",
"- sessions_send: send to another session", "- sessions_send: send to another session",
].join("\n"), ].join("\n"),
"TOOLS.md does not control tool availability; it is user guidance for how to use external tools.", "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.", "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 ? "## Moltbot Self-Update" : "",
hasGateway && !isMinimal hasGateway && !isMinimal
? [ ? [
"Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.", "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.", "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).", "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.", "After restart, Moltbot pings the last active session automatically.",
].join("\n") ].join("\n")
: "", : "",
hasGateway && !isMinimal ? "" : "", 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.", "Treat this directory as the single global workspace for file operations unless explicitly instructed otherwise.",
...workspaceNotes, ...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, ...docsSection,
params.sandboxInfo?.enabled ? "## Sandbox" : "", params.sandboxInfo?.enabled ? "## Sandbox" : "",
params.sandboxInfo?.enabled params.sandboxInfo?.enabled
? [ ? [
"You are running in a sandboxed runtime (tools execute in Docker).", "You are running in a sandboxed runtime (tools execute in Docker).",
"Some tools may be unavailable due to sandbox policy.", "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.", "Sub-agents stay sandboxed (no elevated/host access). Need outside-sandbox read/write? Don't spawn; ask first.",
params.sandboxInfo.workspaceDir params.sandboxInfo.workspaceDir
? `Sandbox workspace: ${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 params.sandboxInfo.elevated?.allowed
? `Agent workspace access: ${params.sandboxInfo.workspaceAccess}${ ? "Elevated exec is available for this session."
params.sandboxInfo.agentWorkspaceMount : "",
? ` (mounted at ${params.sandboxInfo.agentWorkspaceMount})` params.sandboxInfo.elevated?.allowed
: "" ? "User can toggle with /elevated on|off|ask|full."
}` : "",
: "", params.sandboxInfo.elevated?.allowed
params.sandboxInfo.browserBridgeUrl ? "Sandbox browser: enabled." : "", ? "You may also send /elevated on|off|ask|full when needed."
params.sandboxInfo.browserNoVncUrl : "",
? `Sandbox browser observer (noVNC): ${params.sandboxInfo.browserNoVncUrl}` params.sandboxInfo.elevated?.allowed
: "", ? `Current elevated level: ${params.sandboxInfo.elevated.defaultLevel} (ask runs exec on host with approvals; full auto-approves).`
params.sandboxInfo.hostBrowserAllowed === true : "",
? "Host browser control: allowed." ]
: params.sandboxInfo.hostBrowserAllowed === false .filter(Boolean)
? "Host browser control: blocked." .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 ? "" : "", params.sandboxInfo?.enabled ? "" : "",
...buildUserIdentitySection(ownerLine, isMinimal), ...buildUserIdentitySection(ownerLine, isMinimal),
@ -472,22 +482,22 @@ export function buildAgentSystemPrompt(params: {
const guidanceText = const guidanceText =
level === "minimal" level === "minimal"
? [ ? [
`Reactions are enabled for ${channel} in MINIMAL mode.`, `Reactions are enabled for ${channel} in MINIMAL mode.`,
"React ONLY when truly relevant:", "React ONLY when truly relevant:",
"- Acknowledge important user requests or confirmations", "- Acknowledge important user requests or confirmations",
"- Express genuine sentiment (humor, appreciation) sparingly", "- Express genuine sentiment (humor, appreciation) sparingly",
"- Avoid reacting to routine messages or your own replies", "- Avoid reacting to routine messages or your own replies",
"Guideline: at most 1 reaction per 5-10 exchanges.", "Guideline: at most 1 reaction per 5-10 exchanges.",
].join("\n") ].join("\n")
: [ : [
`Reactions are enabled for ${channel} in EXTENSIVE mode.`, `Reactions are enabled for ${channel} in EXTENSIVE mode.`,
"Feel free to react liberally:", "Feel free to react liberally:",
"- Acknowledge messages with appropriate emojis", "- Acknowledge messages with appropriate emojis",
"- Express sentiment and personality through reactions", "- Express sentiment and personality through reactions",
"- React to interesting content, humor, or notable events", "- React to interesting content, humor, or notable events",
"- Use reactions to confirm understanding or agreement", "- Use reactions to confirm understanding or agreement",
"Guideline: react whenever it feels natural.", "Guideline: react whenever it feels natural.",
].join("\n"); ].join("\n");
lines.push("## Reactions", guidanceText, ""); lines.push("## Reactions", guidanceText, "");
} }
if (reasoningHint) { if (reasoningHint) {