fix(codex): preserve assistant image slots in replay

This commit is contained in:
lEWFkRAD
2026-08-27 22:48:59 -04:00
committed by Teknium
parent 8de45940fb
commit b80b9d8271
2 changed files with 35 additions and 2 deletions
+15 -2
View File
@@ -194,8 +194,13 @@ def _chat_content_to_responses_parts(content: Any, *, role: str = "user") -> Lis
continue
if ptype in {"image_url", "input_image"}:
if role == "assistant":
# Responses API rejects input_image on assistant messages
# (HTTP 400 on every replay) — drop, see docstring (#96816).
# Responses output messages cannot carry input_image. Keep a
# text marker so image-only assistant turns still survive in
# replay and later references retain their conversational slot.
converted.append({
"type": "output_text",
"text": "[Assistant image omitted during replay]",
})
continue
image_ref = part.get("image_url")
detail = part.get("detail")
@@ -1167,6 +1172,14 @@ def _preflight_codex_input_items(
text = str(text or "")
validated.append({"type": text_type, "text": sanitize_text(text)})
elif ptype in {"input_image", "image_url"}:
if role == "assistant":
# Enforce the same output-message invariant for
# raw request overrides as for normal history.
validated.append({
"type": "output_text",
"text": "[Assistant image omitted during replay]",
})
continue
image_ref = part.get("image_url", "")
detail = part.get("detail")
if isinstance(image_ref, dict):
@@ -30,6 +30,8 @@ def test_chat_content_drops_images_from_assistant_role():
assert _chat_content_to_responses_parts(content, role="assistant") == [
{"type": "output_text", "text": "generated image"},
{"type": "output_text", "text": "[Assistant image omitted during replay]"},
{"type": "output_text", "text": "[Assistant image omitted during replay]"},
]
@@ -46,6 +48,24 @@ def test_chat_content_keeps_images_on_user_role():
}]
def test_preflight_rewrites_raw_assistant_images_to_text_markers():
raw = [{
"role": "assistant",
"content": [{
"type": "input_image",
"image_url": "https://example.invalid/p.png",
}],
}]
assert _preflight_codex_input_items(raw) == [{
"role": "assistant",
"content": [{
"type": "output_text",
"text": "[Assistant image omitted during replay]",
}],
}]
def _harmony_token(name: str) -> str:
"""Build a literal Harmony token without spelling it contiguously here."""
return f"<\x7c{name}\x7c>"