Skip to content

fix(js/plugins/compat-oai): keep provider baseURL on request-scoped clients; expose DeepSeek reasoning config - #6056

Open
AnasMK9 wants to merge 1 commit into
genkit-ai:mainfrom
AnasMK9:fix/compat-oai-request-scoped-baseurl
Open

fix(js/plugins/compat-oai): keep provider baseURL on request-scoped clients; expose DeepSeek reasoning config#6056
AnasMK9 wants to merge 1 commit into
genkit-ai:mainfrom
AnasMK9:fix/compat-oai-request-scoped-baseurl

Conversation

@AnasMK9

@AnasMK9 AnasMK9 commented Aug 14, 2026

Copy link
Copy Markdown

Bug 1: per-call config.apiKey sends DeepSeek/xAI requests (and the key) to api.openai.com

Request-scoped clients — created when a call supplies config.apiKey — are rebuilt from the pluginOptions object, which deepSeekPlugin and xAIPlugin (identical code pattern) passed without baseURL:

const pluginOptions = { name: 'deepseek', ...options }; // no baseURL

The rebuilt client therefore fell back to the OpenAI SDK default, so the request — carrying the caller's DeepSeek/xAI API key — was sent to https://api.openai.com. Besides failing, this leaks the provider key to a third party.

Fix, two layers:

  1. Both affected plugins now derive the openAICompatible arguments and pluginOptions from one object that always carries the provider baseURL, so the two can't drift. DEEPSEEK_BASE_URL / XAI_BASE_URL are exported and used by the regression test.
  2. maybeCreateRequestScopedOpenAIClient is hardened to inherit the default client's baseURL when pluginOptions omit it — a request-scoped client can never silently point at a different host than the client it derives from, closing this bug class for future plugins too.

Tests: request_scoped_client_test.ts drives the real plugins with a recording fetch (without the fix: https://api.openai.com/v1/chat/completions; with it: the provider host), and utils_test.ts covers the client-rebuild guard directly. Also verified live against the real DeepSeek API: plugin constructed with a bogus key, real key on config.apiKey, request succeeds against api.deepseek.com.

Bug 2: DeepSeek config schema has no reasoning controls

The response side already surfaces reasoning_content, but DeepSeekChatCompletionConfigSchema exposed no way to control it. This adds reasoningEffort and thinking to the schema and request builder, with .describe() docs surfaced in the Dev UI.

DeepSeek's own docs contradict each other on where reasoning_effort lives (API reference says nested under thinking, reasoning guide says top-level), so the enums were verified against the API's request validation, empirically:

  • reasoning_effort (top-level): none | minimal | low | medium | high | xhigh | max — nested inside thinking it is silently ignored
  • thinking.type: adaptive | enabled | disabled

The extra fields are typed via a schema-inferred interface and applied with a satisfies-checked Object.assign — no any casts (per review feedback). Validated live: reasoningEffort scales reasoning token usage; thinking: { type: 'disabled' } yields no reasoning content.

Checklist

  • PR title is following https://www.conventionalcommits.org/en/v1.0.0/
  • Tested: 7 new unit tests (104 total pass in compat-oai), plus live validation against the real DeepSeek and OpenAI APIs
  • Docs updated: new config fields carry .describe() documentation (Dev UI); the genkit.dev DeepSeek integration page lives outside this repo and can be updated once this merges

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for reasoningEffort and thinking configurations in the DeepSeek plugin, and ensures that request-scoped clients with per-call API keys retain their provider-specific base URLs (DeepSeek and xAI) instead of falling back to OpenAI. A new test suite has been added to verify this behavior. Feedback highlights a potential TypeScript compilation error when assigning reasoning_effort directly to params and suggests casting params to any to support DeepSeek's custom enum values.

Comment thread js/plugins/compat-oai/src/deepseek/deepseek.ts Outdated
@AnasMK9
AnasMK9 force-pushed the fix/compat-oai-request-scoped-baseurl branch from d854d5a to 9a9fadf Compare August 14, 2026 03:02
…lients; expose DeepSeek reasoning config

Request-scoped clients (created when a call supplies config.apiKey) are
rebuilt from pluginOptions, which the DeepSeek and xAI plugins passed
without baseURL — so those requests, carrying the caller's provider API
key, were sent to the OpenAI SDK default, api.openai.com. Fix the two
plugins to derive plugin arguments and pluginOptions from one object that
always carries the provider baseURL, and harden
maybeCreateRequestScopedOpenAIClient so a request-scoped client can never
point at a different host than the default client it derives from.

Also add reasoningEffort and thinking to the DeepSeek config schema and
request builder (the response side already surfaces reasoning_content).
Enum values verified against the DeepSeek API's request validation:
reasoning_effort is a top-level field accepting
none|minimal|low|medium|high|xhigh|max; thinking.type accepts
adaptive|enabled|disabled. The extra fields are typed via a
schema-inferred interface and applied with a satisfies-checked
Object.assign — no any casts.

Tested: new regression tests drive the real plugins with a recording
fetch (without the fix the request URL is api.openai.com), plus unit
tests on the client rebuild; validated live against the DeepSeek and
OpenAI APIs.
@AnasMK9
AnasMK9 force-pushed the fix/compat-oai-request-scoped-baseurl branch from 9a9fadf to df9053d Compare August 14, 2026 03:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant