mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 00:15:28 +08:00
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
113 lines
3.2 KiB
Go
113 lines
3.2 KiB
Go
package toolcall
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormalizeParsedToolCallsForSchemasCoercesDeclaredStringFieldsRecursively(t *testing.T) {
|
|
toolsRaw := []any{
|
|
map[string]any{
|
|
"type": "function",
|
|
"function": map[string]any{
|
|
"name": "TaskUpdate",
|
|
"parameters": map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"taskId": map[string]any{"type": "string"},
|
|
"payload": map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"content": map[string]any{"type": "string"},
|
|
"tags": map[string]any{
|
|
"type": "array",
|
|
"items": map[string]any{"type": "string"},
|
|
},
|
|
"count": map[string]any{"type": "number"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
calls := []ParsedToolCall{{
|
|
Name: "TaskUpdate",
|
|
Input: map[string]any{
|
|
"taskId": 1,
|
|
"payload": map[string]any{
|
|
"content": map[string]any{"text": "hello"},
|
|
"tags": []any{1, true, map[string]any{"k": "v"}},
|
|
"count": 2,
|
|
},
|
|
},
|
|
}}
|
|
|
|
got := NormalizeParsedToolCallsForSchemas(calls, toolsRaw)
|
|
if len(got) != 1 {
|
|
t.Fatalf("expected one normalized call, got %#v", got)
|
|
}
|
|
if got[0].Input["taskId"] != "1" {
|
|
t.Fatalf("expected taskId coerced to string, got %#v", got[0].Input["taskId"])
|
|
}
|
|
payload, ok := got[0].Input["payload"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected payload object, got %#v", got[0].Input["payload"])
|
|
}
|
|
if payload["content"] != `{"text":"hello"}` {
|
|
t.Fatalf("expected nested content coerced to json string, got %#v", payload["content"])
|
|
}
|
|
if payload["count"] != 2 {
|
|
t.Fatalf("expected non-string count unchanged, got %#v", payload["count"])
|
|
}
|
|
tags, ok := payload["tags"].([]any)
|
|
if !ok {
|
|
t.Fatalf("expected tags slice, got %#v", payload["tags"])
|
|
}
|
|
wantTags := []any{"1", "true", `{"k":"v"}`}
|
|
if !reflect.DeepEqual(tags, wantTags) {
|
|
t.Fatalf("unexpected normalized tags: got %#v want %#v", tags, wantTags)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeParsedToolCallsForSchemasSupportsDirectToolSchemaShape(t *testing.T) {
|
|
toolsRaw := []any{
|
|
map[string]any{
|
|
"name": "Write",
|
|
"input_schema": map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"content": map[string]any{"type": "string"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
calls := []ParsedToolCall{{Name: "Write", Input: map[string]any{"content": []any{"a", 1}}}}
|
|
got := NormalizeParsedToolCallsForSchemas(calls, toolsRaw)
|
|
if got[0].Input["content"] != `["a",1]` {
|
|
t.Fatalf("expected direct-schema content coerced to string, got %#v", got[0].Input["content"])
|
|
}
|
|
}
|
|
|
|
func TestNormalizeParsedToolCallsForSchemasLeavesAmbiguousUnionUnchanged(t *testing.T) {
|
|
toolsRaw := []any{
|
|
map[string]any{
|
|
"type": "function",
|
|
"function": map[string]any{
|
|
"name": "TaskUpdate",
|
|
"parameters": map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"taskId": map[string]any{"type": []any{"string", "integer"}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
calls := []ParsedToolCall{{Name: "TaskUpdate", Input: map[string]any{"taskId": 1}}}
|
|
got := NormalizeParsedToolCallsForSchemas(calls, toolsRaw)
|
|
if got[0].Input["taskId"] != 1 {
|
|
t.Fatalf("expected ambiguous union to stay unchanged, got %#v", got[0].Input["taskId"])
|
|
}
|
|
}
|