From f03d41c698739d98ae97408fe3b813b55ba0c8a1 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Mon, 13 Jul 2026 18:35:53 +0200 Subject: [PATCH] fix: use dedicated tool-phase prompt for gemma4 orchestration With the butler persona prompt attached, gemma4 reasons about calling the calculator and then answers from memory with a different wrong product every run; tool_choice=required via extra_body is advisory at best on Ollama's OpenAI-compat layer. orchestrate_tool_calls() now uses a terse TATLOCK_ORCHESTRATION_PROMPT; synthesize_from_results() keeps the persona, so the user-visible voice is unchanged. Co-Authored-By: Claude Fable 5 --- src/agents/tatlock.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/agents/tatlock.py b/src/agents/tatlock.py index b65b9a9..af7702e 100644 --- a/src/agents/tatlock.py +++ b/src/agents/tatlock.py @@ -129,6 +129,22 @@ or """ +# Tool-phase prompt for orchestrate_tool_calls(). The butler personality prompt +# suppresses tool calling on small local models (gemma4 reasons about the tool, +# then answers from memory with wrong arithmetic), so the orchestration phase +# uses a terse operator prompt; synthesize_from_results() applies the persona. +TATLOCK_ORCHESTRATION_PROMPT = """You are the tool-execution phase of Tatlock, \ +a butler assistant. Your only job is to gather accurate results by calling the \ +provided tools. + +- ALWAYS use tools for the task - never answer from memory and never do mental math. +- Mathematics: call the calculate tool, even for trivial arithmetic. +- Dates and times: call the date/time tools, never guess. +- When the instructions say DELEGATE to an agent, call the matching delegate_to_* tool. +- After the tool results arrive, reply with a one-line factual summary of the results. \ +A later step writes the polished reply, so do not add personality.""" + + class TatlockAgent(AgentInterface): """ Tatlock - The Butler agent using PydanticAI with Ollama. @@ -654,10 +670,10 @@ class TatlockAgent(AgentInterface): # Create a fresh agent instance with scoped tools only model = get_model() - # Create agent with scoped tools + # Create agent with scoped tools, using the tool-phase prompt scoped_agent = Agent( model, - system_prompt=TATLOCK_SYSTEM_PROMPT, + system_prompt=TATLOCK_ORCHESTRATION_PROMPT, tools=scoped_tools, )