mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-08-24 10:14:19 -05:00
fix(nvidia-nim): enable reasoning template kwargs (#1893)
* fix(nvidia-nim): enable reasoning template kwargs * fix(nim): preserve explicit provider selections * fix(nim): limit env-only startup precedence
This commit is contained in:
@@ -7993,6 +7993,81 @@ test('DeepSeek sends thinking toggle and normalized reasoning effort', async ()
|
||||
expect(requestBody?.store).toBeUndefined()
|
||||
})
|
||||
|
||||
test('NVIDIA NIM DeepSeek sends chat template thinking kwargs', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://integrate.api.nvidia.com/v1'
|
||||
process.env.NVIDIA_API_KEY = 'nvapi-test'
|
||||
|
||||
let requestBody: Record<string, unknown> | undefined
|
||||
globalThis.fetch = (async (_input, init) => {
|
||||
requestBody = JSON.parse(String(init?.body))
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 'chatcmpl-1',
|
||||
model: 'deepseek-ai/deepseek-v4-pro',
|
||||
choices: [
|
||||
{ message: { role: 'assistant', content: 'ok' }, finish_reason: 'stop' },
|
||||
],
|
||||
usage: { prompt_tokens: 3, completion_tokens: 1, total_tokens: 4 },
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } },
|
||||
)
|
||||
}) as unknown as FetchType
|
||||
|
||||
const client = createOpenAIShimClient({
|
||||
reasoningEffort: 'xhigh',
|
||||
}) as OpenAIShimClient
|
||||
await client.beta.messages.create({
|
||||
model: 'deepseek-ai/deepseek-v4-pro',
|
||||
system: 'test',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
max_tokens: 64,
|
||||
stream: false,
|
||||
thinking: { type: 'enabled' },
|
||||
})
|
||||
|
||||
expect(requestBody?.thinking).toEqual({ type: 'enabled' })
|
||||
expect(requestBody?.reasoning_effort).toBe('max')
|
||||
expect(requestBody?.chat_template_kwargs).toEqual({
|
||||
thinking: true,
|
||||
enable_thinking: true,
|
||||
})
|
||||
})
|
||||
|
||||
test('NVIDIA NIM DeepSeek omits chat template thinking kwargs when thinking is disabled', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://integrate.api.nvidia.com/v1'
|
||||
process.env.NVIDIA_API_KEY = 'nvapi-test'
|
||||
|
||||
let requestBody: Record<string, unknown> | undefined
|
||||
globalThis.fetch = (async (_input, init) => {
|
||||
requestBody = JSON.parse(String(init?.body))
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 'chatcmpl-1',
|
||||
model: 'deepseek-ai/deepseek-v4-pro',
|
||||
choices: [
|
||||
{ message: { role: 'assistant', content: 'ok' }, finish_reason: 'stop' },
|
||||
],
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } },
|
||||
)
|
||||
}) as unknown as FetchType
|
||||
|
||||
const client = createOpenAIShimClient({
|
||||
reasoningEffort: 'xhigh',
|
||||
}) as OpenAIShimClient
|
||||
await client.beta.messages.create({
|
||||
model: 'deepseek-ai/deepseek-v4-pro?thinking=disabled',
|
||||
system: 'test',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
max_tokens: 64,
|
||||
stream: false,
|
||||
})
|
||||
|
||||
expect(requestBody?.thinking).toBeUndefined()
|
||||
expect(requestBody?.reasoning_effort).toBeUndefined()
|
||||
expect(requestBody?.chat_template_kwargs).toBeUndefined()
|
||||
})
|
||||
|
||||
test('DeepSeek omits thinking controls when the Anthropic-side request does not set them', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://api.deepseek.com/v1'
|
||||
process.env.OPENAI_API_KEY = 'sk-deepseek'
|
||||
@@ -8565,6 +8640,109 @@ test('Z.AI GLM-5.2: per-turn thinking overrides model-query default', async () =
|
||||
expect(requestBody?.reasoning_effort).toBe('high')
|
||||
})
|
||||
|
||||
test('NVIDIA NIM Z.AI GLM sends chat template thinking kwargs', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://integrate.api.nvidia.com/v1'
|
||||
process.env.NVIDIA_API_KEY = 'nvapi-test'
|
||||
|
||||
let requestBody: Record<string, unknown> | undefined
|
||||
globalThis.fetch = (async (_input, init) => {
|
||||
requestBody = JSON.parse(String(init?.body))
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 'chatcmpl-1',
|
||||
model: 'z-ai/glm-5.2',
|
||||
choices: [
|
||||
{ message: { role: 'assistant', content: 'ok' }, finish_reason: 'stop' },
|
||||
],
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } },
|
||||
)
|
||||
}) as unknown as FetchType
|
||||
|
||||
const client = createOpenAIShimClient({
|
||||
reasoningEffort: 'xhigh',
|
||||
}) as OpenAIShimClient
|
||||
await client.beta.messages.create({
|
||||
model: 'z-ai/glm-5.2',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
max_tokens: 64,
|
||||
stream: false,
|
||||
})
|
||||
|
||||
expect(requestBody?.thinking).toEqual({ type: 'enabled' })
|
||||
expect(requestBody?.reasoning_effort).toBe('max')
|
||||
expect(requestBody?.chat_template_kwargs).toEqual({
|
||||
thinking: true,
|
||||
enable_thinking: true,
|
||||
})
|
||||
})
|
||||
|
||||
test('NVIDIA NIM Z.AI GLM omits chat template thinking kwargs without a reasoning request', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://integrate.api.nvidia.com/v1'
|
||||
process.env.NVIDIA_API_KEY = 'nvapi-test'
|
||||
|
||||
let requestBody: Record<string, unknown> | undefined
|
||||
globalThis.fetch = (async (_input, init) => {
|
||||
requestBody = JSON.parse(String(init?.body))
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 'chatcmpl-1',
|
||||
model: 'z-ai/glm-5.2',
|
||||
choices: [
|
||||
{ message: { role: 'assistant', content: 'ok' }, finish_reason: 'stop' },
|
||||
],
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } },
|
||||
)
|
||||
}) as unknown as FetchType
|
||||
|
||||
const client = createOpenAIShimClient({}) as OpenAIShimClient
|
||||
await client.beta.messages.create({
|
||||
model: 'z-ai/glm-5.2',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
max_tokens: 64,
|
||||
stream: false,
|
||||
})
|
||||
|
||||
expect(requestBody?.thinking).toBeUndefined()
|
||||
expect(requestBody?.reasoning_effort).toBeUndefined()
|
||||
expect(requestBody?.chat_template_kwargs).toBeUndefined()
|
||||
})
|
||||
|
||||
test('NVIDIA NIM Z.AI GLM omits chat template thinking kwargs when thinking is disabled', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://integrate.api.nvidia.com/v1'
|
||||
process.env.NVIDIA_API_KEY = 'nvapi-test'
|
||||
|
||||
let requestBody: Record<string, unknown> | undefined
|
||||
globalThis.fetch = (async (_input, init) => {
|
||||
requestBody = JSON.parse(String(init?.body))
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
id: 'chatcmpl-1',
|
||||
model: 'z-ai/glm-5.2',
|
||||
choices: [
|
||||
{ message: { role: 'assistant', content: 'ok' }, finish_reason: 'stop' },
|
||||
],
|
||||
}),
|
||||
{ headers: { 'Content-Type': 'application/json' } },
|
||||
)
|
||||
}) as unknown as FetchType
|
||||
|
||||
const client = createOpenAIShimClient({
|
||||
reasoningEffort: 'xhigh',
|
||||
}) as OpenAIShimClient
|
||||
await client.beta.messages.create({
|
||||
model: 'z-ai/glm-5.2?thinking=disabled',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
max_tokens: 64,
|
||||
stream: false,
|
||||
})
|
||||
|
||||
expect(requestBody?.thinking).toEqual({ type: 'disabled' })
|
||||
expect(requestBody?.reasoning_effort).toBeUndefined()
|
||||
expect(requestBody?.chat_template_kwargs).toBeUndefined()
|
||||
})
|
||||
|
||||
test('Z.AI GLM-5.2: streaming requests with tools send tool_stream', async () => {
|
||||
process.env.OPENAI_BASE_URL = 'https://api.z.ai/api/coding/paas/v4'
|
||||
process.env.OPENAI_API_KEY = 'sk-zai-test'
|
||||
|
||||
@@ -364,6 +364,47 @@ export function hasMistralApiHost(baseUrl: string | undefined): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function hasNvidiaNimApiHost(baseUrl: string | undefined): boolean {
|
||||
if (!baseUrl) return false
|
||||
|
||||
try {
|
||||
return new URL(baseUrl).hostname.toLowerCase() === 'integrate.api.nvidia.com'
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function setNvidiaNimChatTemplateThinking(body: Record<string, unknown>): void {
|
||||
const existing = body.chat_template_kwargs
|
||||
const kwargs =
|
||||
existing && typeof existing === 'object' && !Array.isArray(existing)
|
||||
? { ...(existing as Record<string, unknown>) }
|
||||
: {}
|
||||
|
||||
kwargs.thinking = true
|
||||
kwargs.enable_thinking = true
|
||||
body.chat_template_kwargs = kwargs
|
||||
}
|
||||
|
||||
function maybeSetNvidiaNimChatTemplateThinking(
|
||||
body: Record<string, unknown>,
|
||||
baseUrl: string | undefined,
|
||||
reasoningRequestPlan: {
|
||||
thinkingType?: string
|
||||
reasoningEffort?: string
|
||||
},
|
||||
): void {
|
||||
if (!hasNvidiaNimApiHost(baseUrl)) return
|
||||
if (
|
||||
reasoningRequestPlan.thinkingType !== 'enabled' &&
|
||||
!reasoningRequestPlan.reasoningEffort
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
setNvidiaNimChatTemplateThinking(body)
|
||||
}
|
||||
|
||||
function formatRetryAfterHint(response: Response): string {
|
||||
const ra = response.headers.get('retry-after')
|
||||
return ra ? ` (Retry-After: ${ra})` : ''
|
||||
@@ -3756,6 +3797,7 @@ class OpenAIShimMessages {
|
||||
if (reasoningRequestPlan.reasoningEffort) {
|
||||
body.reasoning_effort = reasoningRequestPlan.reasoningEffort
|
||||
}
|
||||
maybeSetNvidiaNimChatTemplateThinking(body, request.baseUrl, reasoningRequestPlan)
|
||||
}
|
||||
|
||||
if (reasoningRequestPlan.wireFormat === 'zai_compatible') {
|
||||
@@ -3769,6 +3811,7 @@ class OpenAIShimMessages {
|
||||
} else {
|
||||
delete body.reasoning_effort
|
||||
}
|
||||
maybeSetNvidiaNimChatTemplateThinking(body, request.baseUrl, reasoningRequestPlan)
|
||||
}
|
||||
|
||||
// Route/model strip rules are authoritative even when compatibility
|
||||
|
||||
@@ -507,6 +507,121 @@ test('buildStartupEnvFromProfile preserves explicit OpenAI-compatible env withou
|
||||
assert.equal(isDefaultStartupProviderEnv(env), false)
|
||||
})
|
||||
|
||||
test('buildStartupEnvFromProfile preserves concrete env-only NIM setup over stale profile', async () => {
|
||||
const processEnv = {
|
||||
OPENAI_BASE_URL: 'https://integrate.api.nvidia.com/v1',
|
||||
OPENAI_MODEL: 'qwen/qwen3.5-397b-a17b',
|
||||
NVIDIA_API_KEY: 'nvapi-live',
|
||||
NVIDIA_NIM: '1',
|
||||
}
|
||||
|
||||
const env = await buildStartupEnvFromProfile({
|
||||
persisted: profile('openai', {
|
||||
OPENAI_BASE_URL: 'https://integrate.api.nvidia.com/v1',
|
||||
OPENAI_MODEL: 'z-ai/glm-5.2',
|
||||
NVIDIA_API_KEY: 'nvapi-stale',
|
||||
NVIDIA_NIM: '1',
|
||||
}),
|
||||
processEnv,
|
||||
})
|
||||
|
||||
assert.notEqual(env, processEnv)
|
||||
assert.equal(env.CLAUDE_CODE_USE_OPENAI, '1')
|
||||
assert.equal(env.CLAUDE_CODE_PROVIDER_ROUTE_ID, 'nvidia-nim')
|
||||
assert.equal(env.OPENAI_MODEL, 'qwen/qwen3.5-397b-a17b')
|
||||
assert.equal(env.OPENAI_BASE_URL, 'https://integrate.api.nvidia.com/v1')
|
||||
assert.equal(env.NVIDIA_API_KEY, 'nvapi-live')
|
||||
assert.equal(env.NVIDIA_NIM, '1')
|
||||
assert.equal(resolveActiveRouteIdFromEnv(env), 'nvidia-nim')
|
||||
})
|
||||
|
||||
test('buildStartupEnvFromProfile does not activate non-NIM env-only OpenAI-compatible setup', async () => {
|
||||
const env = await buildStartupEnvFromProfile({
|
||||
persisted: null,
|
||||
processEnv: {
|
||||
OPENAI_BASE_URL: 'https://openrouter.ai/api/v1',
|
||||
OPENAI_MODEL: 'openrouter/zhipu/glm-5.2',
|
||||
OPENAI_API_KEY: 'sk-live',
|
||||
},
|
||||
})
|
||||
|
||||
assert.equal(env.CLAUDE_CODE_USE_OPENAI, '1')
|
||||
assert.equal(env.CLAUDE_CODE_PROVIDER_ROUTE_ID, undefined)
|
||||
assert.equal(env.OPENAI_BASE_URL, 'https://opengateway.gitlawb.com/v1')
|
||||
assert.equal(env.OPENAI_MODEL, 'mimo-v2.5-pro')
|
||||
assert.equal(env.OPENAI_API_KEY, undefined)
|
||||
assert.equal(resolveActiveRouteIdFromEnv(env), 'gitlawb-opengateway')
|
||||
assert.equal(isDefaultStartupProviderEnv(env), true)
|
||||
})
|
||||
|
||||
test('buildStartupEnvFromProfile documents no-flag Gemini env does not beat concrete NIM setup', async () => {
|
||||
const processEnv = {
|
||||
GEMINI_API_KEY: 'gemini-live',
|
||||
GEMINI_MODEL: 'gemini-2.5-flash',
|
||||
OPENAI_BASE_URL: 'https://integrate.api.nvidia.com/v1',
|
||||
OPENAI_MODEL: 'qwen/qwen3.5-397b-a17b',
|
||||
NVIDIA_API_KEY: 'nvapi-live',
|
||||
NVIDIA_NIM: '1',
|
||||
}
|
||||
|
||||
const env = await buildStartupEnvFromProfile({
|
||||
persisted: null,
|
||||
processEnv,
|
||||
})
|
||||
|
||||
assert.notEqual(env, processEnv)
|
||||
assert.equal(env.CLAUDE_CODE_USE_OPENAI, '1')
|
||||
assert.equal(env.CLAUDE_CODE_USE_GEMINI, undefined)
|
||||
assert.equal(env.CLAUDE_CODE_PROVIDER_ROUTE_ID, 'nvidia-nim')
|
||||
assert.equal(env.GEMINI_API_KEY, undefined)
|
||||
assert.equal(env.OPENAI_MODEL, 'qwen/qwen3.5-397b-a17b')
|
||||
assert.equal(resolveActiveRouteIdFromEnv(env), 'nvidia-nim')
|
||||
})
|
||||
|
||||
test('buildStartupEnvFromProfile preserves explicit OpenAI opt-out over concrete env-only NIM setup', async () => {
|
||||
const processEnv: NodeJS.ProcessEnv = {
|
||||
CLAUDE_CODE_USE_OPENAI: '0',
|
||||
OPENAI_BASE_URL: 'https://integrate.api.nvidia.com/v1',
|
||||
OPENAI_MODEL: 'qwen/qwen3.5-397b-a17b',
|
||||
NVIDIA_API_KEY: 'nvapi-live',
|
||||
NVIDIA_NIM: '1',
|
||||
}
|
||||
|
||||
const env = await buildStartupEnvFromProfile({
|
||||
persisted: null,
|
||||
processEnv,
|
||||
})
|
||||
|
||||
assert.equal(env, processEnv)
|
||||
assert.equal(env.CLAUDE_CODE_USE_OPENAI, '0')
|
||||
assert.equal(env.CLAUDE_CODE_PROVIDER_ROUTE_ID, undefined)
|
||||
assert.equal(isDefaultStartupProviderEnv(env), false)
|
||||
})
|
||||
|
||||
test('buildStartupEnvFromProfile preserves explicit Gemini selection over concrete env-only NIM setup', async () => {
|
||||
const processEnv: NodeJS.ProcessEnv = {
|
||||
CLAUDE_CODE_USE_GEMINI: '1',
|
||||
GEMINI_API_KEY: 'gemini-live',
|
||||
GEMINI_MODEL: 'gemini-2.5-flash',
|
||||
OPENAI_BASE_URL: 'https://integrate.api.nvidia.com/v1',
|
||||
OPENAI_MODEL: 'qwen/qwen3.5-397b-a17b',
|
||||
NVIDIA_API_KEY: 'nvapi-live',
|
||||
NVIDIA_NIM: '1',
|
||||
}
|
||||
|
||||
const env = await buildStartupEnvFromProfile({
|
||||
persisted: null,
|
||||
processEnv,
|
||||
})
|
||||
|
||||
assert.equal(env, processEnv)
|
||||
assert.equal(env.CLAUDE_CODE_USE_GEMINI, '1')
|
||||
assert.equal(env.CLAUDE_CODE_USE_OPENAI, undefined)
|
||||
assert.equal(env.CLAUDE_CODE_PROVIDER_ROUTE_ID, undefined)
|
||||
assert.equal(resolveActiveRouteIdFromEnv(env), 'gemini')
|
||||
assert.equal(isDefaultStartupProviderEnv(env), false)
|
||||
})
|
||||
|
||||
test('buildStartupEnvFromProfile respects an explicit CLAUDE_CODE_USE_OPENAI=0 opt-out (issue #1245)', async () => {
|
||||
const env = await buildStartupEnvFromProfile({
|
||||
persisted: null,
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
getRouteDefaultBaseUrl,
|
||||
getRouteDefaultModel,
|
||||
normalizeXiaomiMimoBaseUrl,
|
||||
resolveRouteCredentialValue,
|
||||
resolveRouteIdFromBaseUrl,
|
||||
} from '../integrations/routeMetadata.js'
|
||||
import {
|
||||
@@ -1237,6 +1238,28 @@ export function hasExplicitProviderSelection(
|
||||
)
|
||||
}
|
||||
|
||||
function hasExplicitNonOpenAIProviderSelection(
|
||||
processEnv: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
return (
|
||||
isEnvTruthy(processEnv.CLAUDE_CODE_USE_GITHUB) ||
|
||||
isEnvTruthy(processEnv.CLAUDE_CODE_USE_GEMINI) ||
|
||||
isEnvTruthy(processEnv.CLAUDE_CODE_USE_MISTRAL) ||
|
||||
isEnvTruthy(processEnv.CLAUDE_CODE_USE_BEDROCK) ||
|
||||
isEnvTruthy(processEnv.CLAUDE_CODE_USE_VERTEX) ||
|
||||
isEnvTruthy(processEnv.CLAUDE_CODE_USE_FOUNDRY)
|
||||
)
|
||||
}
|
||||
|
||||
function hasExplicitOpenAICompatibleOptOut(
|
||||
processEnv: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
return (
|
||||
processEnv.CLAUDE_CODE_USE_OPENAI !== undefined &&
|
||||
!isEnvTruthy(processEnv.CLAUDE_CODE_USE_OPENAI)
|
||||
)
|
||||
}
|
||||
|
||||
function hasConcreteProviderSelection(
|
||||
processEnv: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
@@ -1300,6 +1323,38 @@ function hasConcreteProviderSelection(
|
||||
)
|
||||
}
|
||||
|
||||
function getConcreteOpenAICompatibleEnvRouteId(
|
||||
processEnv: NodeJS.ProcessEnv = process.env,
|
||||
): string | null {
|
||||
const openAIBaseUrl =
|
||||
sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL) ??
|
||||
sanitizeProviderConfigValue(processEnv.OPENAI_API_BASE)
|
||||
const openAIModel = normalizeProfileModel(
|
||||
sanitizeProviderConfigValue(processEnv.OPENAI_MODEL),
|
||||
)
|
||||
const openAICredential = resolveOpenAICredentialEnvSelection(processEnv)
|
||||
const openAIRouteId = resolveRouteIdFromBaseUrl(openAIBaseUrl)
|
||||
const routeCredential = sanitizeApiKey(
|
||||
resolveRouteCredentialValue({
|
||||
routeId: openAIRouteId ?? 'custom',
|
||||
baseUrl: openAIBaseUrl,
|
||||
processEnv,
|
||||
}),
|
||||
)
|
||||
const authHeaderValue = sanitizeApiKey(processEnv.OPENAI_AUTH_HEADER_VALUE)
|
||||
if (
|
||||
openAIBaseUrl !== undefined &&
|
||||
openAIModel !== undefined &&
|
||||
(openAICredential?.kind === 'usable' ||
|
||||
routeCredential !== undefined ||
|
||||
authHeaderValue !== undefined)
|
||||
) {
|
||||
return openAIRouteId ?? 'custom'
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export function selectAutoProfile(
|
||||
recommendedOllamaModel: string | null,
|
||||
): ProviderProfile {
|
||||
@@ -1857,6 +1912,7 @@ export async function buildLaunchEnv(options: {
|
||||
'FIREWORKS_API_KEY',
|
||||
'AIMLAPI_API_KEY',
|
||||
'MIMO_API_KEY',
|
||||
'NVIDIA_API_KEY',
|
||||
'VENICE_API_KEY',
|
||||
] as const) {
|
||||
// AI/ML API accepts the generic OPENAI_API_KEY, so it does not need an
|
||||
@@ -1866,6 +1922,9 @@ export async function buildLaunchEnv(options: {
|
||||
if (dedicatedKey === 'AIMLAPI_API_KEY' && effectiveOpenAIRouteId !== 'aimlapi') {
|
||||
continue
|
||||
}
|
||||
if (dedicatedKey === 'NVIDIA_API_KEY' && effectiveOpenAIRouteId !== 'nvidia-nim') {
|
||||
continue
|
||||
}
|
||||
const dedicatedValue =
|
||||
(dedicatedKey === 'AIMLAPI_API_KEY' && openAICredential?.kind === 'usable'
|
||||
? sanitizeApiKey(openAICredential.value)
|
||||
@@ -1876,6 +1935,12 @@ export async function buildLaunchEnv(options: {
|
||||
env[dedicatedKey] = dedicatedValue
|
||||
}
|
||||
}
|
||||
if (effectiveOpenAIRouteId === 'nvidia-nim') {
|
||||
const nvidiaNimFlag = processEnv.NVIDIA_NIM || persistedEnv.NVIDIA_NIM
|
||||
if (nvidiaNimFlag) {
|
||||
env.NVIDIA_NIM = nvidiaNimFlag
|
||||
}
|
||||
}
|
||||
const customHeaders = shellCustomHeaders || persistedCustomHeaders
|
||||
if (customHeaders) {
|
||||
env.ANTHROPIC_CUSTOM_HEADERS = customHeaders
|
||||
@@ -1926,6 +1991,23 @@ export async function buildStartupEnvFromProfile(options?: {
|
||||
return processEnv
|
||||
}
|
||||
|
||||
const concreteOpenAIRouteId = getConcreteOpenAICompatibleEnvRouteId(processEnv)
|
||||
if (
|
||||
concreteOpenAIRouteId === 'nvidia-nim' &&
|
||||
!isEnvTruthy(processEnv.CLAUDE_CODE_USE_OPENAI) &&
|
||||
!hasExplicitOpenAICompatibleOptOut(processEnv) &&
|
||||
!hasExplicitNonOpenAIProviderSelection(processEnv)
|
||||
) {
|
||||
return buildLaunchEnv({
|
||||
profile: 'openai',
|
||||
persisted: null,
|
||||
goal:
|
||||
options?.goal ??
|
||||
normalizeRecommendationGoal(processEnv.OPENCLAUDE_PROFILE_GOAL),
|
||||
processEnv,
|
||||
})
|
||||
}
|
||||
|
||||
// If startup already has a concrete provider selection, keep trusting it.
|
||||
// This prevents legacy profiles or the fresh-install default from becoming
|
||||
// a silent third precedence layer over explicit env/flags.
|
||||
@@ -1943,10 +2025,7 @@ export async function buildStartupEnvFromProfile(options?: {
|
||||
// injecting the default Opengateway profile — otherwise the fallback
|
||||
// re-enables OpenAI and the startup validator reports a spurious missing
|
||||
// OPENAI_API_KEY warning (#1245).
|
||||
if (
|
||||
processEnv.CLAUDE_CODE_USE_OPENAI !== undefined &&
|
||||
!isEnvTruthy(processEnv.CLAUDE_CODE_USE_OPENAI)
|
||||
) {
|
||||
if (hasExplicitOpenAICompatibleOptOut(processEnv)) {
|
||||
return processEnv
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user