package protocol_test import ( "bytes" "context" "fmt" "strings" "testing" "ccLoad/internal/protocol" "ccLoad/internal/protocol/builtin" ) func TestRegistry_TranslateResponseNonStream_GeminiStructuredOutbound(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) rawResp := []byte(`{"candidates":[{"content":{"parts":[{"text":"hello"},{"functionCall":{"name":"lookup","args":{"query":"go"}}}]},"finishReason":"STOP"}],"usageMetadata":{"promptTokenCount":3,"candidatesTokenCount":5,"totalTokenCount":8},"modelVersion":"gemini-2.5-pro"}`) t.Run("openai", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Gemini, protocol.OpenAI, "gpt-4o", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } if !strings.Contains(string(got), `"content":"hello"`) || !strings.Contains(string(got), `"tool_calls":[{"id":"call_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]`) || !strings.Contains(string(got), `"finish_reason":"tool_calls"`) { t.Fatalf("unexpected OpenAI response: %s", got) } }) t.Run("anthropic", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Gemini, protocol.Anthropic, "claude-3-5-sonnet", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } if !strings.Contains(string(got), `"type":"text"`) || !strings.Contains(string(got), `"text":"hello"`) || !strings.Contains(string(got), `"type":"tool_use"`) || !strings.Contains(string(got), `"id":"call_1"`) || !strings.Contains(string(got), `"name":"lookup"`) || !strings.Contains(string(got), `"input":{"query":"go"}`) || !strings.Contains(string(got), `"stop_reason":"tool_use"`) { t.Fatalf("unexpected Anthropic response: %s", got) } }) t.Run("codex", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Gemini, protocol.Codex, "gpt-5-codex", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } if !strings.Contains(string(got), `"type":"message"`) || !strings.Contains(string(got), `"role":"assistant"`) || !strings.Contains(string(got), `"type":"output_text"`) || !strings.Contains(string(got), `"text":"hello"`) || !strings.Contains(string(got), `"type":"function_call"`) || !strings.Contains(string(got), `"call_id":"call_1"`) || !strings.Contains(string(got), `"name":"lookup"`) || !strings.Contains(string(got), `"arguments":"{\"query\":\"go\"}"`) { t.Fatalf("unexpected Codex response: %s", got) } }) } func TestRegistry_TranslateResponseStream_GeminiStructuredOutbound(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) t.Run("openai", func(t *testing.T) { var state any chunks, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.OpenAI, "gpt-4o", nil, nil, []byte("data: {\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"lookup\",\"args\":{\"query\":\"go\"}}}]},\"finishReason\":\"STOP\"}],\"modelVersion\":\"gemini-2.5-pro\"}\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } joined := string(chunks[0]) if len(chunks) != 1 || !strings.Contains(joined, `"tool_calls"`) || !strings.Contains(joined, `"id":"call_1"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"arguments":"{\"query\":\"go\"}"`) || !strings.Contains(joined, `"finish_reason":"tool_calls"`) { t.Fatalf("unexpected OpenAI stream chunk: %#v", chunks) } }) t.Run("anthropic", func(t *testing.T) { var state any chunks, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.Anthropic, "claude-3-5-sonnet", nil, nil, []byte("data: {\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"lookup\",\"args\":{\"query\":\"go\"}}}]},\"finishReason\":\"STOP\"}],\"modelVersion\":\"gemini-2.5-pro\",\"usageMetadata\":{\"promptTokenCount\":3,\"candidatesTokenCount\":5}}\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } joined := string(bytes.Join(chunks, nil)) if !strings.Contains(joined, `event: message_start`) || !strings.Contains(joined, `"type":"tool_use"`) || !strings.Contains(joined, `"id":"call_1"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"partial_json":"{\"query\":\"go\"}"`) || !strings.Contains(joined, `"stop_reason":"tool_use"`) || !strings.Contains(joined, `event: message_stop`) { t.Fatalf("unexpected Anthropic stream chunks: %s", joined) } }) t.Run("codex", func(t *testing.T) { var state any chunks, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.Codex, "gpt-5-codex", nil, nil, []byte("data: {\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"lookup\",\"args\":{\"query\":\"go\"}}}]}}],\"modelVersion\":\"gemini-2.5-pro\"}\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } joined := string(chunks[0]) if len(chunks) != 1 || !strings.Contains(joined, `event: response.output_item.done`) || !strings.Contains(joined, `"type":"function_call"`) || !strings.Contains(joined, `"call_id":"call_1"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"arguments":"{\"query\":\"go\"}"`) { t.Fatalf("unexpected Codex stream chunk: %#v", chunks) } }) } func TestRegistry_TranslateResponseNonStream_AnthropicStructuredOutbound(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) rawResp := []byte(`{"id":"msg_1","type":"message","role":"assistant","content":[{"type":"text","text":"hello"},{"type":"tool_use","id":"toolu_1","name":"lookup","input":{"query":"go"}}],"model":"claude-3-5-sonnet","stop_reason":"tool_use","usage":{"input_tokens":3,"output_tokens":5}}`) t.Run("openai", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } if !strings.Contains(string(got), `"content":"hello"`) || !strings.Contains(string(got), `"tool_calls":[{"id":"toolu_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]`) || !strings.Contains(string(got), `"finish_reason":"tool_calls"`) { t.Fatalf("unexpected OpenAI response: %s", got) } }) t.Run("codex", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } if !strings.Contains(string(got), `"type":"message"`) || !strings.Contains(string(got), `"role":"assistant"`) || !strings.Contains(string(got), `"type":"output_text"`) || !strings.Contains(string(got), `"text":"hello"`) || !strings.Contains(string(got), `"type":"function_call"`) || !strings.Contains(string(got), `"call_id":"toolu_1"`) || !strings.Contains(string(got), `"name":"lookup"`) || !strings.Contains(string(got), `"arguments":"{\"query\":\"go\"}"`) { t.Fatalf("unexpected Codex response: %s", got) } }) } func TestRegistry_TranslateResponseNonStream_OpenAIStructuredOutboundToGemini(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) rawResp := []byte(`{"id":"chatcmpl_1","object":"chat.completion","created":0,"model":"gpt-4o","choices":[{"index":0,"message":{"role":"assistant","content":"","tool_calls":[{"id":"call_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}`) got, err := reg.TranslateResponseNonStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } body := string(got) if !strings.Contains(body, `"functionCall"`) || !strings.Contains(body, `"name":"lookup"`) || !strings.Contains(body, `"query":"go"`) || !strings.Contains(body, `"finishReason":"STOP"`) { t.Fatalf("unexpected Gemini response: %s", got) } } func TestRegistry_TranslateResponseStream_OpenAIStructuredOutboundToGemini(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) chunks := []string{ `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]}}]}` + "\n\n", `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}` + "\n\n", } var state any var outputs [][]byte for _, chunk := range chunks { out, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(chunk), &state) if err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } outputs = append(outputs, out...) } joined := string(bytes.Join(outputs, nil)) if !strings.Contains(joined, `"functionCall"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"query":"go"`) || !strings.Contains(joined, `"finishReason":"STOP"`) || !strings.Contains(joined, `"promptTokenCount":3`) { t.Fatalf("unexpected Gemini stream output: %s", joined) } } func TestRegistry_TranslateResponseStream_OpenAIStructuredOutboundToGeminiDoneSentinel(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) chunks := []string{ `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]}}]}` + "\n\n", `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}` + "\n\n", } var state any for _, chunk := range chunks { if _, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(chunk), &state); err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } } done, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte("data: [DONE]\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream done failed: %v", err) } if done != nil { t.Fatalf("expected [DONE] to emit no extra Gemini payload after finish_reason, got: %#v", done) } } func TestRegistry_TranslateResponseStream_OpenAIStructuredOutboundToGeminiUsageOnlyTail(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) chunks := []string{ `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]}}]}` + "\n\n", `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}` + "\n\n", } var state any for _, chunk := range chunks { if _, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(chunk), &state); err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } } usageOnly, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(`data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}`+"\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream usage-only tail failed: %v", err) } if usageOnly != nil { t.Fatalf("expected usage-only tail to emit no extra Gemini payload after terminal chunk, got: %#v", usageOnly) } } func TestRegistry_TranslateResponseStream_OpenAIStructuredOutboundToGeminiUsageOnlyTailCarriesUsage(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) chunks := []string{ `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"lookup","arguments":"{\"query\":\"go\"}"}}]}}]}` + "\n\n", `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}` + "\n\n", } var state any for _, chunk := range chunks { if _, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(chunk), &state); err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } } usageOnly, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(`data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}`+"\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream usage-only tail failed: %v", err) } if len(usageOnly) != 1 || !strings.Contains(string(usageOnly[0]), `"promptTokenCount":3`) || !strings.Contains(string(usageOnly[0]), `"candidatesTokenCount":5`) || strings.Contains(string(usageOnly[0]), `"finishReason"`) { t.Fatalf("expected usage-only tail to emit usageMetadata without duplicate finishReason, got: %#v", usageOnly) } done, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte("data: [DONE]\n\n"), &state) if err != nil { t.Fatalf("TranslateResponseStream done failed: %v", err) } if done != nil { t.Fatalf("expected DONE sentinel to emit nothing after usage-only tail, got: %#v", done) } } func TestRegistry_TranslateResponseStream_OpenAIStructuredOutboundToGemini_FragmentedToolCalls(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) chunks := []string{ `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"lookup","arguments":""}}]}}]}` + "\n\n", `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"query\":"}}]}}]}` + "\n\n", `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"go\"}"}}]},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}` + "\n\n", } var state any var outputs [][]byte for _, chunk := range chunks { out, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(chunk), &state) if err != nil { t.Fatalf("TranslateResponseStream failed: %v", err) } outputs = append(outputs, out...) } joined := string(bytes.Join(outputs, nil)) if !strings.Contains(joined, `"functionCall"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"query":"go"`) { t.Fatalf("expected assembled Gemini functionCall, got: %s", joined) } if !strings.Contains(joined, `"finishReason":"STOP"`) || !strings.Contains(joined, `"promptTokenCount":3`) { t.Fatalf("expected terminal Gemini usage payload, got: %s", joined) } } func TestRegistry_TranslateResponseStream_OpenAIStructuredOutboundToGemini_FragmentedToolCalls_AllSplitPoints(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) arguments := `{"query":"go"}` for split := 0; split <= len(arguments); split++ { t.Run(fmt.Sprintf("split-%d", split), func(t *testing.T) { var state any var outputs [][]byte chunks := []string{ `data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"lookup","arguments":""}}]}}]}` + "\n\n", fmt.Sprintf(`data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":%q}}]}}]}`+"\n\n", arguments[:split]), fmt.Sprintf(`data: {"id":"chatcmpl_1","object":"chat.completion.chunk","model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":%q}}]},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":3,"completion_tokens":5,"total_tokens":8}}`+"\n\n", arguments[split:]), } for _, chunk := range chunks { out, err := reg.TranslateResponseStream(context.Background(), protocol.OpenAI, protocol.Gemini, "gemini-2.5-pro", nil, nil, []byte(chunk), &state) if err != nil { t.Fatalf("split %d TranslateResponseStream failed: %v", split, err) } outputs = append(outputs, out...) } joined := string(bytes.Join(outputs, nil)) if !strings.Contains(joined, `"functionCall"`) || !strings.Contains(joined, `"query":"go"`) || !strings.Contains(joined, `"promptTokenCount":3`) { t.Fatalf("split %d unexpected Gemini stream output: %s", split, joined) } }) } } func TestRegistry_TranslateResponseStream_GeminiStructuredOutbound_MultipleToolCallsAcrossChunks(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) firstChunk := []byte("data: {\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"lookup\",\"args\":{\"query\":\"one\"}}}]}}],\"modelVersion\":\"gemini-2.5-pro\"}\n\n") secondChunk := []byte("data: {\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"search\",\"args\":{\"query\":\"two\"}}}]},\"finishReason\":\"STOP\"}],\"modelVersion\":\"gemini-2.5-pro\"}\n\n") t.Run("openai", func(t *testing.T) { var state any first, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.OpenAI, "gpt-4o", nil, nil, firstChunk, &state) if err != nil { t.Fatalf("first chunk failed: %v", err) } second, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.OpenAI, "gpt-4o", nil, nil, secondChunk, &state) if err != nil { t.Fatalf("second chunk failed: %v", err) } firstJoined := string(bytes.Join(first, nil)) secondJoined := string(bytes.Join(second, nil)) if !strings.Contains(firstJoined, `"index":0`) || !strings.Contains(firstJoined, `"id":"call_1"`) { t.Fatalf("expected first tool call index/id, got %s", firstJoined) } if !strings.Contains(secondJoined, `"index":1`) || !strings.Contains(secondJoined, `"id":"call_2"`) { t.Fatalf("expected second tool call index/id, got %s", secondJoined) } }) t.Run("anthropic", func(t *testing.T) { var state any first, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.Anthropic, "claude-3-5-sonnet", nil, nil, firstChunk, &state) if err != nil { t.Fatalf("first chunk failed: %v", err) } second, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.Anthropic, "claude-3-5-sonnet", nil, nil, secondChunk, &state) if err != nil { t.Fatalf("second chunk failed: %v", err) } firstJoined := string(bytes.Join(first, nil)) secondJoined := string(bytes.Join(second, nil)) if !strings.Contains(firstJoined, `"id":"call_1"`) { t.Fatalf("expected first tool id call_1, got %s", firstJoined) } if !strings.Contains(secondJoined, `"id":"call_2"`) { t.Fatalf("expected second tool id call_2, got %s", secondJoined) } }) t.Run("codex", func(t *testing.T) { var state any first, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.Codex, "gpt-5-codex", nil, nil, firstChunk, &state) if err != nil { t.Fatalf("first chunk failed: %v", err) } second, err := reg.TranslateResponseStream(context.Background(), protocol.Gemini, protocol.Codex, "gpt-5-codex", nil, nil, secondChunk, &state) if err != nil { t.Fatalf("second chunk failed: %v", err) } firstJoined := string(bytes.Join(first, nil)) secondJoined := string(bytes.Join(second, nil)) if !strings.Contains(firstJoined, `"call_id":"call_1"`) { t.Fatalf("expected first call_id call_1, got %s", firstJoined) } if !strings.Contains(secondJoined, `"call_id":"call_2"`) { t.Fatalf("expected second call_id call_2, got %s", secondJoined) } }) } func TestRegistry_TranslateResponseStream_AnthropicStructuredOutbound(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) t.Run("openai", func(t *testing.T) { var state any start := []byte("event: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"tool_use\",\"id\":\"toolu_1\",\"name\":\"lookup\"}}\n\n") if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, start, &state); err != nil || out != nil { t.Fatalf("content_block_start = %#v, %v", out, err) } delta := []byte("event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"{\\\"query\\\":\\\"go\\\"}\"}}\n\n") if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, delta, &state); err != nil || out != nil { t.Fatalf("content_block_delta = %#v, %v", out, err) } toolChunk, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\n"), &state) if err != nil { t.Fatalf("content_block_stop failed: %v", err) } joined := string(toolChunk[0]) if len(toolChunk) != 1 || !strings.Contains(joined, `"tool_calls"`) || !strings.Contains(joined, `"id":"toolu_1"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"arguments":"{\"query\":\"go\"}"`) { t.Fatalf("unexpected OpenAI tool chunk: %#v", toolChunk) } finish, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"tool_use\"},\"usage\":{\"input_tokens\":3,\"output_tokens\":5}}\n\n"), &state) if err != nil { t.Fatalf("message_delta failed: %v", err) } if len(finish) != 1 || !strings.Contains(string(finish[0]), `"finish_reason":"tool_calls"`) || !strings.Contains(string(finish[0]), `"prompt_tokens":3`) { t.Fatalf("unexpected OpenAI finish chunk: %#v", finish) } done, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"), &state) if err != nil { t.Fatalf("message_stop failed: %v", err) } if len(done) != 1 || string(done[0]) != "data: [DONE]\n\n" { t.Fatalf("unexpected OpenAI done chunk: %#v", done) } }) t.Run("codex", func(t *testing.T) { var state any start := []byte("event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_1\",\"model\":\"claude-3-5-sonnet\",\"usage\":{\"input_tokens\":3,\"output_tokens\":0}}}\n\n") if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, start, &state); err != nil || out != nil { t.Fatalf("message_start = %#v, %v", out, err) } toolStart := []byte("event: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"tool_use\",\"id\":\"toolu_1\",\"name\":\"lookup\"}}\n\n") if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, toolStart, &state); err != nil || out != nil { t.Fatalf("content_block_start = %#v, %v", out, err) } toolDelta := []byte("event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"{\\\"query\\\":\\\"go\\\"}\"}}\n\n") if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, toolDelta, &state); err != nil || out != nil { t.Fatalf("content_block_delta = %#v, %v", out, err) } toolChunk, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\n"), &state) if err != nil { t.Fatalf("content_block_stop failed: %v", err) } joined := string(toolChunk[0]) if len(toolChunk) != 1 || !strings.Contains(joined, `event: response.output_item.done`) || !strings.Contains(joined, `"type":"function_call"`) || !strings.Contains(joined, `"call_id":"toolu_1"`) || !strings.Contains(joined, `"name":"lookup"`) || !strings.Contains(joined, `"arguments":"{\"query\":\"go\"}"`) { t.Fatalf("unexpected Codex tool chunk: %#v", toolChunk) } if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"tool_use\"},\"usage\":{\"output_tokens\":5}}\n\n"), &state); err != nil || out != nil { t.Fatalf("message_delta = %#v, %v", out, err) } done, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"), &state) if err != nil { t.Fatalf("message_stop failed: %v", err) } if len(done) != 1 || !strings.Contains(string(done[0]), `event: response.completed`) || !strings.Contains(string(done[0]), `"input_tokens":3`) || !strings.Contains(string(done[0]), `"output_tokens":5`) { t.Fatalf("unexpected Codex done chunk: %#v", done) } }) } func TestRegistry_TranslateResponseNonStream_AnthropicReasoningAndUsageDetails(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) rawResp := []byte(`{"id":"msg_1","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"step by step","signature":"sig_1"},{"type":"text","text":"hello"},{"type":"redacted_thinking","data":"redacted_blob"}],"model":"claude-3-5-sonnet","stop_reason":"end_turn","usage":{"input_tokens":3,"output_tokens":5,"cache_read_input_tokens":7,"cache_creation_input_tokens":11,"reasoning_tokens":13}}`) t.Run("openai", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } body := string(got) if !strings.Contains(body, `"reasoning_content":"step by step"`) || !strings.Contains(body, `"type":"thinking"`) || !strings.Contains(body, `"signature":"sig_1"`) || !strings.Contains(body, `"type":"redacted_thinking"`) || !strings.Contains(body, `"data":"redacted_blob"`) { t.Fatalf("unexpected OpenAI reasoning payload: %s", got) } if !strings.Contains(body, `"prompt_tokens":21`) || !strings.Contains(body, `"cached_tokens":7`) || !strings.Contains(body, `"cache_creation_input_tokens":11`) || !strings.Contains(body, `"reasoning_tokens":13`) { t.Fatalf("unexpected OpenAI usage payload: %s", got) } }) t.Run("codex", func(t *testing.T) { got, err := reg.TranslateResponseNonStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, rawResp) if err != nil { t.Fatalf("TranslateResponseNonStream failed: %v", err) } body := string(got) if !strings.Contains(body, `"type":"reasoning"`) || !strings.Contains(body, `"type":"reasoning_text"`) || !strings.Contains(body, `"text":"step by step"`) || !strings.Contains(body, `"encrypted_content":"sig_1"`) || !strings.Contains(body, `"text":"hello"`) { t.Fatalf("unexpected Codex reasoning payload: %s", got) } if !strings.Contains(body, `"input_tokens":21`) || !strings.Contains(body, `"cached_tokens":7`) || !strings.Contains(body, `"cache_creation_input_tokens":11`) || !strings.Contains(body, `"reasoning_tokens":13`) { t.Fatalf("unexpected Codex usage payload: %s", got) } }) } func TestRegistry_TranslateResponseStream_AnthropicReasoningAndUsageDetails(t *testing.T) { t.Parallel() reg := protocol.NewRegistry() builtin.Register(reg) t.Run("openai", func(t *testing.T) { var state any if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"model\":\"claude-3-5-sonnet\",\"usage\":{\"input_tokens\":3,\"cache_read_input_tokens\":7,\"cache_creation_input_tokens\":11}}}\n\n"), &state); err != nil || out != nil { t.Fatalf("message_start = %#v, %v", out, err) } if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"thinking\"}}\n\n"), &state); err != nil || out != nil { t.Fatalf("content_block_start = %#v, %v", out, err) } reasoning, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"step by step\"}}\n\n"), &state) if err != nil { t.Fatalf("content_block_delta failed: %v", err) } if len(reasoning) != 1 || !strings.Contains(string(reasoning[0]), `"reasoning_content":"step by step"`) { t.Fatalf("unexpected OpenAI reasoning chunk: %#v", reasoning) } meta, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"signature_delta\",\"signature\":\"sig_1\"}}\n\n"), &state) if err != nil || meta != nil { t.Fatalf("signature_delta = %#v, %v", meta, err) } meta, err = reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\n"), &state) if err != nil { t.Fatalf("content_block_stop failed: %v", err) } if len(meta) != 1 || !strings.Contains(string(meta[0]), `"reasoning"`) || !strings.Contains(string(meta[0]), `"type":"thinking"`) || !strings.Contains(string(meta[0]), `"signature":"sig_1"`) { t.Fatalf("unexpected OpenAI reasoning meta chunk: %#v", meta) } finish, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.OpenAI, "gpt-4o", nil, nil, []byte("event: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"output_tokens\":5,\"cache_read_input_tokens\":7,\"cache_creation_input_tokens\":11,\"reasoning_tokens\":13}}\n\n"), &state) if err != nil { t.Fatalf("message_delta failed: %v", err) } if len(finish) != 1 || !strings.Contains(string(finish[0]), `"prompt_tokens":21`) || !strings.Contains(string(finish[0]), `"cached_tokens":7`) || !strings.Contains(string(finish[0]), `"cache_creation_input_tokens":11`) || !strings.Contains(string(finish[0]), `"reasoning_tokens":13`) { t.Fatalf("unexpected OpenAI finish chunk: %#v", finish) } }) t.Run("codex", func(t *testing.T) { var state any if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_1\",\"model\":\"claude-3-5-sonnet\",\"usage\":{\"input_tokens\":3,\"cache_read_input_tokens\":7,\"cache_creation_input_tokens\":11}}}\n\n"), &state); err != nil || out != nil { t.Fatalf("message_start = %#v, %v", out, err) } if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"thinking\"}}\n\n"), &state); err != nil || out != nil { t.Fatalf("content_block_start = %#v, %v", out, err) } if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"step by step\"}}\n\n"), &state); err != nil || out != nil { t.Fatalf("thinking_delta = %#v, %v", out, err) } if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"signature_delta\",\"signature\":\"sig_1\"}}\n\n"), &state); err != nil || out != nil { t.Fatalf("signature_delta = %#v, %v", out, err) } reasoning, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\n"), &state) if err != nil { t.Fatalf("content_block_stop failed: %v", err) } if len(reasoning) != 1 || !strings.Contains(string(reasoning[0]), `event: response.output_item.done`) || !strings.Contains(string(reasoning[0]), `"type":"reasoning"`) || !strings.Contains(string(reasoning[0]), `"text":"step by step"`) || !strings.Contains(string(reasoning[0]), `"encrypted_content":"sig_1"`) { t.Fatalf("unexpected Codex reasoning chunk: %#v", reasoning) } if out, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"output_tokens\":5,\"cache_read_input_tokens\":7,\"cache_creation_input_tokens\":11,\"reasoning_tokens\":13}}\n\n"), &state); err != nil || out != nil { t.Fatalf("message_delta = %#v, %v", out, err) } done, err := reg.TranslateResponseStream(context.Background(), protocol.Anthropic, protocol.Codex, "gpt-5-codex", nil, nil, []byte("event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"), &state) if err != nil { t.Fatalf("message_stop failed: %v", err) } if len(done) != 1 || !strings.Contains(string(done[0]), `"input_tokens":21`) || !strings.Contains(string(done[0]), `"cached_tokens":7`) || !strings.Contains(string(done[0]), `"cache_creation_input_tokens":11`) || !strings.Contains(string(done[0]), `"reasoning_tokens":13`) { t.Fatalf("unexpected Codex done chunk: %#v", done) } }) }