| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package apicompat
- import (
- "testing"
- "github.com/stretchr/testify/require"
- )
- func TestFlattenResponsesNamespaces_RewritesDeclarationHistoryAndChoice(t *testing.T) {
- req := map[string]any{
- "model": "gpt-5.5",
- "tools": []any{
- map[string]any{"type": "function", "name": "plain", "description": "keep"},
- map[string]any{
- "type": "namespace",
- "name": "collaboration",
- "tools": []any{
- map[string]any{"type": "function", "name": "spawn_agent", "description": "spawn", "parameters": map[string]any{"type": "object"}},
- },
- },
- },
- "tool_choice": map[string]any{"type": "function", "name": "spawn_agent", "namespace": "collaboration"},
- "input": []any{
- map[string]any{"type": "function_call", "call_id": "call_1", "name": "spawn_agent", "namespace": "collaboration", "arguments": "{}"},
- map[string]any{"type": "message", "role": "user", "content": "hi", "name": "spawn_agent", "namespace": "collaboration"},
- },
- }
- names, changed, err := FlattenResponsesNamespaces(req)
- require.NoError(t, err)
- require.True(t, changed)
- require.Equal(t, ResponsesNamespaceName{Namespace: "collaboration", Name: "spawn_agent"}, names["collaboration__spawn_agent"])
- tools, ok := req["tools"].([]any)
- require.True(t, ok)
- require.Len(t, tools, 2)
- plainTool, ok := tools[0].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "plain", plainTool["name"])
- flatTool, ok := tools[1].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "collaboration__spawn_agent", flatTool["name"])
- require.Equal(t, "spawn", flatTool["description"])
- choice, ok := req["tool_choice"].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "collaboration__spawn_agent", choice["name"])
- require.NotContains(t, choice, "namespace")
- input, ok := req["input"].([]any)
- require.True(t, ok)
- require.Len(t, input, 2)
- call, ok := input[0].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "collaboration__spawn_agent", call["name"])
- require.NotContains(t, call, "namespace")
- message, ok := input[1].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "spawn_agent", message["name"])
- require.Equal(t, "collaboration", message["namespace"])
- require.Equal(t, "gpt-5.5", req["model"])
- }
- func TestFlattenResponsesNamespaces_RejectsFlatNameCollision(t *testing.T) {
- req := map[string]any{"tools": []any{
- map[string]any{"type": "function", "name": "collaboration__spawn_agent"},
- map[string]any{"type": "namespace", "name": "collaboration", "tools": []any{
- map[string]any{"type": "function", "name": "spawn_agent"},
- }},
- }}
- _, _, err := FlattenResponsesNamespaces(req)
- require.ErrorContains(t, err, "conflicts with a top-level tool")
- }
- func TestFlattenResponsesNamespaces_NamespaceGroupChoiceFallsBackToAuto(t *testing.T) {
- req := map[string]any{
- "tools": []any{map[string]any{
- "type": "namespace", "name": "collaboration", "tools": []any{
- map[string]any{"type": "function", "name": "spawn_agent"},
- map[string]any{"type": "function", "name": "send_message"},
- },
- }},
- "tool_choice": map[string]any{"type": "namespace", "name": "collaboration"},
- }
- _, changed, err := FlattenResponsesNamespaces(req)
- require.NoError(t, err)
- require.True(t, changed)
- require.Equal(t, "auto", req["tool_choice"])
- }
- func TestFlattenResponsesNamespacesExcept_PreservesBuiltInNamespaceAndChoice(t *testing.T) {
- req := map[string]any{
- "tools": []any{
- map[string]any{"type": "namespace", "name": "image_gen", "tools": []any{
- map[string]any{"type": "function", "name": "imagegen"},
- }},
- map[string]any{"type": "namespace", "name": "collaboration", "tools": []any{
- map[string]any{"type": "function", "name": "spawn_agent"},
- }},
- },
- "tool_choice": map[string]any{"type": "namespace", "name": "image_gen"},
- }
- names, changed, err := FlattenResponsesNamespacesExcept(req, map[string]bool{"image_gen": true})
- require.NoError(t, err)
- require.True(t, changed)
- require.Contains(t, names, "collaboration__spawn_agent")
- tools, ok := req["tools"].([]any)
- require.True(t, ok)
- require.Len(t, tools, 2)
- preservedTool, ok := tools[0].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "namespace", preservedTool["type"])
- require.Equal(t, "image_gen", preservedTool["name"])
- flatTool, ok := tools[1].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "function", flatTool["type"])
- require.Equal(t, "collaboration__spawn_agent", flatTool["name"])
- require.Equal(t, map[string]any{"type": "namespace", "name": "image_gen"}, req["tool_choice"])
- }
- func TestFlattenResponsesNamespaces_RejectsNamespaceCollision(t *testing.T) {
- req := map[string]any{"tools": []any{
- map[string]any{"type": "namespace", "name": "a", "tools": []any{
- map[string]any{"type": "function", "name": "b__c"},
- }},
- map[string]any{"type": "namespace", "name": "a__b", "tools": []any{
- map[string]any{"type": "function", "name": "c"},
- }},
- }}
- _, _, err := FlattenResponsesNamespaces(req)
- require.ErrorContains(t, err, "both flatten")
- }
- func TestRestoreResponsesNamespaceCalls_RewritesOnlyFunctionCalls(t *testing.T) {
- payload := []byte(`{"type":"response.completed","response":{"output":[{"type":"function_call","name":"collaboration__spawn_agent","call_id":"call_1","arguments":"{}","extra":"keep"},{"type":"function_call","name":"plain","arguments":"{}"},{"type":"message","name":"collaboration__spawn_agent","content":"<tag>&value</tag>"}]}}`)
- names := map[string]ResponsesNamespaceName{
- "collaboration__spawn_agent": {Namespace: "collaboration", Name: "spawn_agent"},
- }
- got, changed, err := RestoreResponsesNamespaceCalls(payload, names)
- require.NoError(t, err)
- require.True(t, changed)
- require.JSONEq(t, `{"type":"response.completed","response":{"output":[{"type":"function_call","name":"spawn_agent","namespace":"collaboration","call_id":"call_1","arguments":"{}","extra":"keep"},{"type":"function_call","name":"plain","arguments":"{}"},{"type":"message","name":"collaboration__spawn_agent","content":"<tag>&value</tag>"}]}}`, string(got))
- require.Contains(t, string(got), "<tag>&value</tag>")
- require.NotContains(t, string(got), `\u003c`)
- }
- func TestRestoreResponsesNamespaceCalls_RewritesLifecycleItems(t *testing.T) {
- for _, eventType := range []string{"response.output_item.added", "response.output_item.done"} {
- t.Run(eventType, func(t *testing.T) {
- payload := []byte(`{"type":"` + eventType + `","item":{"type":"function_call","name":"collaboration__spawn_agent","arguments":"{}"}}`)
- got, changed, err := RestoreResponsesNamespaceCalls(payload, map[string]ResponsesNamespaceName{
- "collaboration__spawn_agent": {Namespace: "collaboration", Name: "spawn_agent"},
- })
- require.NoError(t, err)
- require.True(t, changed)
- require.JSONEq(t, `{"type":"`+eventType+`","item":{"type":"function_call","name":"spawn_agent","namespace":"collaboration","arguments":"{}"}}`, string(got))
- })
- }
- }
|