package apicompat import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestAnthropicStreamingMaxTokens_MapsToIncomplete(t *testing.T) { state := NewAnthropicEventToResponsesState() AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_start", Message: &AnthropicResponse{ID: "msg_test", Model: "claude-opus-4-6", Role: "assistant"}, }, state) AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_delta", Delta: &AnthropicDelta{ StopReason: "max_tokens", }, Usage: &AnthropicUsage{OutputTokens: 4096}, }, state) require.Equal(t, "max_tokens", state.StopReason) events := AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_stop", }, state) var completed *ResponsesStreamEvent for i := range events { if events[i].Type == "response.completed" || events[i].Type == "response.incomplete" { completed = &events[i] break } } require.NotNil(t, completed, "should have terminal event") assert.Equal(t, "response.incomplete", completed.Type) require.NotNil(t, completed.Response) assert.Equal(t, "incomplete", completed.Response.Status) require.NotNil(t, completed.Response.IncompleteDetails) assert.Equal(t, "max_output_tokens", completed.Response.IncompleteDetails.Reason) } func TestAnthropicStreamingMaxTokens_FinalizeMapsToIncompleteWithoutMessageStop(t *testing.T) { state := NewAnthropicEventToResponsesState() AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_start", Message: &AnthropicResponse{ID: "msg_test", Model: "claude-opus-4-6", Role: "assistant"}, }, state) AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_delta", Delta: &AnthropicDelta{StopReason: "max_tokens"}, Usage: &AnthropicUsage{OutputTokens: 4096}, }, state) events := FinalizeAnthropicResponsesStream(state) require.Len(t, events, 1) assert.Equal(t, "response.incomplete", events[0].Type) require.NotNil(t, events[0].Response) assert.Equal(t, "incomplete", events[0].Response.Status) require.NotNil(t, events[0].Response.IncompleteDetails) assert.Equal(t, "max_output_tokens", events[0].Response.IncompleteDetails.Reason) assert.Empty(t, FinalizeAnthropicResponsesStream(state), "repeated finalization must be idempotent") } func TestAnthropicStreamingEndTurn_MapsToCompleted(t *testing.T) { state := NewAnthropicEventToResponsesState() AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_start", Message: &AnthropicResponse{ID: "msg_test", Model: "claude-opus-4-6", Role: "assistant"}, }, state) AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_delta", Delta: &AnthropicDelta{StopReason: "end_turn"}, Usage: &AnthropicUsage{OutputTokens: 100}, }, state) events := AnthropicEventToResponsesEvents(&AnthropicStreamEvent{ Type: "message_stop", }, state) var completed *ResponsesStreamEvent for i := range events { if events[i].Type == "response.completed" { completed = &events[i] break } } require.NotNil(t, completed) assert.Equal(t, "completed", completed.Response.Status) assert.Nil(t, completed.Response.IncompleteDetails) } func TestResponsesToChatCompletions_ContentFilter(t *testing.T) { resp := &ResponsesResponse{ ID: "resp_cf", Status: "incomplete", IncompleteDetails: &ResponsesIncompleteDetails{ Reason: "content_filter", }, Output: []ResponsesOutput{{ Type: "message", Content: []ResponsesContentPart{{Type: "output_text", Text: "partial"}}, }}, Usage: &ResponsesUsage{InputTokens: 10, OutputTokens: 5}, } cc := ResponsesToChatCompletions(resp, "gpt-5.5") require.Len(t, cc.Choices, 1) assert.Equal(t, "content_filter", cc.Choices[0].FinishReason) } func TestResponsesToChatCompletionsStreaming_ContentFilter(t *testing.T) { state := NewResponsesEventToChatState() state.ID = "resp_cf" state.Model = "gpt-5.5" state.SentRole = true events := ResponsesEventToChatChunks(&ResponsesStreamEvent{ Type: "response.completed", Response: &ResponsesResponse{ ID: "resp_cf", Status: "incomplete", IncompleteDetails: &ResponsesIncompleteDetails{ Reason: "content_filter", }, }, }, state) hasContentFilter := false for _, chunk := range events { for _, choice := range chunk.Choices { if choice.FinishReason != nil && *choice.FinishReason == "content_filter" { hasContentFilter = true } } } assert.True(t, hasContentFilter, "streaming content_filter should map to finish_reason content_filter") }