ConcurredConcurred API
Gateway API

Provider Compatibility

Per-provider matrix for tool use, parallel calls, streaming, and prompt caching

The Gateway normalizes every provider to OpenAI chat-completions semantics. This page covers what each provider does natively and which quirks the Gateway hides.

Tool-use matrix

ProviderTool useParallel callsStreaming deltasstrict:trueForced tool_choicePrompt cachingKnown quirks
Anthropic Claude✅ arg-by-arg✅ server-side validation"required" + namedephemeraltoolu_XXX IDs are prefixed with call_ by the Gateway for OpenAI-client compatibility.
Google Gemini✅ whole-object (args don't chunk)✅ server-side validation"required" + namedJSON schemas are sanitized before forwarding: additionalProperties, $ref, $schema, $defs, strict, and similar draft-meta keywords are dropped with a warning. IDs are synthesized as call_<uuid>. A thinkingBudget cap is applied to prevent reasoning tokens from eating the output budget.
OpenAI✅ arg-by-arg✅ passthrough"required" + named (passthrough)✅ automatic (>1024 tok)Passthrough.
xAI Grok✅ arg-by-arg✅ server-side validation"required" + namedPassthrough via OpenAI-compat endpoint.
DeepSeek (chat)✅ arg-by-arg✅ server-side validation"required" + nameddeepseek-reasoner / deepseek-r1 do not support tools — returns tool_unsupported_for_model. Use deepseek-chat.
Mistral✅ arg-by-arg✅ server-side validation"required" + namedPassthrough.
Kimi (Moonshot)provider-dependent✅ server-side validation"required" + namedVia OpenRouter.
Llama (Meta)provider-dependent✅ server-side validationprovider-dependentVia OpenRouter. Tool support varies per Llama variant.
MiniMax (M2.7)✅ server-side validation"required" + namedMiniMax's hosted API is OpenAI-compatible including tools / tool_choice / tool_calls. The model serves XML-format tool calls internally but the wire format is standard OpenAI.

Reasoning models and tool use

ModelTools allowed?
gpt-5.2 (OpenAI o-series derivative)
claude-opus-4-*
grok-4-1-fast-reasoning
deepseek-reasoner / deepseek-r1❌ — rejected with tool_unsupported_for_model.

JSON Schema subset

The Gateway validates parameters as a JSON Schema Draft 2020-12 subset with type:"object" at the root. Supported keywords:

  • type, properties, required, description, enum
  • items, minItems, maxItems
  • oneOf, anyOf, allOf
  • pattern, minLength, maxLength
  • minimum, maximum
  • format (validation is lenient: uuid, date, date-time checked loosely)
  • additionalProperties (Claude/OpenAI/Grok/DeepSeek/Mistral; dropped for Gemini)

When a keyword isn't supported by the target provider, the Gateway either drops it with a warning (Gemini) or validates server-side.

Fallback behavior with tool use

When you pass fallback: ["gpt", "gemini"], the Gateway will try fallback providers only before any tool-call delta has been emitted. Once a tool call has streamed, no mid-stream failover is attempted — tool-call IDs and schemas wouldn't align across providers.

{
  "model": "claude",
  "fallback": ["gpt", "gemini"],
  "tools": [ /* ... */ ]
}
  • Anthropic 529 before any delta → try gpt.
  • Anthropic connection drop after first tool-call delta → surface tool_provider_error + [DONE].

Guardrails with tool use

Guardrails run on assistant text content only. Tool-call arguments are skipped — they're structured JSON often containing emails, UUIDs, IDs, and search terms that would false-positive against PII rules.

Token usage and cached tokens

The Gateway normalizes usage reporting:

  • prompt_tokens counts input tokens including cached-hit tokens, following OpenAI convention. It does not include cache-creation tokens (the first-write turn on Anthropic ephemeral).
  • completion_tokens counts the assistant output, including tool_calls arguments.
  • prompt_tokens_details.cached_tokens is populated for Anthropic (cache_read_input_tokens) and OpenAI (native cached_tokens). Other providers report 0.

tool_choice shapes

Every provider above accepts the two OpenAI-style forced shapes:

// Force *some* tool to be called — model picks which one
"tool_choice": "required"
 
// Force a *specific* tool by name — must match one of tools[].function.name
"tool_choice": { "type": "function", "function": { "name": "search_code" } }

A bad name in the named shape returns tool_choice_invalid.

See also

On this page