From 32a97b7493786e5784e4445e80c1a078c14c255f Mon Sep 17 00:00:00 2001 From: Aditya Aggarwal Date: Sun, 28 Jun 2026 00:30:55 +0530 Subject: [PATCH] tools: ignore braces inside JSON strings when detecting tool call end (#16937) Parser.done() counted the tag's open/close characters ({}, []) without tracking JSON string context, so a streamed tool call whose string argument value contained a closing brace or bracket (e.g. {"code": "if (x) { y }"}) was treated as complete too early and flushed to the user as plain text instead of being parsed as a tool call. findArguments() in the same file already tracks string context; apply the same handling in done() so open/close characters inside string values are ignored. --- tools/tools.go | 16 ++++++++++++++++ tools/tools_test.go | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tools/tools.go b/tools/tools.go index c319a6d4..b8ea767d 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -358,7 +358,23 @@ func (p *Parser) done() bool { } var count int + var inString, escaped bool for _, c := range p.buffer { + if escaped { + escaped = false + continue + } + if c == '\\' { + escaped = true + continue + } + if c == '"' { + inString = !inString + continue + } + if inString { + continue + } if c == byte(open) { count++ } else if c == byte(close) { diff --git a/tools/tools_test.go b/tools/tools_test.go index 2b8b04f8..689d6517 100644 --- a/tools/tools_test.go +++ b/tools/tools_test.go @@ -842,6 +842,24 @@ func TestDone(t *testing.T) { buffer: []byte("[]"), want: true, }, + { + name: "json close brace inside string", + tag: "{", + buffer: []byte("{\"note\": \"a}b\""), + want: false, + }, + { + name: "json complete with brace inside string", + tag: "{", + buffer: []byte("{\"note\": \"a}b\"}"), + want: true, + }, + { + name: "list close bracket inside string", + tag: "[", + buffer: []byte("[{\"note\": \"x]y\"}"), + want: false, + }, } for _, tt := range tests {