feat: sideQuery 支持第三方 provider 路由 (OpenAI/Grok/Gemini)
- 新增 getProviderPrimaryModel() 从环境变量解析 provider 主模型 - getDefaultOpus/Sonnet/HaikuModel 在第三方 provider 下回退到用户配置的主模型 - sideQuery 根据 provider 类型分发到对应的 API 适配器 - 新增 sideQueryViaOpenAICompatible (OpenAI + Grok) 和 sideQueryViaGemini 适配函数 - 避免 sideQuery 后台任务在配置第三方端点时仍请求 Anthropic API
This commit is contained in:
parent
b9fcd991cc
commit
9ae258f917
|
|
@ -123,6 +123,19 @@ export function getBestModel(): ModelName {
|
|||
return getDefaultOpusModel()
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the provider's primary model from its env var (e.g. OPENAI_MODEL).
|
||||
* Returns undefined for providers that don't have a primary-model env var
|
||||
* (Bedrock, Vertex, Foundry, firstParty).
|
||||
*/
|
||||
function getProviderPrimaryModel(): ModelName | undefined {
|
||||
const provider = getAPIProvider()
|
||||
if (provider === 'openai') return process.env.OPENAI_MODEL
|
||||
if (provider === 'gemini') return process.env.GEMINI_MODEL
|
||||
if (provider === 'grok') return process.env.GROK_MODEL
|
||||
return undefined
|
||||
}
|
||||
|
||||
// @[MODEL LAUNCH]: Update the default Opus model (3P providers may lag so keep defaults unchanged).
|
||||
export function getDefaultOpusModel(): ModelName {
|
||||
const provider = getAPIProvider()
|
||||
|
|
@ -138,10 +151,15 @@ export function getDefaultOpusModel(): ModelName {
|
|||
if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL) {
|
||||
return process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
}
|
||||
// Fall back to user's configured model — custom providers may not
|
||||
// recognize hardcoded Anthropic model IDs.
|
||||
// Skip if the user setting is a model alias (e.g. "opus", "opus[1m]") to
|
||||
// avoid infinite recursion: parseUserSpecifiedModel(alias) → getDefaultOpusModel().
|
||||
// 3P providers: if user set a primary model (e.g. OPENAI_MODEL=glm-5.1),
|
||||
// fall back to it instead of a hardcoded Anthropic model. This prevents
|
||||
// sideQuery / background tasks from sending requests to Anthropic's API
|
||||
// when the user configured a third-party provider.
|
||||
const primaryModel = getProviderPrimaryModel()
|
||||
if (primaryModel) return primaryModel
|
||||
// Fall back to user's configured model — custom providers may not recognize
|
||||
// hardcoded Anthropic model IDs. Skip aliases to avoid infinite recursion:
|
||||
// parseUserSpecifiedModel(alias) → getDefaultOpusModel().
|
||||
const userSpecifiedOpus = getUserSpecifiedModelSetting()
|
||||
if (userSpecifiedOpus && !isAliasOrAliasWithSuffix(userSpecifiedOpus)) {
|
||||
return parseUserSpecifiedModel(userSpecifiedOpus)
|
||||
|
|
@ -170,9 +188,12 @@ export function getDefaultSonnetModel(): ModelName {
|
|||
if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL) {
|
||||
return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
}
|
||||
// Fall back to user's configured model (ANTHROPIC_MODEL / settings) —
|
||||
// custom providers (proxies, national clouds) may not recognize the
|
||||
// hardcoded Anthropic model IDs.
|
||||
// 3P providers: fall back to user's primary model instead of a hardcoded
|
||||
// Anthropic model name. Prevents background API calls from being routed to
|
||||
// Anthropic when the user configured a third-party endpoint.
|
||||
const primaryModel = getProviderPrimaryModel()
|
||||
if (primaryModel) return primaryModel
|
||||
// Fall back to user's configured model (ANTHROPIC_MODEL / settings).
|
||||
// Skip if the user setting is a model alias to avoid infinite recursion.
|
||||
const userSpecified = getUserSpecifiedModelSetting()
|
||||
if (userSpecified && !isAliasOrAliasWithSuffix(userSpecified)) {
|
||||
|
|
@ -200,9 +221,12 @@ export function getDefaultHaikuModel(): ModelName {
|
|||
if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
|
||||
return process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
}
|
||||
// Fall back to user's configured model — custom providers may not
|
||||
// recognize hardcoded Anthropic model IDs.
|
||||
// Skip if the user setting is a model alias to avoid infinite recursion.
|
||||
// 3P providers: fall back to user's primary model instead of a hardcoded
|
||||
// Anthropic model name.
|
||||
const primaryModel = getProviderPrimaryModel()
|
||||
if (primaryModel) return primaryModel
|
||||
// Fall back to user's configured model — custom providers may not recognize
|
||||
// hardcoded Anthropic model IDs. Skip aliases to avoid infinite recursion.
|
||||
const userSpecifiedHaiku = getUserSpecifiedModelSetting()
|
||||
if (userSpecifiedHaiku && !isAliasOrAliasWithSuffix(userSpecifiedHaiku)) {
|
||||
return parseUserSpecifiedModel(userSpecifiedHaiku)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import { normalizeModelStringForAPI } from './model/model.js'
|
|||
import { getAPIProvider } from './model/providers.js'
|
||||
import { getOpenAIClient } from '../services/api/openai/client.js'
|
||||
import { getGrokClient } from '../services/api/grok/client.js'
|
||||
import { anthropicMessagesToOpenAI } from '../services/api/openai/convertMessages.js'
|
||||
import { resolveOpenAIModel } from '../services/api/openai/modelMapping.js'
|
||||
import { resolveGrokModel } from '../services/api/grok/modelMapping.js'
|
||||
import {
|
||||
|
|
@ -222,10 +221,9 @@ async function sideQueryViaOpenAICompatible(
|
|||
if (openaiToolChoice) requestParams.tool_choice = openaiToolChoice
|
||||
}
|
||||
|
||||
const response = await client.chat.completions.create(
|
||||
requestParams as any,
|
||||
{ signal },
|
||||
)
|
||||
const response = await client.chat.completions.create(requestParams as any, {
|
||||
signal,
|
||||
})
|
||||
|
||||
const choice = response.choices[0]
|
||||
const message = choice?.message
|
||||
|
|
@ -303,9 +301,14 @@ async function sideQueryViaOpenAICompatible(
|
|||
* Use this instead of direct client.beta.messages.create() calls to ensure
|
||||
* proper OAuth token validation with fingerprint attribution headers.
|
||||
*
|
||||
* Third-party provider routing (OpenAI, Grok, Gemini) is handled transparently —
|
||||
* when the user configures a third-party provider, sideQuery automatically
|
||||
* routes to the correct API adapter instead of sending requests to Anthropic.
|
||||
* This handles:
|
||||
* - Fingerprint computation for OAuth validation
|
||||
* - Attribution header injection
|
||||
* - CLI system prompt prefix
|
||||
* - Proper betas for the model
|
||||
* - API metadata
|
||||
* - Model string normalization (strips [1m] suffix for API)
|
||||
* - Third-party provider routing (OpenAI, Grok, Gemini)
|
||||
*
|
||||
* @example
|
||||
* // Permission explainer
|
||||
|
|
@ -603,7 +606,8 @@ async function sideQueryViaGemini(
|
|||
const body: Record<string, unknown> = {
|
||||
contents,
|
||||
...(systemInstruction && { systemInstruction }),
|
||||
...(geminiTools && (geminiTools as unknown[]).length > 0 && { tools: geminiTools }),
|
||||
...(geminiTools &&
|
||||
(geminiTools as unknown[]).length > 0 && { tools: geminiTools }),
|
||||
...(geminiToolConfig && {
|
||||
toolConfig: { functionCallingConfig: geminiToolConfig },
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user