The one-line answer: build your agent against the Chat Completions message shape for everything you want to keep portable, and reach for the Responses API only where you actually use its OpenAI-native, stateful features — because this week proved the format is going cross-vendor, but the statefulness is not.

Two months ago the advice on this site was clean: Chat Completions for portability, the Responses API for OpenAI-native agents. The Responses API was the surface you adopted when you'd decided to live inside OpenAI. That framing just started to bend — and if you build agents for a living, the bend is worth understanding before you pick your next API.

1. What actually happened this week#

Two small releases, one big signal.

Add the fact that Pydantic AI v2 already defaults to the Responses API (docs), and a pattern comes into focus: the Responses API's typed item model — messages, reasoning items, tool-call items — is quietly becoming a convention that things other than OpenAI now emit and consume.

2. Why this inverts the old advice#

The reason "Chat Completions for portability" was true is that Chat Completions is the format everyone copied. Every OpenAI-compatible provider — DeepSeek, most open-weight hosts — implements it, so code written against it moves for free.

The Responses API was the opposite: a newer, richer, OpenAI-only surface. Adopting it meant accepting lock-in in exchange for hosted tools and server-held state.

What DeepSeek did is copy the shape of the Responses API too — the item model, the reasoning-item placement. So the clean "portable vs proprietary" split no longer maps neatly onto "Chat Completions vs Responses." The format is converging on both.

The thing that's standardizing isn't an API you call. It's a way of shaping input and output — typed items, a reasoning item before the message item — that more than one vendor now agrees on.

3. The catch: the portability is shallow#

Here is the part that saves you a rewrite. Not all of the Responses API travels.

Two capabilities are the actual reason to use it, and neither is portable:

  1. Server-side conversation statestore: true plus previous_response_id. OpenAI holds your conversation and you chain turns by ID instead of resending history (OpenAI). DeepSeek and others don't host your threads. This does not move.
  2. Hosted built-in tools — web search, file search, code interpreter, computer use, remote MCP. These run on OpenAI's side. Copy the item shape all you like; the tools themselves are OpenAI's.

So the Responses API splits in two: a portable item format that's becoming a cross-vendor standard, and a proprietary state-and-tools layer that is exactly as locked-in as it always was. The mistake is treating "we're on the Responses API" as one decision. It's two.

4. What to build against#

The rule that survives all of this:

Keep your own state, pass full history each turn, and put the model behind one variable. Do that and your agent runs unchanged across OpenAI and DeepSeek — because both speak the OpenAI SDK — and a vendor swap is two lines:

from openai import OpenAI

# OpenAI (GPT-5.6 Luna) — the default
client = OpenAI()  # base_url defaults to OpenAI
MODEL = "gpt-5.6-luna"

# DeepSeek V4 Flash — same SDK, two changes
client = OpenAI(base_url="https://api.deepseek.com/v1")
MODEL = "deepseek-v4-flash"

# ...everything below is identical for both
messages = load_history()            # YOUR store, not the provider's
messages.append({"role": "user", "content": user_input})
resp = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
save_history(messages + [resp.choices[0].message])

Because you own load_history/save_history, you never touch previous_response_id, and the workload follows the price war instead of the vendor. When OpenAI cuts a tier 80% overnight (as it did July 30) or DeepSeek open-weights a million-token model under MIT (July 31), you move by changing two lines, not by rewriting an agent.

Reach for the Responses API deliberately when — and only when — you want the thing it uniquely gives you:

Everything else — the typed items, the reasoning-item-before-message ordering — you can now adopt as a portable convention, because DeepSeek and others emit it too. Write one parser: read the message item, log the reasoning item, merge nothing.

The through-line#

For most of the last two years, "which API" was a proxy for "which vendor." That's ending. The wire format is converging on the Responses item model, and a Chinese frontier model copying OpenAI's reasoning-item layout is the clearest sign yet. But convergence at the format layer doesn't mean convergence at the state layer — and that gap is where lock-in still hides. Build against the shape, keep your state, and the next 80% price cut is a two-line change instead of a bad week.