Skip to content

Commit 0334e67

Browse files
authored
tools: parse tool calls that don't conform to ("name": name, "arguments": args} (ollama#12738)
1 parent e0ead1a commit 0334e67

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

tools/tools.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (p *Parser) parseToolCall() *api.ToolCall {
125125
}
126126

127127
var args map[string]any
128-
if found, i := findArguments(p.buffer); found == nil {
128+
if found, i := findArguments(tool, p.buffer); found == nil {
129129
return nil
130130
} else {
131131
args = found
@@ -219,7 +219,7 @@ func findTool(tools []api.Tool, buf []byte) (*api.Tool, int) {
219219
// objects for functions that have all-optional parameters
220220
// e.g. `{"name": "get_conditions", "arguments": {}}` will work but
221221
// `{"name": "get_conditions"}` will not currently work
222-
func findArguments(buffer []byte) (map[string]any, int) {
222+
func findArguments(tool *api.Tool, buffer []byte) (map[string]any, int) {
223223
if len(buffer) == 0 {
224224
return nil, 0
225225
}
@@ -269,27 +269,30 @@ func findArguments(buffer []byte) (map[string]any, int) {
269269

270270
var findObject func(obj map[string]any) (map[string]any, bool)
271271
findObject = func(obj map[string]any) (map[string]any, bool) {
272-
if _, hasName := obj["name"]; hasName {
273-
if args, ok := obj["arguments"].(map[string]any); ok {
272+
findMap := func(name string, obj map[string]any) (map[string]any, bool) {
273+
if args, ok := obj[name].(map[string]any); ok {
274274
return args, true
275275
}
276-
if argsStr, ok := obj["arguments"].(string); ok {
276+
if argsStr, ok := obj[name].(string); ok {
277277
var argsData map[string]interface{}
278278
if err := json.Unmarshal([]byte(argsStr), &argsData); err == nil {
279279
return argsData, ok
280280
}
281281
}
282-
if args, ok := obj["parameters"].(map[string]any); ok {
282+
return nil, false
283+
}
284+
if _, hasName := obj["name"]; hasName {
285+
if args, ok := findMap("arguments", obj); ok {
283286
return args, true
284287
}
285-
if argsStr, ok := obj["parameters"].(string); ok {
286-
var argsData map[string]interface{}
287-
if err := json.Unmarshal([]byte(argsStr), &argsData); err == nil {
288-
return argsData, ok
289-
}
288+
if args, ok := findMap("parameters", obj); ok {
289+
return args, true
290290
}
291291
return nil, true
292292
}
293+
if args, ok := findMap(tool.Function.Name, obj); ok {
294+
return args, true
295+
}
293296

294297
for _, v := range obj {
295298
switch child := v.(type) {

tools/tools_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,7 @@ func TestFindArguments(t *testing.T) {
10331033
name string
10341034
buffer []byte
10351035
want map[string]any
1036+
tool string
10361037
}{
10371038
{
10381039
name: "empty string",
@@ -1290,11 +1291,29 @@ func TestFindArguments(t *testing.T) {
12901291
"location": "San Francisco, CA",
12911292
},
12921293
},
1294+
{
1295+
name: "simple tool call",
1296+
tool: "get_temperature",
1297+
buffer: []byte(`{"get_temperature": {"format": "fahrenheit", "location": "San Francisco, CA"}}`),
1298+
want: map[string]any{
1299+
"format": "fahrenheit",
1300+
"location": "San Francisco, CA",
1301+
},
1302+
},
1303+
{
1304+
name: "stringified simple tool call",
1305+
tool: "get_temperature",
1306+
buffer: []byte(`{"get_temperature": "{\"format\": \"fahrenheit\", \"location\": \"San Francisco, CA\"}"}`),
1307+
want: map[string]any{
1308+
"format": "fahrenheit",
1309+
"location": "San Francisco, CA",
1310+
},
1311+
},
12931312
}
12941313

12951314
for _, tt := range tests {
12961315
t.Run(tt.name, func(t *testing.T) {
1297-
got, _ := findArguments(tt.buffer)
1316+
got, _ := findArguments(&api.Tool{Function: api.ToolFunction{Name: tt.tool}}, tt.buffer)
12981317

12991318
if diff := cmp.Diff(got, tt.want); diff != "" {
13001319
t.Errorf("scanArguments() args mismatch (-got +want):\n%s", diff)

0 commit comments

Comments
 (0)