ccpoad / internal /protocol /registry_structured_response_test.go
anyalerob's picture
Upload folder using huggingface_hub
2986042 verified
Raw
History Blame Contribute Delete
35.8 kB
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)
}
})
}