Skip to content

fix(codex): classify content-filter incomplete responses as terminal refusals - #65061

Merged
teknium1 merged 1 commit into
mainfrom
fix/55637-codex-content-filter-refusal
Jul 15, 2026
Merged

fix(codex): classify content-filter incomplete responses as terminal refusals#65061
teknium1 merged 1 commit into
mainfrom
fix/55637-codex-content-filter-refusal

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Codex Responses content-filter refusals (status="incomplete" + incomplete_details.reason="content_filter", typically with output=[]) are now classified as terminal finish_reason="content_filter" and routed through the existing content-policy refusal path — instead of falling into invalid-response retries plus 3 continuation attempts that end in the misleading "Codex response remained incomplete after 3 continuation attempts".

Salvages #55639 (@sk-holmes, fixes #55637) with authorship preserved. Chosen over duplicates #55682 (loop-only — misses the empty-output validation gap, so the refusal dies in invalid-response retries before its branch runs) and #55718 (adapter-only + unrelated STT change); @sk-holmes's was both first-submitted and the only one covering all three layers.

Changes (@sk-holmes)

  • agent/transports/codex.py: validate_response accepts the empty-output content-filter shape as a valid terminal response so it reaches normalization; empty-output non-filter responses still fail validation
  • agent/codex_responses_adapter.py: the refusal outranks every other finish reason; empty-output refusals synthesize an empty message instead of raising "no output items"
  • agent/conversation_loop.py: the codex_responses status check maps the refusal to finish_reason="content_filter" (case-normalized), joining the existing refusal handling (ContentPolicyBlocked, provider fallback)

Validation

Shape Before After
incomplete + content_filter + output=[] invalid-response retries → misleading error terminal content_filter, refusal path + fallback
incomplete + content_filter + reasoning item (codex backend) reasoning-only continuation ×3 terminal content_filter (refusal outranks)
incomplete + max_output_tokens continuation continuation (unchanged)
completed + output=[] RuntimeError RuntimeError (unchanged)

Infographic

content-filter-refusal-classification

Map Codex Responses status=incomplete with incomplete_details.reason=content_filter to finish_reason=content_filter so the existing refusal/fallback path runs instead of burning incomplete continuation attempts.
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/openai OpenAI / Codex Responses API codex P2 Medium — degraded but workaround exists labels Jul 15, 2026
@teknium1
teknium1 merged commit fe1ab94 into main Jul 15, 2026
31 checks passed
@teknium1
teknium1 deleted the fix/55637-codex-content-filter-refusal branch July 15, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Codex incomplete content_filter Responses are handled as incomplete retries

3 participants