fix(config): support QWEN_CODE_API_TIMEOUT_MS across OAuth and non-OAuth paths#3629
Conversation
Adds support for QWEN_CODE_API_TIMEOUT_MS as an environment override for model generation timeout. Qwen Code already supports timeout configuration via: settings.model.generationConfig.timeout This change introduces an env-based override for users running slow local/OpenAI-compatible backends where editing config is less convenient. Precedence: modelProvider > env var > settings > default (120000ms) Behavior: - Valid positive env values override configured timeout - Invalid values are ignored - Default behavior remains unchanged (applied in buildClient()) Note: The 5-minute timeout reported in QwenLM#1045 originally came from undici's default bodyTimeout, which is now disabled (bodyTimeout:0). The modelConfigResolver default is 120000ms (2 minutes). Includes unit tests covering precedence and validation. Closes QwenLM#1045 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
The PR successfully implements the QWEN_CODE_API_TIMEOUT_MS environment variable override for most authentication types. However, there are a few minor items to address for consistency and robustness, particularly regarding the QWEN_OAUTH code path.\n\n_— Gemini CLI /review_
| sources, | ||
| ); | ||
|
|
||
| // ---- Env override: QWEN_CODE_API_TIMEOUT_MS ---- |
There was a problem hiding this comment.
[Suggestion] The QWEN_CODE_API_TIMEOUT_MS override logic here is skipped for QWEN_OAUTH due to the early return at the start of resolveModelConfig. Consider moving this logic or applying it within resolveQwenOAuthConfig for consistency across all auth types.\n\n_— Gemini CLI /review_
| const envTimeout = env['QWEN_CODE_API_TIMEOUT_MS']; | ||
| if (envTimeout !== undefined) { | ||
| const parsed = Number(envTimeout); | ||
| if (Number.isFinite(parsed) && parsed > 0) { |
There was a problem hiding this comment.
[Nice to have] Use Math.floor(Number(envTimeout)) or parseInt(envTimeout, 10) to ensure the timeout value is an integer, which is the standard format for millisecond durations.\n\n_— Gemini CLI /review_
| expect(result.config.timeout).toBe(60000); | ||
| expect(result.sources['timeout'].kind).toBe('modelProviders'); | ||
| }); | ||
|
|
There was a problem hiding this comment.
[Suggestion] Add a test case to verify that QWEN_CODE_API_TIMEOUT_MS correctly overrides settings when authType is AuthType.QWEN_OAUTH. This would have helped catch the missing support in the implementation.\n\n_— Gemini CLI /review_
| @@ -247,6 +247,24 @@ export function resolveModelConfig( | |||
| sources, | |||
There was a problem hiding this comment.
[Critical] The timeout env override is only applied in the non-OAuth path because resolveModelConfig() returns early for AuthType.QWEN_OAUTH before reaching this new block. resolveQwenOAuthConfig() never reads input.env, so Qwen OAuth users still cannot override API timeouts with QWEN_CODE_API_TIMEOUT_MS.
Please move this override into shared generation-config resolution used by both paths, preserving modelProvider > env > settings, and add a Qwen OAuth test for the env timeout override.
— gpt-5.5 via Qwen Code /review
| sources, | ||
| ); | ||
|
|
||
| // ---- Env override: QWEN_CODE_API_TIMEOUT_MS ---- |
There was a problem hiding this comment.
[Critical] This override is applied only after the AuthType.QWEN_OAUTH early return above, so QWEN_CODE_API_TIMEOUT_MS is ignored for Qwen OAuth sessions. That means the new env override does not work on the default Qwen auth path, even though the downstream provider can consume config.timeout.
Please apply the same env-timeout merge in resolveQwenOAuthConfig() as well, or factor this logic into a shared helper used by both resolver paths after resolveGenerationConfig(), while preserving modelProvider > env > settings precedence.
— gpt-5.5 via Qwen Code /review
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — gpt-5.5 via Qwen Code /review
79eae30 to
005d822
Compare
Covers: large timeout values, whitespace-padded env values, negative env values, and reinforces provider > env > settings precedence. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
005d822 to
0a5b96d
Compare
Adds support for QWEN_CODE_API_TIMEOUT_MS as an environment override for model generation timeout. Closes QwenLM#13 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0a5b96d to
5eb2406
Compare
| // Regression: when settings.model.name is set but doesn't match any | ||
| // provider, the code should NOT fall through to OPENAI_MODEL/QWEN_MODEL. | ||
| // The env-matched provider should only supply metadata when no model is requested. | ||
| const mockSettings = makeMockSettings({ |
There was a problem hiding this comment.
[Critical] The new regression test is outside the describe('modelConfigUtils', ...) block where makeMockSettings is scoped. This makes npm run typecheck fail with TS2552: Cannot find name 'makeMockSettings', and the focused vitest run fails with ReferenceError: makeMockSettings is not defined. Move this test inside the existing describe('resolveCliGenerationConfig', ...) block, or hoist makeMockSettings to module scope.
— gpt-5.5 via Qwen Code /review
|
Follow-up note: I've created a refactor PR (#3651, now closed) to dedupe the duplicated |
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — gpt-5.5 via Qwen Code /review
…Override helper Deduplicates the timeout env override logic that was duplicated in resolveModelConfig() and resolveQwenOAuthConfig() after PR QwenLM#3629 merged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…uth paths (QwenLM#3629) * feat(config): support API timeout env override Adds support for QWEN_CODE_API_TIMEOUT_MS as an environment override for model generation timeout. Qwen Code already supports timeout configuration via: settings.model.generationConfig.timeout This change introduces an env-based override for users running slow local/OpenAI-compatible backends where editing config is less convenient. Precedence: modelProvider > env var > settings > default (120000ms) Behavior: - Valid positive env values override configured timeout - Invalid values are ignored - Default behavior remains unchanged (applied in buildClient()) Note: The 5-minute timeout reported in QwenLM#1045 originally came from undici's default bodyTimeout, which is now disabled (bodyTimeout:0). The modelConfigResolver default is 120000ms (2 minutes). Includes unit tests covering precedence and validation. Closes QwenLM#1045 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(core): add edge-case tests for QWEN_CODE_API_TIMEOUT_MS Covers: large timeout values, whitespace-padded env values, negative env values, and reinforces provider > env > settings precedence. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(config): support QWEN_CODE_API_TIMEOUT_MS override Adds support for QWEN_CODE_API_TIMEOUT_MS as an environment override for model generation timeout. Closes QwenLM#13 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Adds
QWEN_CODE_API_TIMEOUT_MSas an environment override for model generation timeout.This is intended for slow local or OpenAI-compatible backends where editing
settings.jsonis inconvenient.What changed
Supports
QWEN_CODE_API_TIMEOUT_MStimeout overridePreserves precedence:
modelProvider > env var > settings > defaultApplies the override to both:
AuthType.QWEN_OAUTHconfig resolutionFloors float values to integer milliseconds
Ignores invalid, zero, negative, or non-numeric values
Keeps default behavior unchanged when the env var is not set
Review feedback addressed
This updates the original implementation based on review feedback:
resolveModelConfig()returned early before the env override was appliedQWEN_CODE_API_TIMEOUT_MSis tested against the default auth pathValidation
npx vitest run packages/core/src/models/modelConfigResolver.test.tsnpm run lintScope / risk
Low risk. This only changes timeout resolution when
QWEN_CODE_API_TIMEOUT_MSis explicitly provided.No breaking changes.