Three Ways to Talk to a Model: Anthropic Messages, Chat Completions, and Responses
There is no single standard for sending a prompt to an LLM. There are three competing wire formats, they disagree on nearly every detail that matters, and the gap between them is why swapping providers is rarely a one-line change.
July 23, 2026
There’s a piece of folk wisdom that goes around whenever someone complains about their AI bill: just switch providers. Point your code at a cheaper model, change one URL, change the model name, done. And for a certain slice of cases, that’s genuinely true. You can move a plain chat request from OpenAI to a dozen other providers without touching much else.
The moment you use anything modern, that wisdom falls apart. Tool calling, reasoning, streaming, server-side conversation state: these are exactly the features that don’t survive the trip. The reason is that there is no universal way to send a prompt to a large language model. There are at least three competing formats for it, and they disagree on almost every structural detail that ends up mattering.
This post is a tour of those three formats. What they are, why there are three, and why the differences between them have quietly become one of the more annoying problems in AI infrastructure. If you build on models for a living, this is the map that explains why “I just changed the model and everything broke” keeps happening to people.
What a “wire format” even is
When your code talks to a model, it sends a chunk of JSON over HTTP and gets JSON back. The exact shape of that JSON, where the system prompt goes, how a tool call is represented, how the streamed response is chopped up, is the wire format. It’s the contract between your software and the provider.
One detail up front, because it shapes everything else: most of these APIs are stateless. The server doesn’t remember your conversation. Every single turn, your client resends the entire history from scratch: the system prompt, every prior message, every tool result. The model reprocesses all of it and appends its next move. That’s just how the current generation of these APIs works, and it’s the backdrop for the newest format’s big departure, which we’ll get to.
Three formats dominate right now, and they line up neatly with three eras of API design.
OpenAI Chat Completions is the oldest, from 2023. It’s built around a flat messages array, where each entry has a role (system, user, assistant, or tool) and some content. It’s stateless and simple.
Anthropic’s Messages API (the /v1/messages endpoint) is stateless too, but structurally richer. Instead of plain strings, a response comes back as an array of typed content blocks: a text block, an image block, a tool_use block, a thinking block. This is the format Claude Code speaks.
OpenAI’s Responses API is the newcomer, launched on March 11, 2025 (AI Wiki). It’s item-based, it can optionally keep your conversation state on the server, and it has tools that run inside OpenAI’s own infrastructure. This is what the Codex CLI speaks by default, and it’s the format OpenAI now recommends for anything new.
The important framing: these are not three versions of the same thing. They’re three genuinely different designs, built at different times with different assumptions baked in.
How Chat Completions became the language everyone speaks
Here’s the twist that makes the whole situation confusing. Even though there are three formats, one of them has quietly turned into a de facto standard that no standards body ever actually blessed. That’s Chat Completions.
When a new model provider launches, they almost always ship an “OpenAI-compatible” endpoint on day one. You point the official OpenAI SDK at their URL, and it works. The 2026 wave of open-weight model launches followed this pattern closely, shipping OpenAI-compatible APIs out of the gate (digitalapplied, 2026; CometAPI). One widely-cited figure claims north of 80 percent of new AI API providers ship OpenAI-SDK compatibility, though that number comes from a blog rather than a primary survey, so read it as directional rather than gospel.
Why did this one win? Because it’s dead simple and stateless. As one commenter on Hacker News put it, Chat Completions lets you “swap out providers with nothing more than a base url and a model id” (HN #44052947). That’s the whole appeal, and it’s real.
So the “just change the URL” wisdom isn’t wrong. It’s just narrower than people think. It’s true inside the Chat Completions dialect, among providers who all agreed to imitate the same 2023-era shape. Step outside that dialect, to Anthropic’s blocks or OpenAI’s own newer format, and the URL swap stops being enough.
Where the three formats disagree
If the formats only differed cosmetically, translating between them would be a weekend project. The problem is they disagree on the specific things that make agents work. Here are the ones that bite.
The system prompt lives in a different place in each one. In Chat Completions it’s a message with role: "system" at the top of the array. In Anthropic’s format it’s not a message at all; it’s a separate top-level system parameter sitting outside the messages. In Responses it’s yet another field, instructions, and newer OpenAI models even rename the role from system to developer. Same concept, three homes.
Tool calls are represented three different ways. This is the one that causes the most pain. When a model wants to call a tool, Chat Completions puts a tool_calls array on the assistant message, and you return the result as a separate message with role: "tool" that references a tool_call_id. Anthropic instead embeds a tool_use content block inside the assistant’s content, and you send the result back as a tool_result block nested inside a user message, referencing a tool_use_id. Responses treats each tool call as an item in its stream, and adds hosted tools that run server-side. The IDs and the nesting are different in all three, and when a gateway remaps them even slightly wrong, the agent loop doesn’t error loudly. It just silently stalls.
Streaming is three separate dialects of the same underlying technology. All three stream their responses using server-sent events, but the events themselves don’t match. Anthropic sends named, typed events: message_start, content_block_start, content_block_delta (with subtypes like text_delta, input_json_delta, and thinking_delta), then content_block_stop and message_stop (Anthropic streaming docs). Chat Completions sends a uniform stream of chat.completion.chunk objects, each carrying a small delta, ending with a finish_reason and a literal [DONE]. Responses sends semantic, item-oriented events like response.output_item.added and response.output_text.delta. Converting one live stream into another means holding state across events and repackaging on the fly.
A gateway vendor summed up the whole mess bluntly: the Anthropic and OpenAI protocols “overlap in shape but disagree on every detail that matters: tool calls live in different fields, system prompts go in different places, cache control means different things, and streaming event types don’t match. Every one of these mismatches causes silent failures or broken agent loops if the translation isn’t precise” (Future AGI, 2026).
Reasoning is the part that flat-out won’t translate
Everything above is annoying but solvable with careful engineering. Reasoning is different. Reasoning is the part where translation stops being hard and starts being impossible.
When a modern model “thinks” before answering, that thinking isn’t just extra text you can copy around. Anthropic’s format returns it as a thinking content block, and during tool use you’re required to pass the complete, unmodified thinking block, cryptographic signature and all, back on the next turn. Modify it and the request gets rejected (Anthropic extended thinking docs). OpenAI’s Responses API handles reasoning as its own item type, which can be encrypted: you get back a reasoning.encrypted_content blob you replay later without ever seeing inside it (OpenAI reasoning guide). Chat Completions, being older, has no first-class concept of reasoning at all; some providers bolt on a non-standard reasoning_content field, but there’s no agreement on it (LiteLLM).
Now put those together. A tool sitting between an Anthropic-format session and an OpenAI model cannot manufacture a valid signed thinking block, because it doesn’t hold Anthropic’s signing key. It cannot decrypt OpenAI’s reasoning to port it the other way, because that’s the whole point of encryption. The best it can do is forward a lossy summary and hope the destination model can pick up the thread.
This overturns a belief a lot of people quietly hold: that reasoning is just more tokens, and tokens move freely between providers. They don’t. Reasoning is signed, or encrypted, or both, and it’s meant to be preserved verbatim across turns within one family. Across families, it mostly can’t be. (I wrote about that specific wall in more detail in Switching Models Mid-Session Is Easy. Keeping the Reasoning Is the Hard Part.)
Statefulness, and the lock-in fight it started
The Responses API’s biggest departure is that it can be stateful. Set store: true, pass a previous_response_id, and OpenAI keeps your conversation history, your reasoning items, and your tool state on their servers. You stop resending everything every turn. That’s genuinely convenient, and it’s part of why Responses can be cheaper to run (Portkey, February 2026).
It also means your conversation now lives on OpenAI’s infrastructure, and that’s where the argument starts. On Hacker News, one developer noted that where Chat Completions lets you swap providers with a URL, Responses requires “data migration as well as replacement infrastructure,” adding that “it does seem to partially be a strategic moat-building move by OpenAI” (HN #44052947). The hosted tools deepen that coupling: an app that leans on the built-in web search or file search “cannot easily swap to another model provider without rewriting that orchestration” (AI Checker Hub, March 2026).
This isn’t theoretical. The Codex CLI dropped Chat Completions support entirely. The change was announced December 9, 2025 and completed February 1, 2026, forcing custom providers to switch their config from wire_api = "chat" to wire_api = "responses". A maintainer explained that “the chat/completions API has increasingly hampered our ability to improve Codex and deliver new features” and that “maintaining compatibility with this legacy protocol has added complexity, introduced regressions, and increased support overhead” (openai/codex Discussion #7782). The fallout landed on the wider ecosystem: tools like LM Studio and LiteLLM struggled to implement Responses correctly, and some users found themselves unable to migrate at all.
Two honest corrections before this reads as one-sided. First, a myth worth killing: OpenAI is not deprecating Chat Completions. Their own migration guide says plainly that “while Chat Completions remains supported, Responses is recommended for all new projects” (OpenAI). The API actually being retired is the older Assistants API, which sunsets August 26, 2026. Second, the “stateless” escape hatch from Responses (store: false plus replaying encrypted reasoning) isn’t airtight; there’s a filed issue showing reasoning items still getting stored in some zero-data-retention cases (openai-agents-python #2063). Even OpenAI’s own leadership acknowledged “way too much confusion” about the Responses API and posted a thread trying to clear it up (VentureBeat).
So what are you actually supposed to do?
Step back and look at the position most teams are in. Your coding agent or your product’s agent speaks one format. The cheapest capable model this week might speak another. The translation between them is precisely where things break silently, and the breakage clusters in the newest, most valuable features: reasoning, tool calls, streaming, state.
That leaves two unappealing options if you handle it yourself. You can freeze on the lowest common denominator, plain Chat Completions with no reasoning and no server-side state, and give up the frontier features to keep your portability. Or you can build and maintain a real translation layer, which means owning the tool-call remapping, the streaming re-packaging, the reasoning edge cases, and every silent-failure mode above. Plenty of gateways will route a request for you, but most stop at “pick a provider and forward it.” The hard part, the faithful translation across families, is the part they tend to skip.
This is the layer AJNT is built for. It collapses all three wire protocols, Anthropic Messages, OpenAI Chat Completions, and OpenAI Responses, into one internal pipeline, and it translates across families live: the reasoning semantics, the tool-call shapes, the streaming formats. A session opened in one format can be served by a model that natively speaks another, without changing your agent’s code. And because AJNT sits on the context window itself, compressing the history that these stateless formats resend on every turn, it’s operating right at the layer where the formats collide. That matters because the context window is the same thing Responses’ server-side state and Anthropic’s compaction are both reaching for from different directions.
To be honest about the boundary: translation can’t invent fidelity the source model never exposed. If a model hands over encrypted reasoning or a signed thinking block, no gateway can turn that into perfect reasoning for a different model family. A summary is a summary. What a good translation layer can do is handle the mechanical mismatches precisely, keep the agent loop from silently stalling, and make the cheap-model fallback actually work for the 80 percent that does translate, while being upfront about the 20 percent that doesn’t.
The takeaway
The lack of a standard here isn’t a temporary rough edge that gets sanded down next quarter. The incentives point the other way: the provider with the most capable models has real reasons to make its newest format sticky, and reasoning and state are sticky by design. As of July 2026, we have one old format that everyone imitates but that’s frozen in features, one richly-typed format from Anthropic, and one expressive-but-coupled format from OpenAI, with no sign of convergence.
For anyone building on models, the practical lesson is to treat the wire format as a real architectural decision rather than an implementation detail. Know which one your tools speak, know that the features you most want to use are the ones least likely to port, and plan for the translation instead of assuming a URL swap will cover you. It usually won’t.
← Back to Blog