Skip to content
Model APIsMulti-provider abstraction

Senior · Core path · 7 chapters

Multi-provider abstraction

Gateways, routers, or a hand-rolled adapter

A provider seam is valuable only when it preserves deliberate escape hatches; otherwise it turns vendor change into silent feature loss.

Read these first

What you will know

  • Put a seam between your code and a specific provider

    A thin interface at the call site is enough; pushing every provider feature behind it creates an inflexible pseudo-standard.

  • Run the same request through two providers and document which hosted state, reasoning blocks, and provider-specific tools cannot be represented by the shared contract

    A normalized response can look valid while silently discarding continuation handles, control signals, or tool semantics.

  • Swap providers for one feature without touching business logic

    Provider selection and translation should stay at the integration boundary, leaving domain behavior independent of vendor names.

  • Measure the feature and quality loss caused by a lowest-common-denominator interface before adopting it

    Flattening streaming events, tool calls, or structured outputs may lower capability without causing compile-time or obvious runtime failures.

  • Decide when a gateway is better than an in-process adapter

    A gateway centralises keys, budgets, and logging for many services; an adapter is right for one.


Chapters

  1. 1

    The provider seam

    The boundary where code written in terms of your product ends and code written in terms of one vendor's API begins is the one place the question of which vendor gets answered — and how it is placed decides whether changing the answer is a config edit or a fortnight. This chapter contrasts a single Provider object selected by one environment variable with per-capability ports resolved at the composition root, gives a test for what belongs in a port, and separates independence of vendor names from independence of vendor behaviour.

  2. 2

    The size of the shared contract

    An interface that grew to fourteen methods because each vendor feature was given a shared equivalent charges rent on every capability it took responsibility for: adding one vendor's server-side search means editing the interface, all three implementations, the fake and both call sites. This chapter measures that cost, contrasts it with the ratified standards it resembles, and gives two questions that decide what belongs in a shared shape and what belongs inside one adapter.

  3. 3

    Losses in a normalized response

    Flattening a provider's reply to {text, tool_calls, usage} discards whatever has no field, and a field that does not exist cannot fail to be filled. Reasoning blocks vanish when the adapter rebuilds the next turn, a server-held conversation id is dropped so every turn resends the whole transcript, and tool-call semantics change meaning while keeping their names. This chapter traces each loss to the symptom it produces and the dashboard it produces it on, and explains why a shared conformance suite is green throughout.

  4. 4

    Adapters and gateways

    The translation code inside a gateway is the same code you would write in an adapter; what moving it out of your process changes is ownership — its own uptime, schema, release cadence and pager, and the ability to be down while every provider it fronts is healthy. This chapter prices what centralising keys, budgets, quota and audit logs actually buys against the number of services sharing them, works the availability arithmetic, and names the configuration that keeps a new failure domain from becoming an outage.

  5. 5

    Hosted routers and ownership

    A hosted router carries every cost of an out-of-process hop — its own uptime, schema and release cadence — on a service nobody at your company can page, patch or roll back, and it puts a second party between you and the vendor's error semantics, rate limits and quota accounting. This chapter works through what an on-call engineer can and cannot do when a router misbehaves, why the direct fallback decays unless it carries real traffic, and the workloads a router is genuinely the right answer for.

  6. 6

    Measuring the capability loss

    \"Supported\" in a compatibility matrix is a claim about a request being accepted, not about extended thinking surviving the round trip or a cache breakpoint landing where you placed it. This chapter separates four things the word can mean, then measures the difference: replay a few hundred production requests through both paths, aggregate the field-by-field diff, convert the lines that matter into currency, and run the evaluation set on each — a day of work that produces the number a compatibility matrix cannot.

  7. 7

    Documented escape hatches

    Adding a method to the shared interface and throwing NotImplemented in two implementations converts a compile-time fact into a production crash on the day a failover routes traffic to the wrong vendor. This chapter handles the vendor-specific capability by handing back the raw provider client as its own injected type, documented in an architecture decision record, shows how to price the swap that hatch commits you to, and gives the CI check that distinguishes a real hatch from a port that is missing a parameter.

External resources