fix(codex): preserve assistant image slots in replay
This commit is contained in:
@@ -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>"
|
||||
|
||||
Reference in New Issue
Block a user