Skip to content

OpenAI Responses API model classes#1435

Merged
simonw merged 12 commits into
mainfrom
claude/research-openai-tool-calls-595q7
May 12, 2026
Merged

OpenAI Responses API model classes#1435
simonw merged 12 commits into
mainfrom
claude/research-openai-tool-calls-595q7

Conversation

@simonw

@simonw simonw commented May 6, 2026

Copy link
Copy Markdown
Owner

We need to leave the existing chat completion class alone, since other plugins import it

Instead we will add a new class which implements the responses API but also offers a special chat_completions Boolean option which, if set, dispatches to the existing chat completions implantation. This is so when we register model they can use the new responses class but callers can still opt in to chat completions using "-o chat_completions 1" if they really need to

Start by building that new class and testing it interest against the real API - there is an OPENAI_API_KEY in this environment so testing with "llm -m gpt-5.5 hello" should work, try that once first to confirm it does before you start coding

Get it all working and then add new tests by capturing test data using the mechanism described in the README

https://claude.ai/code/session_01S7UevnY7zKogbthSz4UXJv

claude and others added 4 commits May 6, 2026 01:57
Adds Responses and AsyncResponses classes that drive the OpenAI
/v1/responses endpoint. The existing Chat / AsyncChat classes are
unchanged because other plugins import them.

gpt-5.5 (and gpt-5.5-2026-04-23) is now registered against Responses
by default. Pass `-o chat_completions 1` to fall back to the older
/v1/chat/completions code path.

This is feature parity with the Chat path (text, tools, streaming,
schema, reasoning_effort, verbosity, attachments, system prompts).
Interleaved reasoning across tool round-trips is not exercised yet -
encrypted reasoning items are accepted on the input side, but the
plugin doesn't yet stash them on outgoing ReasoningParts.
When the Responses API returns a reasoning item alongside function
calls, capture its opaque id + encrypted_content as provider_metadata
on the resulting ReasoningPart. _build_responses_input already echoed
that metadata back as a reasoning input item on the next turn - now
the output side actually populates it.

This preserves the model's hidden chain of thought across the tool
round-trip. Without it, GPT-5-class models silently lose ~3% on
SWE-bench (per OpenAI) when used with tools.

Adds a dedicated VCR test that asserts the encrypted_content captured
on the first turn appears verbatim in the second turn's outgoing
request body.
The previous commit wired up encrypted_content round-trip but only
tested that the data flows through correctly on a single tool round-
trip. This adds a multi-turn cassette test that proves the full
interleaved-reasoning capability:

- Each turn produces fresh reasoning_tokens (not just the first)
- Every prior reasoning block is round-tripped on every subsequent
  turn (the Nth turn echoes >= N-1 reasoning items)
- ReasoningParts persisted on the assistant messages carry the same
  encrypted_content + id that gets sent back on the wire

The puzzle is shaped so the model can't parallelize tool calls -
each db_lookup result tells it the next key to use, forcing the
model to think between calls. The recorded 4-turn chain shows
reasoning_tokens of 45/98/196/17 across turns with reasoning items
accumulating in every outgoing input.

This is the GPT-5-class capability that Chat Completions can't
deliver because it discards reasoning between turns.
@simonw simonw added enhancement New feature or request openai labels May 6, 2026
@simonw simonw marked this pull request as ready for review May 12, 2026 04:48
@simonw

simonw commented May 12, 2026

Copy link
Copy Markdown
Owner Author

I had Codex run a manual testing run against the branch using Showboat, results here: https://gist.github.com/simonw/19cfef23659a939c12b1f8a6ccfe227a

@simonw

simonw commented May 12, 2026

Copy link
Copy Markdown
Owner Author

Had Codex write and execute a script to test ALL the model IDs, which I used to help decide which ones to port to Responses: https://gist.github.com/simonw/4d1a1749475b092a328b92ae5f272e87

simonw added 3 commits May 11, 2026 22:40
When building the `input` list for the OpenAI Responses API from prior
conversation turns, an assistant text-only turn was being serialized as:

    {"role": "assistant",
     "content": [{"type": "output_text", "text": "..."}]}

The openai-python SDK's EasyInputMessage shape uses a plain string for
this case, matching what a direct OpenAI Responses call would send. Use
the same shape so our history matches the SDK exactly, and add tests
covering both _build_responses_input and a two-turn response.reply()
flow.
@simonw simonw changed the title OpenAI Responses API client OpenAI Responses API model classes May 12, 2026
@simonw simonw merged commit 40549b2 into main May 12, 2026
32 checks passed
@simonw simonw deleted the claude/research-openai-tool-calls-595q7 branch May 12, 2026 15:32
simonw added a commit that referenced this pull request May 12, 2026
simonw added a commit that referenced this pull request May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request openai

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants