Skip to content

fix(provider): skip Azure content-filter preamble frames - #3817

Merged
kwakayama merged 2 commits into
mainfrom
fix/azure-content-filter-preamble
Aug 17, 2026
Merged

fix(provider): skip Azure content-filter preamble frames#3817
kwakayama merged 2 commits into
mainfrom
fix/azure-content-filter-preamble

Conversation

@kwakayama

@kwakayama kwakayama commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3815, from sweeping all 16 catalog models against the live gateway.

No version bump — this PR does not cut a release. Stays at 0.1.1241; the release is cut separately.

Problem

Azure OpenAI opens a stream with an informational content-filter report before any content. Captured live from https://api.veryfront.org/ai/gateway/openai/v1/chat/completions on 2026-08-17 — first data chunk for both gpt-5.4 and gpt-5.5:

{"choices":[],"created":0,"id":"","model":"","object":"",
 "prompt_filter_results":[{"prompt_index":0,"content_filter_results":{
   "hate":{"filtered":false,"severity":"safe"},
   "jailbreak":{"detected":false,"filtered":false},
   "self_harm":{"filtered":false,"severity":"safe"},
   "sexual":{"filtered":false,"severity":"safe"},
   "violence":{"filtered":false,"severity":"safe"}}}]}

Empty choices, no usage. The parser required usage on any content-free frame and failed the whole stream:

ProviderRequestError: invalid successful stream (empty choices event had no usage)

gpt-5.2 does not emit it — it is not on the Azure route.

Honest severity: latent, not an outage

No user is affected today, and I want that on the record rather than overstated.

gpt-5.4 and gpt-5.5 never reach this parser: openai-provider.ts:1308-1310 routes reasoning models to the Responses API, and both qualify (isReasoningCapableGpt5 matches gpt-5.<n> for n >= 2, src/provider/shared/openai-reasoning.ts:29-40; supportsDefaultReasoningParams is true for veryfront-cloud, same file :16-19).

Loki corroborates:

Why fix it anyway

Kimi is Azure-routed and does use this parser. terraform/staging/variables.tf deploys kimi-k26-staging / kimi-k25-staging on Azure AI Foundry, and Moonshot models go through Chat Completions, not Responses. Kimi does not emit a content-filter preamble today — but that is an Azure deployment setting, not a property of the model. Enabling content filtering there would break Kimi instantly, in exactly the way #3815 just repaired.

Secondary: the guard is wrong on the merits. An empty choices array simply carries no content. Usage-only frames use the same shape and were already tolerated; this is the same case. There was no coverage at all — grep -rn prompt_filter_results over extensions/ and src/ returned nothing.

Fix

Skip content-free frames instead of demanding usage. A missing choices key stays rejected — that is a malformed event rather than a content-free one, and that guard keeps its test.

Two files, 41 insertions.

Verification

TDD red → green: the new test fails on main with the exact production error, then passes.

Replaying the verbatim captured streams:

                 BEFORE (main)                          AFTER
gpt-5.4   invalid successful stream (empty…)   parts: {"text-delta":2,"finish":1}
gpt-5.5   invalid successful stream (empty…)   parts: {"text-delta":2,"finish":1}
gpt-5.2   parts: {"text-delta":2,"finish":1}   parts: {"text-delta":2,"finish":1}

Kimi captures still parse fully after this change — text stream 23 reasoning deltas, tool stream through to tool-call + finish.

deno test extensions/ext-llm-openai/ src/utils/version.test.ts — 11 passed (178 steps), 0 failed.

Fixes veryfront/veryfront-issue-inbox#543

Azure OpenAI opens a stream with an informational content-filter report
before any content:

    {"choices":[],"created":0,"id":"","model":"","object":"",
     "prompt_filter_results":[{"prompt_index":0,"content_filter_results":{...}}]}

Empty `choices`, no `usage`. The parser required usage on any content-free
frame and failed the whole stream with "empty choices event had no usage".

An empty `choices` array simply carries no content. Usage-only frames use the
same shape and were already tolerated; the preamble is the same case. Skip the
frame. A missing `choices` key stays rejected -- that is a malformed event
rather than a content-free one.

No user is affected today: gpt-5.4 and gpt-5.5 are the only models observed
emitting the preamble, and both route to the Responses API instead
(openai-provider.ts:1308, isReasoningCapableGpt5 matches gpt-5.<n> for n>=2).
Loki confirms zero occurrences in 30 days, and the only stream error in
veryfront-server over 7 days is the Kimi one fixed in #3815.

It is still worth closing. Kimi is Azure-routed and does use this parser, so
enabling content filtering on that Foundry deployment would break it instantly
in exactly the way #3815 just repaired.

Tests replay the verbatim captured Azure preamble.

Fixes veryfront/veryfront-issue-inbox#543
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cec647d1-7146-4c4c-b143-c857e3fe1183


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

📦 Client bundle boundary

Entrypoint Modules Source size Server leaks
src/index.client.ts 325 1937 KiB ✅ 0

A server module in a client graph aborts hydration in the browser. New leaks fail CI; known leaks are tracked in scripts/lint/client-bundle-baseline.json to burn down.

Keep 0.1.1241 so merging this does not trigger a publish. The release will be
cut separately.
@kwakayama
kwakayama added this pull request to the merge queue Aug 17, 2026
Merged via the queue into main with commit 5b0ba2b Aug 17, 2026
34 checks passed
@kwakayama
kwakayama deleted the fix/azure-content-filter-preamble branch August 17, 2026 11:46
This was referenced Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant