mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-21 14:19:18 +08:00
fix(apicompat): preserve incomplete stream finalization
This commit is contained in:
@@ -211,8 +211,8 @@ func FinalizeAnthropicResponsesStream(state *AnthropicEventToResponsesState) []R
|
||||
// Close any open item
|
||||
events = append(events, closeCurrentResponsesItem(state)...)
|
||||
|
||||
// Emit response.completed
|
||||
events = append(events, makeResponsesCompletedEvent(state, "completed", nil))
|
||||
status, incompleteDetails := anthropicResponsesStreamTerminalState(state.StopReason)
|
||||
events = append(events, makeResponsesCompletedEvent(state, status, incompleteDetails))
|
||||
state.CompletedSent = true
|
||||
return events
|
||||
}
|
||||
@@ -434,13 +434,7 @@ func anthToResHandleMessageStop(state *AnthropicEventToResponsesState) []Respons
|
||||
var events []ResponsesStreamEvent
|
||||
events = append(events, closeCurrentResponsesItem(state)...)
|
||||
|
||||
status := "completed"
|
||||
var incompleteDetails *ResponsesIncompleteDetails
|
||||
if state.StopReason == "max_tokens" {
|
||||
status = "incomplete"
|
||||
incompleteDetails = &ResponsesIncompleteDetails{Reason: "max_output_tokens"}
|
||||
}
|
||||
|
||||
status, incompleteDetails := anthropicResponsesStreamTerminalState(state.StopReason)
|
||||
events = append(events, makeResponsesCompletedEvent(state, status, incompleteDetails))
|
||||
state.CompletedSent = true
|
||||
return events
|
||||
@@ -448,6 +442,13 @@ func anthToResHandleMessageStop(state *AnthropicEventToResponsesState) []Respons
|
||||
|
||||
// --- helper functions ---
|
||||
|
||||
func anthropicResponsesStreamTerminalState(stopReason string) (string, *ResponsesIncompleteDetails) {
|
||||
if stopReason == "max_tokens" {
|
||||
return "incomplete", &ResponsesIncompleteDetails{Reason: "max_output_tokens"}
|
||||
}
|
||||
return "completed", nil
|
||||
}
|
||||
|
||||
func closeCurrentResponsesItem(state *AnthropicEventToResponsesState) []ResponsesStreamEvent {
|
||||
if state.CurrentItemType == "" {
|
||||
return nil
|
||||
|
||||
@@ -44,6 +44,29 @@ func TestAnthropicStreamingMaxTokens_MapsToIncomplete(t *testing.T) {
|
||||
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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user