diff --git a/providers/anthropic/anthropic.go b/providers/anthropic/anthropic.go index a1816bd8f..007a4edbf 100644 --- a/providers/anthropic/anthropic.go +++ b/providers/anthropic/anthropic.go @@ -1268,10 +1268,12 @@ func mapFinishReason(finishReason string) fantasy.FinishReason { switch finishReason { case "end_turn", "pause_turn", "stop_sequence": return fantasy.FinishReasonStop - case "max_tokens": + case "max_tokens", "model_context_window_exceeded": return fantasy.FinishReasonLength case "tool_use": return fantasy.FinishReasonToolCalls + case "refusal": + return fantasy.FinishReasonContentFilter default: return fantasy.FinishReasonUnknown } diff --git a/providers/anthropic/anthropic_test.go b/providers/anthropic/anthropic_test.go index 2ee0cfe70..c4854be99 100644 --- a/providers/anthropic/anthropic_test.go +++ b/providers/anthropic/anthropic_test.go @@ -3237,3 +3237,26 @@ func TestStream_TruncatedWithoutStopReason(t *testing.T) { require.True(t, providerErr.IsRetryable()) require.ErrorIs(t, providerErr.Cause, io.ErrUnexpectedEOF) } + +func TestMapFinishReason(t *testing.T) { + t.Parallel() + + tests := []struct { + reason string + expected fantasy.FinishReason + }{ + {"end_turn", fantasy.FinishReasonStop}, + {"pause_turn", fantasy.FinishReasonStop}, + {"stop_sequence", fantasy.FinishReasonStop}, + {"max_tokens", fantasy.FinishReasonLength}, + {"model_context_window_exceeded", fantasy.FinishReasonLength}, + {"tool_use", fantasy.FinishReasonToolCalls}, + {"refusal", fantasy.FinishReasonContentFilter}, + {"", fantasy.FinishReasonUnknown}, + {"unrecognized_future_reason", fantasy.FinishReasonUnknown}, + } + + for _, tc := range tests { + require.Equal(t, tc.expected, mapFinishReason(tc.reason), "stop_reason %q", tc.reason) + } +}