From 8e5747ff43790b219e77ca61aba8d90090515884 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 8 Apr 2026 18:42:47 -0400 Subject: [PATCH] Fix tool result format: Qwen expects in user role Qwen's chat template renders tool results as: <|im_start|>user\n\n{content}\n<|im_end|> We were rendering as: <|im_start|>tool\n{content}<|im_end|> The model never saw <|im_start|>tool in training, so it ignored our tool results and looped retrying the same call. Found by comparing our tokenization against vLLM's /tokenize endpoint with chat messages. Co-Authored-By: Proof of Concept --- src/agent/context.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/agent/context.rs b/src/agent/context.rs index 05ad935..47e6c7a 100644 --- a/src/agent/context.rs +++ b/src/agent/context.rs @@ -146,9 +146,9 @@ impl NodeBody { out.push_str("\n\n"); } Self::ToolResult(text) => { - out.push_str("<|im_start|>tool\n"); + out.push_str("<|im_start|>user\n\n"); out.push_str(text); - out.push_str("<|im_end|>\n"); + out.push_str("\n<|im_end|>\n"); } Self::Memory { text, .. } => { out.push_str("<|im_start|>memory\n"); @@ -1035,7 +1035,7 @@ mod tests { #[test] fn test_render_tool_result() { let node = AstNode::tool_result("output here"); - assert_eq!(node.render(), "<|im_start|>tool\noutput here<|im_end|>\n"); + assert_eq!(node.render(), "<|im_start|>user\n\noutput here\n<|im_end|>\n"); } #[test]