From 1aa4947cdc931b8d05969102960f8599863a20f8 Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Wed, 3 Sep 2025 15:02:39 -0700 Subject: [PATCH] Revert "tools: avoid matching braces that are part of tool content (#12039)" This reverts commit 4bcb04ad886c0c7b66e6822c08fed4a1f03bece1. --- tools/tools.go | 33 +--------- tools/tools_test.go | 155 +------------------------------------------- 2 files changed, 4 insertions(+), 184 deletions(-) diff --git a/tools/tools.go b/tools/tools.go index 80fc6e0d0..f9ca15530 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -224,45 +224,22 @@ func findArguments(buffer []byte) (map[string]any, int) { return nil, 0 } - start := -1 var braces int - var inString, escaped bool - - for i := range buffer { - c := buffer[i] - - if escaped { - escaped = false - continue - } - - if c == '\\' { - escaped = true - continue - } - - if c == '"' { - inString = !inString - continue - } - - if inString { - continue - } + var start int = -1 + for i, c := range buffer { if c == '{' { if braces == 0 { start = i } braces++ - } else if c == '}' { + } else if c == '}' && braces > 0 { braces-- if braces == 0 && start != -1 { object := buffer[start : i+1] var data map[string]any if err := json.Unmarshal(object, &data); err != nil { - // not a valid object, keep looking start = -1 continue } @@ -305,10 +282,6 @@ func findArguments(buffer []byte) (map[string]any, int) { return data, i } - - if braces < 0 { - braces = 0 - } } } diff --git a/tools/tools_test.go b/tools/tools_test.go index 2a449a0ea..3ed6afc62 100644 --- a/tools/tools_test.go +++ b/tools/tools_test.go @@ -1,7 +1,6 @@ package tools import ( - "strings" "testing" "text/template" @@ -1117,163 +1116,11 @@ func TestFindArguments(t *testing.T) { }, { name: "deepseek", - buffer: []byte(`"arguments": {"location": "Tokyo"}}`), + buffer: []byte(`", "arguments": {"location": "Tokyo"}}`), want: map[string]any{ "location": "Tokyo", }, }, - { - name: "string with braces", - buffer: []byte(`{"name": "process_code", "arguments": {"code": "if (x > 0) { return true; }"}}`), - want: map[string]any{ - "code": "if (x > 0) { return true; }", - }, - }, - { - name: "string with nested json", - buffer: []byte(`{"name": "send_data", "arguments": {"payload": "{\"nested\": {\"key\": \"value\"}}"}}`), - want: map[string]any{ - "payload": `{"nested": {"key": "value"}}`, - }, - }, - { - name: "string with escaped quotes and braces", - buffer: []byte(`{"name": "analyze", "arguments": {"text": "The JSON is: {\"key\": \"val{ue}\"}"}}`), - want: map[string]any{ - "text": `The JSON is: {"key": "val{ue}"}`, - }, - }, - { - name: "multiple objects with string containing braces", - buffer: []byte(`{"name": "test", "arguments": {"query": "find } in text"}} {"name": "other"}`), - want: map[string]any{ - "query": "find } in text", - }, - }, - { - name: "unmatched closing brace in string", - buffer: []byte(`{"name": "search", "arguments": {"pattern": "regex: }"}}`), - want: map[string]any{ - "pattern": "regex: }", - }, - }, - { - name: "complex nested with mixed braces", - buffer: []byte(`{"name": "analyze", "arguments": {"data": "{\"items\": [{\"value\": \"}\"}, {\"code\": \"if (x) { return y; }\"}]}"}}`), - want: map[string]any{ - "data": `{"items": [{"value": "}"}, {"code": "if (x) { return y; }"}]}`, - }, - }, - { - name: "string with newline and braces", - buffer: []byte(`{"name": "format", "arguments": {"template": "{\n \"key\": \"value\"\n}"}}`), - want: map[string]any{ - "template": "{\n \"key\": \"value\"\n}", - }, - }, - { - name: "string with unicode escape", - buffer: []byte(`{"name": "test", "arguments": {"text": "Unicode: \u007B and \u007D"}}`), - want: map[string]any{ - "text": "Unicode: { and }", - }, - }, - { - name: "array arguments", - buffer: []byte(`{"name": "batch", "arguments": ["item1", "item2", "{\"nested\": true}"]}`), - want: nil, // This should return nil because arguments is not a map - }, - { - name: "escaped backslash before quote", - buffer: []byte(`{"name": "path", "arguments": {"dir": "C:\\Program Files\\{App}\\"}}`), - want: map[string]any{ - "dir": `C:\Program Files\{App}\`, - }, - }, - { - name: "single quotes not treated as string delimiters", - buffer: []byte(`{"name": "query", "arguments": {"sql": "SELECT * FROM users WHERE name = '{admin}'"}}`), - want: map[string]any{ - "sql": "SELECT * FROM users WHERE name = '{admin}'", - }, - }, - { - name: "incomplete json at buffer end", - buffer: []byte(`{"name": "test", "arguments": {"data": "some {"`), - want: nil, - }, - { - name: "multiple escaped quotes", - buffer: []byte(`{"name": "echo", "arguments": {"msg": "He said \"Hello {World}\" loudly"}}`), - want: map[string]any{ - "msg": `He said "Hello {World}" loudly`, - }, - }, - { - name: "json with comments style string", - buffer: []byte(`{"name": "code", "arguments": {"snippet": "// This is a comment with { and }"}}`), - want: map[string]any{ - "snippet": "// This is a comment with { and }", - }, - }, - { - name: "consecutive escaped backslashes", - buffer: []byte(`{"name": "test", "arguments": {"path": "C:\\\\{folder}\\\\"}}`), - want: map[string]any{ - "path": `C:\\{folder}\\`, - }, - }, - { - name: "empty string with braces after", - buffer: []byte(`{"name": "test", "arguments": {"a": "", "b": "{value}"}}`), - want: map[string]any{ - "a": "", - "b": "{value}", - }, - }, - { - name: "unicode in key names", - buffer: []byte(`{"name": "test", "arguments": {"key{": "value", "key}": "value2"}}`), - want: map[string]any{ - "key{": "value", - "key}": "value2", - }, - }, - { - name: "very long string with braces", - buffer: []byte(`{"name": "test", "arguments": {"data": "` + strings.Repeat("a{b}c", 100) + `"}}`), - want: map[string]any{ - "data": strings.Repeat("a{b}c", 100), - }, - }, - { - name: "tab characters and braces", - buffer: []byte(`{"name": "test", "arguments": {"code": "\tif (true) {\n\t\treturn;\n\t}"}}`), - want: map[string]any{ - "code": "\tif (true) {\n\t\treturn;\n\t}", - }, - }, - { - name: "null byte in string", - buffer: []byte(`{"name": "test", "arguments": {"data": "before\u0000{after}"}}`), - want: map[string]any{ - "data": "before\x00{after}", - }, - }, - { - name: "escaped quote at end of string", - buffer: []byte(`{"name": "test", "arguments": {"data": "text with quote at end\\\""}}`), - want: map[string]any{ - "data": `text with quote at end\"`, - }, - }, - { - name: "mixed array and object in arguments", - buffer: []byte(`{"name": "test", "arguments": {"items": ["{", "}", {"key": "value"}]}}`), - want: map[string]any{ - "items": []any{"{", "}", map[string]any{"key": "value"}}, - }, - }, } for _, tt := range tests {