Skip to content

fix(openai): send type="message" on all Responses API message input items - #444

Merged
cpsievert merged 1 commit into
mainfrom
fix/openai-responses-message-type
Oct 7, 2026
Merged

cpsievert merged 1 commit into
mainfrom
fix/openai-responses-message-type

Conversation

@cpsievert

Copy link
Copy Markdown
Collaborator

Ports tidyverse/ellmer#1161 (fixes tidyverse/ellmer#1153).

Problem

Every message-shaped input item ChatOpenAI() serializes for the Responses API (user/system text, images, PDFs, documents, uploaded-file references) carried role and content but no top-level type. type is optional in the published schema and OpenAI infers it, but llama.cpp's /v1/responses parser only infers it for system/developer/user items, not assistant — so a replayed assistant turn gets rejected with HTTP 400 Cannot determine type of 'item', which is terminal for any tool-using conversation.

Fix

as_message() (the single helper all non-assistant message items go through) now includes "type": "message". The assistant-text path already set it. This is a no-op against OpenAI itself and fixes every OpenAI-compatible server that discriminates on it.

Cassettes

Since VCR matches on (structurally parsed) request bodies, the 72 affected cassettes' recorded request bodies were hand-updated to add the new field — response bodies are untouched, so all recorded-response assertions (token counts, etc.) remain valid. This mirrors the approach taken in the ellmer PR.

Tests

  • New test_all_message_input_items_carry_type_message covers text, PDF, and assistant items across roles.
  • All modules with modified cassettes pass (190 tests).

…tems

The Responses API marks `type` optional on message-shaped input items and
OpenAI infers it, but some OpenAI-compatible servers (e.g. llama.cpp) only
infer it for system/developer/user items and reject replayed assistant
items without it, which is terminal for any tool-using conversation.
Setting it explicitly is a no-op against OpenAI itself.

VCR cassettes were hand-updated (bodies only; responses untouched) since
body matching is structural JSON.

Ports tidyverse/ellmer#1161 (fixes tidyverse/ellmer#1153).
@cpsievert
cpsievert merged commit 1746ec6 into main Oct 7, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant