From 8e02e150f14fa9bb718789e973a31fb9d5b1c900 Mon Sep 17 00:00:00 2001 From: quick-sort Date: Wed, 17 Jun 2026 05:29:26 +0000 Subject: [PATCH] fix: format AskUserQuestion tool_result content as natural-language string Match Claude Code CLI's actual tool_result format. The content fed back to the model should be a human-readable string ("User has answered your questions: ...") rather than JSON. Structured questions/answers belong in the transcript's toolUseResult metadata, not the message content. Co-Authored-By: Claude Opus 4.7 --- src/agent_box/agents/claude_code.py | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/agent_box/agents/claude_code.py b/src/agent_box/agents/claude_code.py index de23f58..46b8f81 100644 --- a/src/agent_box/agents/claude_code.py +++ b/src/agent_box/agents/claude_code.py @@ -308,6 +308,25 @@ async def _parse_user_answer(questions: list[dict], user_reply: str) -> dict: return json.loads(text) +def _format_answers_for_tool_result(answers: dict) -> str: + """Render answers as the natural-language string Claude Code expects. + + Matches the CLI's own format: + ``User has answered your questions: ""="", ... You can now + continue with the user's answers in mind.`` + """ + pairs = [] + for question, answer in answers.items(): + if isinstance(answer, list): + answer = ", ".join(str(a) for a in answer) + pairs.append(f'"{question}"="{answer}"') + return ( + "User has answered your questions: " + + ", ".join(pairs) + + ". You can now continue with the user's answers in mind." + ) + + class ClaudeCodeAgent(BaseAgent): """Each project gets one ClaudeSDKClient. Session id is tracked externally.""" @@ -488,21 +507,19 @@ async def run(self, prompt: str, user_id: str = "", channel: str = "") -> AsyncI ) try: parsed = await _parse_user_answer(questions, prompt) - content = json.dumps({ - "questions": questions, - "answers": parsed["answers"], - }) + content = _format_answers_for_tool_result(parsed["answers"]) log.info("parsed AskUserQuestion answers: %s", parsed["answers"]) except Exception: log.warning( "failed to parse AskUserQuestion answer with LLM, " - "falling back to response field", + "falling back to raw user reply", exc_info=True, ) - content = json.dumps({ - "questions": questions, - "response": prompt, - }) + content = ( + "User has answered your questions: " + f"{prompt}. You can now continue with the user's " + "answers in mind." + ) await self._send_tool_result( client, tool_use_id=ask["tool_use_id"],