diff --git a/src/mcplocal/src/proxymodel/plugins/gate.ts b/src/mcplocal/src/proxymodel/plugins/gate.ts index 78ef5d9..eafd54e 100644 --- a/src/mcplocal/src/proxymodel/plugins/gate.ts +++ b/src/mcplocal/src/proxymodel/plugins/gate.ts @@ -21,6 +21,26 @@ import { withTimeout, TimeoutError } from '../../util/with-timeout.js'; * begin_session — on timeout we fall back to deterministic tag matching. */ const GATE_LLM_TIMEOUT_MS = Number(process.env['MCPCTL_GATE_LLM_TIMEOUT_MS'] ?? '8000'); +/** + * Extra request fields for the gate's server-Llm selection call. Prompt + * selection is mechanical classification that gains nothing from chain-of- + * thought, so we ask reasoning models to skip thinking (they otherwise burn the + * whole budget reasoning and blow the gate timeout). Sent verbatim by mcpd's + * passthrough adapter → litellm/vLLM. Harmless for models that ignore them, and + * if a backend rejects them the selector falls back to the local provider. + * - `chat_template_kwargs.enable_thinking:false` — Qwen3 hard-off. + * - `reasoning_effort:'low'` — OpenAI o-series / newer vLLM. + * Override with a JSON object in MCPCTL_GATE_SELECT_EXTRA_BODY, or '' to disable. + */ +const GATE_SELECT_EXTRA_BODY: Record = (() => { + const raw = process.env['MCPCTL_GATE_SELECT_EXTRA_BODY']; + if (raw === '') return {}; + if (raw !== undefined) { + try { return JSON.parse(raw) as Record; } catch { /* use default */ } + } + return { chat_template_kwargs: { enable_thinking: false }, reasoning_effort: 'low' }; +})(); + export interface GatePluginConfig { gated?: boolean; providerRegistry?: ProviderRegistry | null; @@ -308,6 +328,7 @@ async function handleBeginSession( temperature: o.temperature, max_tokens: o.maxTokens, stream: false, + ...GATE_SELECT_EXTRA_BODY, // ask reasoning models for a fast, no-think answer }); return pickCompletionText(resp); }