Skip to content

Commit d5959f4

Browse files
tbitcsoz-agent
andcommitted
fix: strip bare JSON tool calls from LLM text output
Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent cc85e0f commit d5959f4

1 file changed

Lines changed: 18 additions & 12 deletions

File tree

src/specsmith/agent/runner.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -602,19 +602,25 @@ def _agent_turn(self, user_input: str, silent: bool = False) -> str:
602602
final_response = response.content
603603
# Strip inline tool call blocks that local models (Qwen/Mistral)
604604
# sometimes emit as text instead of using the tool_use API.
605+
# Pattern 1: XML-wrapped tool calls <tool>{...}</tool>
605606
_TOOL_BLOCK = re.compile(r"<tools?>\s*\{.*?\}\s*</tools?>", re.DOTALL)
606-
if _TOOL_BLOCK.search(final_response):
607-
final_response = _TOOL_BLOCK.sub("", final_response).strip()
608-
# If the response was ONLY a tool call block, suppress entirely
609-
if not final_response:
610-
response = CompletionResponse(
611-
content="",
612-
model=response.model,
613-
input_tokens=response.input_tokens,
614-
output_tokens=response.output_tokens,
615-
estimated_cost_usd=response.estimated_cost_usd,
616-
tool_calls=response.tool_calls,
617-
)
607+
# Pattern 2: Bare JSON tool calls {"name":..., "arguments":...}
608+
_BARE_TOOL = re.compile(
609+
r'\{\s*"name"\s*:\s*"[^"]+"\s*,\s*"arguments"\s*:\s*\{[^}]*\}\s*\}',
610+
)
611+
for pat in (_TOOL_BLOCK, _BARE_TOOL):
612+
if pat.search(final_response):
613+
final_response = pat.sub("", final_response).strip()
614+
# If the response was ONLY tool call blocks, suppress entirely
615+
if not final_response:
616+
response = CompletionResponse(
617+
content="",
618+
model=response.model,
619+
input_tokens=response.input_tokens,
620+
output_tokens=response.output_tokens,
621+
estimated_cost_usd=response.estimated_cost_usd,
622+
tool_calls=response.tool_calls,
623+
)
618624

619625
if not response.has_tool_calls:
620626
# Non-English correction: if the final response is in a non-English

0 commit comments

Comments
 (0)