| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- package service
- import (
- "net/http"
- "testing"
- "github.com/stretchr/testify/require"
- )
- func TestParseOpenAIWSEventEnvelope(t *testing.T) {
- eventType, responseID, response := parseOpenAIWSEventEnvelope([]byte(`{"type":"response.completed","response":{"id":"resp_1","model":"gpt-5.1"}}`))
- require.Equal(t, "response.completed", eventType)
- require.Equal(t, "resp_1", responseID)
- require.True(t, response.Exists())
- require.Equal(t, `{"id":"resp_1","model":"gpt-5.1"}`, response.Raw)
- eventType, responseID, response = parseOpenAIWSEventEnvelope([]byte(`{"type":"response.delta","id":"evt_1"}`))
- require.Equal(t, "response.delta", eventType)
- require.Equal(t, "evt_1", responseID)
- require.False(t, response.Exists())
- }
- func TestParseOpenAIWSResponseUsageFromCompletedEvent(t *testing.T) {
- usage := &OpenAIUsage{}
- parseOpenAIWSResponseUsageFromCompletedEvent(
- []byte(`{"type":"response.completed","response":{"usage":{"input_tokens":11,"output_tokens":7,"input_tokens_details":{"cached_tokens":3}}}}`),
- usage,
- )
- require.Equal(t, 11, usage.InputTokens)
- require.Equal(t, 7, usage.OutputTokens)
- require.Equal(t, 3, usage.CacheReadInputTokens)
- parseOpenAIWSResponseUsageFromCompletedEvent(
- []byte(`{"type":"response.completed","response":{"usage":{"prompt_tokens":19,"completion_tokens":5,"prompt_tokens_details":{"cached_tokens":4}}}}`),
- usage,
- )
- require.Equal(t, 19, usage.InputTokens)
- require.Equal(t, 5, usage.OutputTokens)
- require.Equal(t, 4, usage.CacheReadInputTokens)
- parseOpenAIWSResponseUsageFromCompletedEvent(
- []byte(`{"type":"response.completed","response":{"usage":{"input_tokens":0,"output_tokens":0,"input_tokens_details":{"cached_tokens":0}}}}`),
- usage,
- )
- require.Equal(t, OpenAIUsage{InputTokens: 19, OutputTokens: 5, CacheReadInputTokens: 4}, *usage)
- parseOpenAIWSResponseUsageFromCompletedEvent(
- []byte(`{"type":"response.failed","response":{"usage":{"input_tokens":3,"output_tokens":0,"input_tokens_details":{"cached_tokens":0}}}}`),
- usage,
- )
- require.Equal(t, OpenAIUsage{InputTokens: 3}, *usage)
- }
- func TestOpenAIWSEventShouldParseUsageTerminalEvents(t *testing.T) {
- t.Parallel()
- for _, eventType := range []string{
- "response.completed",
- "response.done",
- "response.failed",
- "response.incomplete",
- "response.cancelled",
- "response.canceled",
- } {
- require.True(t, openAIWSEventShouldParseUsage(eventType), eventType)
- require.True(t, openAIWSEventShouldParseUsage(" "+eventType+" "), eventType)
- }
- require.False(t, openAIWSEventShouldParseUsage("response.output_text.delta"))
- require.True(t, openAIWSEventShouldParseUsage("response.output_text.done"))
- require.False(t, openAIWSEventShouldParseUsage(""))
- require.False(t, openAIWSMessageShouldParseUsage("response.in_progress", []byte(`{"type":"response.in_progress"}`)))
- require.True(t, openAIWSMessageShouldParseUsage("response.in_progress", []byte(`{"type":"response.in_progress","usage":{}}`)))
- require.False(t, openAIWSMessageShouldParseUsage("response.output_text.delta", []byte(`{"type":"response.output_text.delta","usage":{}}`)))
- }
- func TestOpenAIWSErrorEventHelpers_ConsistentWithWrapper(t *testing.T) {
- message := []byte(`{"type":"error","error":{"type":"invalid_request_error","code":"invalid_request","message":"invalid input"}}`)
- codeRaw, errTypeRaw, errMsgRaw := parseOpenAIWSErrorEventFields(message)
- wrappedReason, wrappedRecoverable := classifyOpenAIWSErrorEvent(message)
- rawReason, rawRecoverable := classifyOpenAIWSErrorEventFromRaw(codeRaw, errTypeRaw, errMsgRaw)
- require.Equal(t, wrappedReason, rawReason)
- require.Equal(t, wrappedRecoverable, rawRecoverable)
- wrappedStatus := openAIWSErrorHTTPStatus(message)
- rawStatus := openAIWSErrorHTTPStatusFromRaw(codeRaw, errTypeRaw)
- require.Equal(t, wrappedStatus, rawStatus)
- require.Equal(t, http.StatusBadRequest, rawStatus)
- wrappedCode, wrappedType, wrappedMsg := summarizeOpenAIWSErrorEventFields(message)
- rawCode, rawType, rawMsg := summarizeOpenAIWSErrorEventFieldsFromRaw(codeRaw, errTypeRaw, errMsgRaw)
- require.Equal(t, wrappedCode, rawCode)
- require.Equal(t, wrappedType, rawType)
- require.Equal(t, wrappedMsg, rawMsg)
- }
- func TestOpenAIWSMessageLikelyContainsToolCalls(t *testing.T) {
- require.False(t, openAIWSMessageLikelyContainsToolCalls([]byte(`{"type":"response.output_text.delta","delta":"hello"}`)))
- require.True(t, openAIWSMessageLikelyContainsToolCalls([]byte(`{"type":"response.output_item.added","item":{"tool_calls":[{"id":"tc1"}]}}`)))
- require.True(t, openAIWSMessageLikelyContainsToolCalls([]byte(`{"type":"response.output_item.added","item":{"type":"function_call"}}`)))
- }
- func TestReplaceOpenAIWSMessageModel_OptimizedStillCorrect(t *testing.T) {
- noModel := []byte(`{"type":"response.output_text.delta","delta":"hello"}`)
- require.Equal(t, string(noModel), string(replaceOpenAIWSMessageModel(noModel, "gpt-5.1", "custom-model")))
- rootOnly := []byte(`{"type":"response.created","model":"gpt-5.1"}`)
- require.Equal(t, `{"type":"response.created","model":"custom-model"}`, string(replaceOpenAIWSMessageModel(rootOnly, "gpt-5.1", "custom-model")))
- responseOnly := []byte(`{"type":"response.completed","response":{"model":"gpt-5.1"}}`)
- require.Equal(t, `{"type":"response.completed","response":{"model":"custom-model"}}`, string(replaceOpenAIWSMessageModel(responseOnly, "gpt-5.1", "custom-model")))
- both := []byte(`{"model":"gpt-5.1","response":{"model":"gpt-5.1"}}`)
- require.Equal(t, `{"model":"custom-model","response":{"model":"custom-model"}}`, string(replaceOpenAIWSMessageModel(both, "gpt-5.1", "custom-model")))
- }
|