package responses import ( "strings" "testing" "time" "ds2api/internal/httpapi/openai/embeddings" "ds2api/internal/promptcompat" ) func TestNormalizeResponsesInputAsMessagesString(t *testing.T) { msgs := promptcompat.NormalizeResponsesInputAsMessages("hello") if len(msgs) != 1 { t.Fatalf("expected one message, got %d", len(msgs)) } m, _ := msgs[0].(map[string]any) if m["role"] != "user" || m["content"] != "hello" { t.Fatalf("unexpected message: %#v", m) } } func TestResponsesMessagesFromRequestWithInstructions(t *testing.T) { req := map[string]any{ "model": "gpt-4.1", "input": "ping", "instructions": "system text", } msgs := promptcompat.ResponsesMessagesFromRequest(req) if len(msgs) != 2 { t.Fatalf("expected two messages, got %d", len(msgs)) } sys, _ := msgs[0].(map[string]any) if sys["role"] != "system" { t.Fatalf("unexpected first message: %#v", sys) } } func TestNormalizeResponsesInputAsMessagesObjectRoleContentBlocks(t *testing.T) { msgs := promptcompat.NormalizeResponsesInputAsMessages(map[string]any{ "role": "user", "content": []any{ map[string]any{"type": "input_text", "text": "line-1"}, map[string]any{"type": "input_text", "text": "line-2"}, }, }) if len(msgs) != 1 { t.Fatalf("expected one message, got %d", len(msgs)) } m, _ := msgs[0].(map[string]any) if m["role"] != "user" { t.Fatalf("unexpected role: %#v", m) } if strings.TrimSpace(promptcompat.NormalizeOpenAIContentForPrompt(m["content"])) != "line-1\nline-2" { t.Fatalf("unexpected content: %#v", m["content"]) } } func TestNormalizeResponsesInputAsMessagesFunctionCallOutput(t *testing.T) { msgs := promptcompat.NormalizeResponsesInputAsMessages([]any{ map[string]any{ "type": "function_call_output", "call_id": "call_123", "output": map[string]any{"ok": true}, }, }) if len(msgs) != 1 { t.Fatalf("expected one message, got %d", len(msgs)) } m, _ := msgs[0].(map[string]any) if m["role"] != "tool" { t.Fatalf("expected tool role, got %#v", m) } if m["tool_call_id"] != "call_123" { t.Fatalf("expected tool_call_id propagated, got %#v", m) } } func TestNormalizeResponsesInputAsMessagesBackfillsToolResultNameFromCallID(t *testing.T) { msgs := promptcompat.NormalizeResponsesInputAsMessages([]any{ map[string]any{ "type": "function_call", "call_id": "call_999", "name": "search", "arguments": `{"q":"golang"}`, }, map[string]any{ "type": "function_call_output", "call_id": "call_999", "output": map[string]any{"ok": true}, }, }) if len(msgs) != 2 { t.Fatalf("expected two messages, got %d", len(msgs)) } toolMsg, _ := msgs[1].(map[string]any) if toolMsg["role"] != "tool" { t.Fatalf("expected tool role, got %#v", toolMsg) } if toolMsg["name"] != "search" { t.Fatalf("expected tool name backfilled from call_id, got %#v", toolMsg["name"]) } } func TestNormalizeResponsesInputAsMessagesFunctionCallItem(t *testing.T) { msgs := promptcompat.NormalizeResponsesInputAsMessages([]any{ map[string]any{ "type": "function_call", "call_id": "call_456", "name": "search", "arguments": `{"q":"golang"}`, }, }) if len(msgs) != 1 { t.Fatalf("expected one message, got %d", len(msgs)) } m, _ := msgs[0].(map[string]any) if m["role"] != "assistant" { t.Fatalf("expected assistant role, got %#v", m["role"]) } toolCalls, _ := m["tool_calls"].([]any) if len(toolCalls) != 1 { t.Fatalf("expected one tool_call, got %#v", m["tool_calls"]) } call, _ := toolCalls[0].(map[string]any) if call["id"] != "call_456" { t.Fatalf("expected call id preserved, got %#v", call) } if call["type"] != "function" { t.Fatalf("expected function type, got %#v", call) } fn, _ := call["function"].(map[string]any) if fn["name"] != "search" { t.Fatalf("expected call name preserved, got %#v", call) } if fn["arguments"] != `{"q":"golang"}` { t.Fatalf("expected call arguments preserved, got %#v", call) } } func TestNormalizeResponsesInputAsMessagesFunctionCallItemPreservesConcatenatedArguments(t *testing.T) { msgs := promptcompat.NormalizeResponsesInputAsMessages([]any{ map[string]any{ "type": "function_call", "call_id": "call_456", "name": "search", "arguments": `{}{"q":"golang"}`, }, }) if len(msgs) != 1 { t.Fatalf("expected one message, got %d", len(msgs)) } m, _ := msgs[0].(map[string]any) toolCalls, _ := m["tool_calls"].([]any) call, _ := toolCalls[0].(map[string]any) fn, _ := call["function"].(map[string]any) if fn["arguments"] != `{}{"q":"golang"}` { t.Fatalf("expected original concatenated call arguments preserved, got %#v", fn["arguments"]) } } func TestCollectOpenAIRefFileIDs(t *testing.T) { got := promptcompat.CollectOpenAIRefFileIDs(map[string]any{ "ref_file_ids": []any{"file-top", "file-dup"}, "attachments": []any{ map[string]any{"file_id": "file-attachment"}, }, "input": []any{ map[string]any{ "type": "message", "content": []any{ map[string]any{"type": "input_file", "file_id": "file-input"}, map[string]any{"type": "input_file", "id": "file-dup"}, }, }, }, }) want := []string{"file-top", "file-dup", "file-attachment", "file-input"} if len(got) != len(want) { t.Fatalf("expected %d file ids, got %#v", len(want), got) } for i, id := range want { if got[i] != id { t.Fatalf("unexpected file ids at %d: got=%#v want=%#v", i, got, want) } } } func TestExtractEmbeddingInputs(t *testing.T) { got := embeddings.ExtractEmbeddingInputs([]any{"a", "b"}) if len(got) != 2 || got[0] != "a" || got[1] != "b" { t.Fatalf("unexpected inputs: %#v", got) } } func TestDeterministicEmbeddingStable(t *testing.T) { a := embeddings.DeterministicEmbedding("hello") b := embeddings.DeterministicEmbedding("hello") if len(a) != 64 || len(b) != 64 { t.Fatalf("expected 64 dims, got %d and %d", len(a), len(b)) } for i := range a { if a[i] != b[i] { t.Fatalf("expected stable embedding at %d: %v != %v", i, a[i], b[i]) } } } func TestResponseStorePutGet(t *testing.T) { st := newResponseStore(100 * time.Millisecond) st.put("owner_1", "resp_1", map[string]any{"id": "resp_1"}) got, ok := st.get("owner_1", "resp_1") if !ok { t.Fatal("expected stored response") } if got["id"] != "resp_1" { t.Fatalf("unexpected response payload: %#v", got) } } func TestResponseStoreTenantIsolation(t *testing.T) { st := newResponseStore(100 * time.Millisecond) st.put("owner_a", "resp_1", map[string]any{"id": "resp_1"}) if _, ok := st.get("owner_b", "resp_1"); ok { t.Fatal("expected owner_b to be isolated from owner_a response") } }