Which OpenAI Client Methods the Aggregator's /chat/completions Route Actually Supports
A conceptual map of which OpenAI SDK client methods work against the aggregator's /chat/completions route, which features ride along inside that route, and how to avoid calls that silently no-op.
Why the method surface matters
The aggregator exposes an OpenAI-compatible /chat/completions route, so you can usually keep the official OpenAI SDK and just change baseurl and apikey. That compatibility is route-level, not SDK-level: the SDK ships many methods, but only the ones that map onto a supported HTTP endpoint will do anything meaningful. Calling an unsupported method can fail loudly, or worse, return something that looks empty and leaves you guessing.
A useful mental model: the SDK is a set of typed wrappers around HTTP paths. Your question is always "which path does this method hit, and does the aggregator implement that path?"
Methods that map onto /chat/completions
These are the client calls that resolve to the chat completions endpoint:
- Chat completions (non-streaming) —
client.chat.completions.create(...)withoutstream=True. - Chat completions (streaming) — the same call with
stream=True, returning a server-sent-event iterator of deltas. - Tool/function calling — the
toolsandtool_choiceparameters on the chat call, plus thetoolrole messages you send back. - Vision / image input — content parts of type
image_urlinside a user message, where the selected model accepts images. - Structured output requests —
response_formatwhere the model supports it (for example JSON mode or schema-constrained output). - Sampling and control parameters —
temperature,topp,maxtokens,stop,seed-style parameters, and penalty settings, subject to model support.
A key principle: tools, vision, and structured output are not separate routes. They are fields inside the chat completion request body. If the route accepts chat completions, these features are available to the extent the underlying model supports them. The aggregator passes them through; the model decides whether they mean anything.
Features that ride along with streaming
Streaming deserves its own note because teams often assume it is a separate method. It is the same method with a flag. Practical implications:
- You consume an iterator of chunks and assemble deltas yourself or with the SDK helper.
- Tool calls arrive as partial JSON fragments across chunks and must be concatenated before parsing.
- Usage figures may arrive at the end of the stream or require an explicit option, depending on the SDK and provider.
- Cancellation is client-side: closing the stream stops your consumption; it does not retroactively un-bill generated tokens.
The embeddings question
Embeddings are a different endpoint (/embeddings) and a different method (client.embeddings.create). Do not assume that because chat works, embeddings work. Treat embeddings as a separate capability to verify.
If embeddings are not part of the compatible route set you are using, the safe pattern is to compute embeddings elsewhere (a local model, or a provider you already use directly) and only use the aggregator for chat. Mixing the two is fine as long as the vector dimensions and model stay consistent across your index.
Signs a call silently no-opped
"Silent no-op" usually means one of these, not an actual empty success:
- The parameter was accepted by the SDK's type system but dropped by the upstream model, so you get a normal answer that ignores your instruction.
- A tool call never appears because the model chose not to call a tool; you must inspect
finish_reasonand the message content. - Streaming returned zero chunks because the request was rejected after the connection opened.
- A response format was ignored, and the model returned prose instead of the JSON you expected.
Defensive habits that catch all four:
- Log the raw response object, not just the parsed text.
- Assert on
finishreasonand on the presence oftoolcallswhen you require them. - Validate structured output with a schema and retry with a clearer prompt if it fails.
- Count streamed chunks in development and fail loudly on zero.
Matching models to features
Because the aggregator fronts many model families (Claude, GPT, DeepSeek, Qwen, GLM, Kimi, and others), feature support varies by model, not just by route. Before building on a capability:
- Confirm the model accepts image parts if you send them.
- Confirm tool calling is supported rather than emulated by prompt parsing.
- Confirm the context window fits your prompt plus expected output.
- Run a tiny probe request per model you depend on, and keep it in CI as a smoke test.
This is cheap insurance against a provider changing behavior under a stable model name.
A practical verification checklist
- Point the official SDK at the aggregator's base URL and authenticate with your key.
- Send a minimal chat completion and confirm a normal response.
- Repeat with
stream=Trueand confirm chunks arrive and terminate. - Send a tool definition and a prompt that should trigger it; confirm
tool_callsappear. - Send an image part to a vision-capable model and confirm it is described.
- Request a JSON response format and confirm parseable output.
- Verify embeddings separately, or keep them on another path.
Cost and access notes
Billing is per official model price multiplied by 1.3 for API users, paid in USDC on Base with no KYC. Contributors who help supply capacity are credited at official price × 1.1 (× 1.2 for premium) in USDC. Failed or malformed requests still consume tokens if the upstream model generated them, which is another reason to validate requests client-side before sending.
Bottom line
Treat /chat/completions as one route with a rich request body: chat, streaming, tools, vision, and structured output all travel through it, bounded by model support. Treat embeddings and any other endpoint as separate integrations to verify. The SDK's method names are not a promise about the aggregator's surface — the HTTP path is. Test the path, assert on the response shape, and you will not be surprised by a call that quietly does nothing.