From c12edfdd1b948c84fbfdd0bf99a1e586230891cd Mon Sep 17 00:00:00 2001 From: TerminallyLazy Date: Wed, 24 Jun 2026 05:15:25 -0400 Subject: [PATCH] fix: harden tiny local recovery prompts --- agents/tiny-local/AGENTS.md | 6 ++++- .../agent.system.main.communication.md | 2 ++ .../prompts/agent.system.main.solving.md | 2 ++ .../prompts/agent.system.tool.call_sub.md | 23 ++++++++++++++++ .../prompts/agent.system.tool.parallel.md | 17 ++++++++++++ agents/tiny-local/prompts/fw.msg_misformat.md | 20 ++++++++++++++ agents/tiny-local/prompts/fw.msg_repeat.md | 23 +++++++++++++--- tests/test_default_prompt_budget.py | 26 ++++++++++++++++++- 8 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 agents/tiny-local/prompts/agent.system.tool.call_sub.md create mode 100644 agents/tiny-local/prompts/agent.system.tool.parallel.md create mode 100644 agents/tiny-local/prompts/fw.msg_misformat.md diff --git a/agents/tiny-local/AGENTS.md b/agents/tiny-local/AGENTS.md index e176f2422e..c636b333a5 100644 --- a/agents/tiny-local/AGENTS.md +++ b/agents/tiny-local/AGENTS.md @@ -11,16 +11,20 @@ - `prompts/agent.system.main.communication.md` owns the local-model communication contract. - `prompts/agent.system.main.solving.md` owns the local-model problem-solving contract and suppresses inherited visible reasoning requirements. - `prompts/fw.msg_repeat.md` owns Tiny Local's profile-specific recovery instructions when the framework rejects a duplicate assistant message. +- `prompts/fw.msg_misformat.md` owns Tiny Local's profile-specific recovery instructions when the framework cannot parse a valid tool request. - `prompts/agent.system.tools.md` owns the Tiny Local tools wrapper and final output-shape reminder after tool listing. -- `prompts/agent.system.tool.*.md` files own Tiny Local-specific tool examples that avoid inherited reasoning fields and repeated writes. +- `prompts/agent.system.tool.*.md` files own Tiny Local-specific tool examples that avoid inherited reasoning fields, long subordinate profiles, and repeated writes. ## Local Contracts - Preserve the normal Agent Zero tool-call shape: `tool_name` plus `tool_args`. - Do not add parser repair, duplicate suppression runtime, model transport, memory, or text-editor runtime behavior here. +- Suppress Qwen-style thinking output with prompt text only; do not add provider-specific transport switches here. - Duplicate-message handling may be tightened through profile prompts only. +- Misformat recovery may be tightened through profile prompts only. - Keep prompt text short enough for small local models to follow. - Treat continuation requests such as `proceed` or `continue` as commands to execute the next unfinished step, not as prompts for another status response. +- Subordinate examples must keep child agents on `profile:"tiny-local"` unless a user explicitly requests another profile. - Do not include user-specific provider names, API keys, local paths, or secrets. ## Work Guidance diff --git a/agents/tiny-local/prompts/agent.system.main.communication.md b/agents/tiny-local/prompts/agent.system.main.communication.md index 65f79edefb..e595e2fae0 100644 --- a/agents/tiny-local/prompts/agent.system.main.communication.md +++ b/agents/tiny-local/prompts/agent.system.main.communication.md @@ -1,5 +1,7 @@ ## Communication +/no_think + You are Agent Zero. Act on the user's behalf. When the user asks you to do something, do it directly. Do not explain how the user could do it themselves. diff --git a/agents/tiny-local/prompts/agent.system.main.solving.md b/agents/tiny-local/prompts/agent.system.main.solving.md index 2e410be4a5..94517b9868 100644 --- a/agents/tiny-local/prompts/agent.system.main.solving.md +++ b/agents/tiny-local/prompts/agent.system.main.solving.md @@ -6,6 +6,8 @@ For simple questions, answer with the `response` tool. Continuation words such as "proceed", "continue", "go ahead", "do it", and "excellent proceed" mean execute the next unfinished step. Do not respond by saying you will begin, continue, start, proceed, or investigate. Use a real tool call unless the task is already complete or blocked. +Prefer solving directly with the available tools. If you need `call_subordinate`, include `"profile":"tiny-local"` so the child agent uses the same compact JSON-only contract. + For tasks that need shell commands, files, browser actions, or other capabilities: - choose the appropriate listed tool immediately - keep one tool call per turn unless the `parallel` tool is listed and truly useful diff --git a/agents/tiny-local/prompts/agent.system.tool.call_sub.md b/agents/tiny-local/prompts/agent.system.tool.call_sub.md new file mode 100644 index 0000000000..82398bc6c9 --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.tool.call_sub.md @@ -0,0 +1,23 @@ +### call_subordinate +Delegate only when a separate child agent is truly needed. + +Args in `tool_args`: +- `message`: concrete role, goal, and task for the child agent +- `profile`: use `"tiny-local"` for this profile +- `reset`: use JSON boolean `true` for the first child message or when changing task + +Rules: +- Prefer doing simple work yourself with the available tools. +- If you call a subordinate, include `"profile":"tiny-local"` so the child uses the same compact JSON-only prompts. +- Do not use default, researcher, developer, hacker, or other long profiles unless the user explicitly asks for that profile. +- After the subordinate returns a sufficient result, answer from that result directly. +- Do not include `thoughts`, `headline`, markdown fences, or prose outside the JSON object. + +Example: + +`{"tool_name":"call_subordinate","tool_args":{"profile":"tiny-local","message":"Inspect TODO.md and return the next unchecked item only.","reset":true}}` + +{{if agent_profiles}} +Available profiles: +{{agent_profiles}} +{{endif}} diff --git a/agents/tiny-local/prompts/agent.system.tool.parallel.md b/agents/tiny-local/prompts/agent.system.tool.parallel.md new file mode 100644 index 0000000000..310a5eb4a8 --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.tool.parallel.md @@ -0,0 +1,17 @@ +### parallel +Run independent tool calls concurrently, or await/cancel background parallel jobs. + +Use only when multiple calls are independent and ready now. Each `tool_calls` item is a normal tool request object using only `tool_name` and `tool_args`. + +Rules: +- Do not use for one simple call, dependent steps, ordered steps, shared mutable state, or state/tool-availability changes that must happen in the parent context. +- Never nest `parallel`. +- Use `wait:false` only when you will collect results later with `job_ids`. +- If you include `call_subordinate`, set `"profile":"tiny-local"` inside that child call. +- Do not include `thoughts`, `headline`, markdown fences, or prose outside the JSON object. + +Args in `tool_args`: `tool_calls`, `job_ids`, `wait`, `action`, `timeout`. + +Example: + +`{"tool_name":"parallel","tool_args":{"tool_calls":[{"tool_name":"text_editor","tool_args":{"action":"read","path":"/a0/usr/workdir/TODO.md"}},{"tool_name":"call_subordinate","tool_args":{"profile":"tiny-local","message":"Summarize TODO.md in one sentence.","reset":true}}],"wait":true}}` diff --git a/agents/tiny-local/prompts/fw.msg_misformat.md b/agents/tiny-local/prompts/fw.msg_misformat.md new file mode 100644 index 0000000000..a09e271338 --- /dev/null +++ b/agents/tiny-local/prompts/fw.msg_misformat.md @@ -0,0 +1,20 @@ +/no_think + +Your last message was not valid JSON for a tool request. + +Reply now with exactly one JSON object and nothing else. + +Valid fallback if unsure: +`{"tool_name":"response","tool_args":{"text":"I need a valid next action to continue."}}` + +If your invalid text described an action, convert it to the matching tool call. + +Example: +Invalid: `I will inspect TODO.md now.` +Valid: `{"tool_name":"text_editor","tool_args":{"action":"read","path":"/a0/usr/workdir/TODO.md"}}` + +Rules: +- Use only `tool_name` and `tool_args` as top-level fields. +- Do not include `thoughts`, `headline`, markdown fences, apologies, or explanations. +- Do not repeat the invalid text. +- Do not describe what you will do. Call the tool. diff --git a/agents/tiny-local/prompts/fw.msg_repeat.md b/agents/tiny-local/prompts/fw.msg_repeat.md index 10602a5583..c748e95e05 100644 --- a/agents/tiny-local/prompts/fw.msg_repeat.md +++ b/agents/tiny-local/prompts/fw.msg_repeat.md @@ -1,6 +1,19 @@ -You have sent the same message again. You have to do something else. +/no_think -Your repeated JSON was recorded, but it did not execute another tool. Do not send the same JSON object again. +You sent the same JSON again. It was recorded, but no tool executed. + +Reply now with exactly one different JSON object and nothing else. + +The first character of your reply must be `{` and the last character must be `}`. + +Valid fallback if unsure: +`{"tool_name":"response","tool_args":{"text":"I need a different valid next action to continue."}}` + +If the repeated JSON was a status response about an unfinished action, convert it to the matching tool call. + +Example: +Repeated: `{"tool_name":"response","tool_args":{"text":"I will inspect TODO.md."}}` +Valid: `{"tool_name":"text_editor","tool_args":{"action":"read","path":"/a0/usr/workdir/TODO.md"}}` Choose one different action now: - If work is unfinished, call a real tool for the next unfinished step. @@ -10,4 +23,8 @@ Choose one different action now: - If the user only said "proceed" or "continue", continue with the next real tool call. - If no different action is possible, use `response` with a brief blocker. -Output exactly one JSON object with `tool_name` and `tool_args`. No prose or markdown. +Rules: +- Use only `tool_name` and `tool_args` as top-level fields. +- Do not include `thoughts`, `headline`, markdown fences, apologies, or explanations. +- Do not repeat the previous JSON. +- Do not describe what you will do. Call the tool. diff --git a/tests/test_default_prompt_budget.py b/tests/test_default_prompt_budget.py index eddac9b44b..f1f8cc29b8 100644 --- a/tests/test_default_prompt_budget.py +++ b/tests/test_default_prompt_budget.py @@ -86,6 +86,15 @@ async def test_tiny_local_profile_prompt_is_action_first_json_contract(): repeat_prompt = ( PROJECT_ROOT / "agents" / "tiny-local" / "prompts" / "fw.msg_repeat.md" ).read_text(encoding="utf-8") + misformat_prompt = ( + PROJECT_ROOT / "agents" / "tiny-local" / "prompts" / "fw.msg_misformat.md" + ).read_text(encoding="utf-8") + call_sub_prompt = ( + PROJECT_ROOT / "agents" / "tiny-local" / "prompts" / "agent.system.tool.call_sub.md" + ).read_text(encoding="utf-8") + parallel_prompt = ( + PROJECT_ROOT / "agents" / "tiny-local" / "prompts" / "agent.system.tool.parallel.md" + ).read_text(encoding="utf-8") text_editor_prompt = ( PROJECT_ROOT / "agents" / "tiny-local" / "prompts" / "agent.system.tool.text_editor.md" ).read_text(encoding="utf-8") @@ -94,6 +103,7 @@ async def test_tiny_local_profile_prompt_is_action_first_json_contract(): ).read_text(encoding="utf-8") assert "You are Agent Zero. Act on the user's behalf." in system_text + assert "/no_think" in system_text assert "Your visible assistant message must be exactly one valid JSON object." in system_text assert 'Use exactly these top-level fields: `"tool_name"` and `"tool_args"`.' in system_text assert 'For a final user-facing answer, use the `response` tool.' in system_text @@ -102,6 +112,7 @@ async def test_tiny_local_profile_prompt_is_action_first_json_contract(): assert "Do not explain what command the user could run manually." in system_text assert "output a corrected JSON tool request immediately" in system_text assert "do not resend the same JSON" in system_text + assert 'include `"profile":"tiny-local"`' in system_text assert "## Tiny Local Output Rule" in system_text assert "~~~json" not in communication_prompt assert "~~~json" not in code_prompt @@ -114,8 +125,21 @@ async def test_tiny_local_profile_prompt_is_action_first_json_contract(): assert "Continuation words" in solving_prompt assert "Do not respond by saying you will begin, continue, start, proceed, or investigate." in solving_prompt assert "Do not use this tool for \"proceed\", \"continue\", \"go ahead\"" in response_prompt - assert "Your repeated JSON was recorded, but it did not execute another tool." in repeat_prompt + assert "/no_think" in repeat_prompt + assert "It was recorded, but no tool executed." in repeat_prompt + assert "The first character of your reply must be `{`" in repeat_prompt + assert "Valid fallback if unsure" in repeat_prompt + assert "convert it to the matching tool call" in repeat_prompt assert "replace it with the next real tool call" in repeat_prompt + assert "/no_think" in misformat_prompt + assert "Your last message was not valid JSON for a tool request." in misformat_prompt + assert "Reply now with exactly one JSON object and nothing else." in misformat_prompt + assert "Valid fallback if unsure" in misformat_prompt + assert "convert it to the matching tool call" in misformat_prompt + assert 'Use only `tool_name` and `tool_args` as top-level fields.' in misformat_prompt + assert 'include `"profile":"tiny-local"`' in call_sub_prompt + assert 'default, researcher, developer, hacker' in call_sub_prompt + assert '"profile":"tiny-local"' in parallel_prompt assert "do not repeat the same status response or exact tool request" in solving_prompt assert "do not repeat the same exact tool call" in solving_prompt assert '"open_in_canvas":true' in text_editor_prompt