diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 65478df6..8f24f4d3 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed OpenAI-compatible provider feature detection to use `model.provider` in addition to URL, allowing custom base URLs (e.g., proxies) to work correctly with provider-specific settings ([#774](https://github.com/badlogic/pi-mono/issues/774)) + ## [0.47.0] - 2026-01-16 ### Fixed diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts index 3edeca45..d194d7ab 100644 --- a/packages/ai/src/providers/openai-completions.ts +++ b/packages/ai/src/providers/openai-completions.ts @@ -679,25 +679,33 @@ function mapStopReason(reason: ChatCompletionChunk.Choice["finish_reason"]): Sto } /** - * Detect compatibility settings from baseUrl for known providers. + * 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. */ -function detectCompatFromUrl(baseUrl: string): Required { - const isZai = baseUrl.includes("api.z.ai"); +function detectCompat(model: Model<"openai-completions">): Required { + const provider = model.provider; + const baseUrl = model.baseUrl; + + const isZai = provider === "zai" || baseUrl.includes("api.z.ai"); const isNonStandard = + provider === "cerebras" || baseUrl.includes("cerebras.ai") || + provider === "xai" || baseUrl.includes("api.x.ai") || + provider === "mistral" || baseUrl.includes("mistral.ai") || baseUrl.includes("chutes.ai") || isZai || + provider === "opencode" || baseUrl.includes("opencode.ai"); - const useMaxTokens = baseUrl.includes("mistral.ai") || baseUrl.includes("chutes.ai"); + const useMaxTokens = provider === "mistral" || baseUrl.includes("mistral.ai") || baseUrl.includes("chutes.ai"); - const isGrok = baseUrl.includes("api.x.ai"); + const isGrok = provider === "xai" || baseUrl.includes("api.x.ai"); - const isMistral = baseUrl.includes("mistral.ai"); + const isMistral = provider === "mistral" || baseUrl.includes("mistral.ai"); return { supportsStore: !isNonStandard, @@ -715,10 +723,10 @@ function detectCompatFromUrl(baseUrl: string): Required { /** * Get resolved compatibility settings for a model. - * Uses explicit model.compat if provided, otherwise auto-detects from URL. + * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL. */ function getCompat(model: Model<"openai-completions">): Required { - const detected = detectCompatFromUrl(model.baseUrl); + const detected = detectCompat(model); if (!model.compat) return detected; return {