Skip to content

Insist on native tool calls in the dialog prompts - #290

Merged
iamwavecut merged 1 commit into
mainfrom
fix/native-tool-calls-prompt-rule
Nov 6, 2026
Merged

iamwavecut merged 1 commit into
mainfrom
fix/native-tool-calls-prompt-rule

Conversation

@iamwavecut

Copy link
Copy Markdown
Owner

Problem

The dialog model (Gemma on NInfer GPU0) still writes many tool calls as reply text instead of native tool_calls. In the last three days of dialog requests with stored raw responses, 23–42% of tool calls per day were text: code form react_to_message(emoji=…), <action><tool_call>… markup and Gemma's bare draw_image{…}. The bot salvages some of these, but each one risks a lost action, a rejected turn or a broken argument (see #288).

The rule existed as one sentence in <tool_contract> at the end of the system prompt.

Change

  • aifarm/system.prompt: the native <tool_mode> line says tools are called only through native tool_calls, never as reply text. <tool_contract> states the rule as a hard rule without exceptions, names the forbidden written forms in general terms, says that a written call does nothing, and covers every tool, including react_to_message and send_message.
  • chat/_shared_core.prompt: <silent_tool_calls> and <semantic_reactions> repeat the rule, only when hasTools is true, so the tool-less prompt stays unchanged.
  • aifarm/resample_note.prompt: the protocol_only, no_tool_calls and unexecuted_action retry notes ask for native tool_calls instead of "as described in the catalog".

The prompts do not quote any concrete text-call syntax, so they give the model no form to copy.

Not changed: the memory prompts. Their tool is the engine's structured-output mechanism (response_format sent as a forced structured_response call); they ask for one JSON object, the same prompt serves the Gemini schema path, and 820 of 820 responses in the last day were native.

The system prompt prefix changes, so the dialog prefix cache warms up again once after deploy.

Tests

New test native_tool_calls_rule_appears_only_when_tools_are_available renders the system prompt with and without tools.

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test -p openplotva-prompts (10 passed)
  • cargo test -p openplotva-llm (225 passed, 2 ignored)
  • cargo test -p openplotva-dialog (109 passed)
  • cargo test -p openplotva-app (1460 passed, 7 ignored)

The dialog model still writes about a quarter to two fifths of its tool
calls as reply text (react_to_message(...), <action><tool_call>...,
draw_image{...}) instead of native tool_calls.

The rule was a single sentence at the end of the system prompt. Now the
tool mode line, the tool contract, the silent tool call rule, the reaction
rule and the resample notes all state that a tool runs only through
native tool_calls and that a call written as text does nothing. The
shared core adds its lines only when tools are available.
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Warnings
⚠️ Prompt files are cache-sensitive contracts; confirm prompt shape and role markers were preserved intentionally.
Messages
📖 Danger checked 4 changed file(s).

Generated by 🚫 dangerJS against 7df961e

@iamwavecut

Copy link
Copy Markdown
Owner Author

Re Danger's prompt warning: the shape is preserved intentionally.

  • No role markers, partial names, element names or template data fields changed. The only template logic added is {{#if hasTools}} around two new sentences in chat/_shared_core.prompt, using the existing hasTools field that aifarm/system.prompt already receives.
  • The tool-less render is unchanged; native_tool_calls_rule_appears_only_when_tools_are_available checks both renders.
  • The system prompt text changes, so the dialog prefix cache is rebuilt once after deploy. This is the intended effect of a prompt rule change.

@iamwavecut
iamwavecut merged commit 8bf03b6 into main Nov 6, 2026
12 checks passed
@iamwavecut
iamwavecut deleted the fix/native-tool-calls-prompt-rule branch November 6, 2026 22:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant