Skip to content

Parity gaps, shims and legacy endpoints

What to do when the target provider cannot do what the source could, and how to leave a completions-era API behind.

A migration between two model providers is rarely blocked by the part everybody plans for. Renaming max_tokens, moving the system prompt out of the message array, rewriting a response path — that work is mechanical, and an afternoon finds all of it. What stops the migration is the capability on the old provider that the new one does not have at all: no grammar-constrained JSON, one tool call per turn instead of several, no log probabilities, no seed. There is no field to rename, because there is no field.

These pages are about that residue. Each takes one concept — structured output, parallel tool calls, sampling parameters, tool-call history, image input, a fine-tuning file — and works through how each API expresses it, what does not survive the translation, and what you build to cover the part that does not. The shims here are real code with named failure modes, because a shim you cannot see the edges of is worse than the gap it hides.

Feature Parity Gaps Between Providers, and How to Shim Them

The capabilities that exist on one provider and not another, which of them can be approximated in client code, and which cannot be approximated at all.

10 min read

Shimming Structured Output When a Provider Has No Native Support

A prompt-plus-validation shim that approximates schema-constrained output on a provider that has none, with the extraction, repair and truncation handling that make it survive contact with real replies.

11 min read

Shimming Parallel Tool Calls on a Provider That Only Allows One

A client-side loop that serialises what would have been concurrent tool invocations, keeping the caller's interface intact, and the semantics it quietly changes.

11 min read

Exporting a Fine-Tuning Dataset Between Provider Formats

Converting a training file between the prompt/completion and messages-array JSONL shapes, including the separator and whitespace conventions that carry meaning and do not convert.

10 min read

What Changes in Your Prompts When You Move From Completion to Chat

How a legacy text-completion prompt is rewritten as a message array, and which parts of the old framing actively hurt once roles exist.

10 min read

Migrating From a Legacy Completions Endpoint

The errors a deprecated completions endpoint produces, and the mechanical rewrite from a prompt-string call to a messages-based one including the response paths.

10 min read

Mapping Temperature and Sampling Parameters Between APIs

Where each sampling parameter lives in each API shape, which ranges differ, and why rescaling a temperature between two scales is not a translation.

10 min read

Fixing "temperature must be between 0 and 1" After Switching Providers

Why a temperature that worked on one provider is rejected by another, how to read the validation error, and where the fix belongs so it does not recur.

9 min read

Mapping Multi-Turn Tool-Call Sequences Between APIs

One assistant-calls-tool-then-answers exchange written out in each API's history shape, and the correlation and role differences that make a naive replay drop turns.

11 min read

Mapping Image and File Inputs Between Chat APIs

How an image is attached to a message in each API shape, why base64 is the only portable floor, and what the request-size and token-accounting differences cost you.

10 min read

Mapping Response ID and Request Metadata Fields Between APIs

Which field carries the response id, the model identifier and the token counts on each major API shape, and which pieces of metadata have no counterpart at all.

9 min read

Rewriting a LangChain Prompt Template for a Different Provider

Why a PromptTemplate that worked against one chat model raises a formatting or message-ordering error after the LLM wrapper is swapped, and the specific rewrite that fixes it.

9 min read

Migrating a LangChain Agent to a Different Tool-Calling Provider

Why a LangChain agent stops choosing the right tool after the underlying model is swapped, separated into the constructor that no longer applies and the tool-selection behaviour that genuinely changed.

10 min read

Migrating LlamaIndex From GPTSimpleVectorIndex to VectorStoreIndex

Rewrites an old LlamaIndex build against the current VectorStoreIndex API, including the import path change, the query call that moved, and the persisted index that cannot be loaded.

9 min read

Migrating a Vercel AI SDK Route From the Pages Router to App Router

Rewrites a working Pages Router API route that streams a model response as an App Router route handler, including the response-construction change that is the whole migration.

9 min read

Fixing “AI_APICallError” After a Vercel AI SDK Upgrade

What the AI_APICallError class actually carries, how to read the upstream response out of it, and the specific upgrade changes that turn a working call into a 400.

9 min read

Moving From LangChain’s OpenAI Wrapper to the Native SDK

Rewrites a LangChain-wrapped chat call as a direct SDK call, naming exactly which conveniences you lose and what each one costs to reimplement.

10 min read

What an OpenAI-Compatible Endpoint Does With Unsupported Parameters

The three things a compatible endpoint can do with a parameter it does not implement — reject it, ignore it, or accept it and do nothing — and why the silent one is the failure that reaches production.

10 min read

Why an OpenAI-Compatible Streaming Response Can Break a Parser Built for OpenAI

Traces a streaming parser that works against OpenAI and crashes against a compatible endpoint to a specific framing, chunk-shape or terminator difference, and gives a parser that tolerates all of them.

10 min read

Other topics