fix(auxiliary): treat a content-filtered Codex aux partial as length

An incomplete response with incomplete_details.reason=content_filter kept
finish_reason 'content_filter'. The aux consumers (context compressor
truncation guard, micro_compaction, MCP sampling) only reject 'length', so a
filtered partial summary was committed as if it were complete. No aux
consumer reads 'content_filter', so map every provider-incomplete response to
'length' (completed tool calls still stay 'tool_calls').
This commit is contained in:
kshitijk4poor
2026-10-05 13:42:45 +05:30
committed by kshitij
parent a5cdd9ee29
commit 8314d3bb28
2 changed files with 5 additions and 5 deletions

View File

@@ -1155,12 +1155,10 @@ def _parse_codex_final_response(
)
# Aux consumers speak Chat Completions: "length" activates their existing
# partial-summary rejection/fallback, whereas Codex's "incomplete" does not.
# A final_answer phase cannot override the provider's incomplete status, but completed
# tool calls stay "tool_calls" so dispatchers (e.g. MCP sampling) still run them.
status = _lower_or_none(normalized_final.status)
reason = str(_field(normalized_final.incomplete_details, "reason", "") or "").strip().lower()
# Any provider-incomplete response (token cap or content_filter) is a partial no aux consumer
# may commit; completed tool calls stay "tool_calls" so dispatchers (e.g. MCP sampling) still run them.
if finish_reason != "tool_calls" and (
finish_reason == "incomplete" or (status == "incomplete" and reason != "content_filter")
finish_reason == "incomplete" or _lower_or_none(normalized_final.status) == "incomplete"
):
finish_reason = "length"
text_parts = [message.content] if message.content else []

View File

@@ -99,6 +99,8 @@ _CODEX_REASONING_ONLY = SimpleNamespace(
id="tool-call-like-output-text-beside-commentary"),
pytest.param("", "incomplete", [_message("PARTIAL")], "max_output_tokens", "PARTIAL", "length", id="token-cap"),
pytest.param("", "incomplete", [_TOOL_CALL], "max_output_tokens", None, "tool_calls", id="token-cap-after-tool-call"),
# Compressor only rejects "length": a content-filtered partial must not be committed as a summary.
pytest.param("", "incomplete", [_message("CF")], "content_filter", "CF", "length", id="content-filter"),
# Commentary + unphased text is incomplete whether or not the unphased text looks like a tool call.
pytest.param("", "completed", [_message("NOTE", phase="commentary"), _message(_LEAK_LIKE_ANSWER, phase=None)],
None, _LEAK_LIKE_ANSWER, "length", id="tool-call-like-beside-commentary"),