feat(ai): add strictResponsesPairing for Azure OpenAI Responses API

Split OpenAICompat into OpenAICompletionsCompat and OpenAIResponsesCompat
for type-safe API-specific compat settings. Added strictResponsesPairing
option to suppress orphaned reasoning/tool calls on incomplete turns,
fixing 400 errors on Azure's Responses API which requires strict pairing.

Closes #768
This commit is contained in:
Mario Zechner
2026-01-18 20:15:26 +01:00
parent def9e4e9a9
commit d43930c818
17 changed files with 112 additions and 23 deletions

View File

@@ -15,7 +15,7 @@ import type {
Context,
Message,
Model,
OpenAICompat,
OpenAICompletionsCompat,
StopReason,
StreamFunction,
StreamOptions,
@@ -452,7 +452,7 @@ function maybeAddOpenRouterAnthropicCacheControl(
function convertMessages(
model: Model<"openai-completions">,
context: Context,
compat: Required<OpenAICompat>,
compat: Required<OpenAICompletionsCompat>,
): ChatCompletionMessageParam[] {
const params: ChatCompletionMessageParam[] = [];
@@ -681,9 +681,9 @@ function mapStopReason(reason: ChatCompletionChunk.Choice["finish_reason"]): Sto
/**
* Detect compatibility settings from provider and baseUrl for known providers.
* Provider takes precedence over URL-based detection since it's explicitly configured.
* Returns a fully resolved OpenAICompat object with all fields set.
* Returns a fully resolved OpenAICompletionsCompat object with all fields set.
*/
function detectCompat(model: Model<"openai-completions">): Required<OpenAICompat> {
function detectCompat(model: Model<"openai-completions">): Required<OpenAICompletionsCompat> {
const provider = model.provider;
const baseUrl = model.baseUrl;
@@ -725,7 +725,7 @@ function detectCompat(model: Model<"openai-completions">): Required<OpenAICompat
* Get resolved compatibility settings for a model.
* Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.
*/
function getCompat(model: Model<"openai-completions">): Required<OpenAICompat> {
function getCompat(model: Model<"openai-completions">): Required<OpenAICompletionsCompat> {
const detected = detectCompat(model);
if (!model.compat) return detected;