diff --git a/.changeset/gemini-blocked-finish-reasons.md b/.changeset/gemini-blocked-finish-reasons.md new file mode 100644 index 0000000000..e67d63768c --- /dev/null +++ b/.changeset/gemini-blocked-finish-reasons.md @@ -0,0 +1,5 @@ +--- +'manifest': patch +--- + +Report Gemini replies blocked for BLOCKLIST, PROHIBITED_CONTENT, SPII or IMAGE_SAFETY as `content_filter` instead of `stop`. diff --git a/packages/backend/src/routing/proxy/__tests__/google-adapter.spec.ts b/packages/backend/src/routing/proxy/__tests__/google-adapter.spec.ts index 2a7191f382..82cddc9318 100644 --- a/packages/backend/src/routing/proxy/__tests__/google-adapter.spec.ts +++ b/packages/backend/src/routing/proxy/__tests__/google-adapter.spec.ts @@ -1732,6 +1732,23 @@ describe('Google Adapter', () => { expect(choices[0].finish_reason).toBe('content_filter'); }); + it.each(['BLOCKLIST', 'PROHIBITED_CONTENT', 'SPII', 'IMAGE_SAFETY'])( + 'maps %s finish reason to content_filter', + (finishReason) => { + const google = { + candidates: [ + { + content: { parts: [{ text: '' }] }, + finishReason, + }, + ], + }; + const result = fromGoogleResponse(google, 'gemini-2.0-flash'); + const choices = result.choices as Array<{ finish_reason: string }>; + expect(choices[0].finish_reason).toBe('content_filter'); + }, + ); + it('maps unknown finish reason to stop', () => { const google = { candidates: [ diff --git a/packages/backend/src/routing/proxy/google-adapter.ts b/packages/backend/src/routing/proxy/google-adapter.ts index 760701c414..4a5f161c17 100644 --- a/packages/backend/src/routing/proxy/google-adapter.ts +++ b/packages/backend/src/routing/proxy/google-adapter.ts @@ -544,6 +544,10 @@ function mapFinishReason(candidate: Record, hasToolCalls = fals MAX_TOKENS: 'length', SAFETY: 'content_filter', RECITATION: 'content_filter', + BLOCKLIST: 'content_filter', + PROHIBITED_CONTENT: 'content_filter', + SPII: 'content_filter', + IMAGE_SAFETY: 'content_filter', }; return map[reason] ?? 'stop'; }