feat(core): configure stream rate-limit retry delays - #7666
Conversation
|
✅ Qwen Triage finished — CI landed green on ✅ Qwen Triage 已完成 —— |
|
Thanks for the PR! Template looks good ✓ Context shift since last review: the core feature (configurable Problem: observed. Issue #7658 documented the hardcoded 60s → 120s → 240s backoff with a concrete DashScope per-minute quota scenario. The issue was triaged, accepted, and labeled Direction: aligned. The Size: 4 production logic lines (2x Approach: tight and focused. Every edit serves the stated goal. One observation: the test rename from "should increase delay" to "should use configured delay" creates a near-duplicate of the existing "uses configured stream rate-limit retry delays" test that #7674 already added — see Stage 2 for details. Non-blocking. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 自上次审查以来的上下文变化: 核心功能(可配置的 问题:已观测到的问题。Issue #7658 记录了硬编码的 60s → 120s → 240s 退避,并给出了 DashScope 分钟级配额的具体场景。该 issue 已被分类、接受,并标记为 方向:对齐。 规模:4 行生产逻辑(settingsSchema.ts 和 settings.schema.json 各 2 行 方案:紧凑且聚焦。每处改动都服务于既定目标。一个观察:测试从 "should increase delay" 重命名为 "should use configured delay" 后,与 #7674 已添加的 "uses configured stream rate-limit retry delays" 测试近乎重复——详见 Stage 2。非阻塞。 进入代码审查 🔍 — Qwen Code · qwen3.8-max-preview Reviewed at |
Code ReviewIndependent proposal: with the core feature already in main (via #7674), the remaining work is: (1) add Findings: no critical blockers, no convention violations.
CI Test EvidenceFetched via API for commit Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Ubuntu test suite is still running. Windows/macOS and integration tests were skipped (standard for fork PRs). Precheck passed. Will defer approval until CI lands green. Real-Scenario TestingN/A — the change adds schema validation constraints and test coverage for non-visual configuration behavior. No user-visible TUI surface is affected. The previous review's maintainer verification (real E2E with a mock throttling provider) already confirmed the underlying feature works end-to-end. 中文说明代码审查独立方案: 核心功能已通过 #7674 合并到 main,剩余工作为:(1) 为两个重试延迟字段的 schema 条目添加 发现: 无关键阻塞项,无规范违反。
CI 测试证据通过 API 获取,commit Ubuntu 测试套件仍在运行中。Windows/macOS 和集成测试被跳过(fork PR 的标准行为)。Precheck 已通过。将推迟批准直到 CI 全绿。 真实场景测试不适用——该改动添加 schema 校验约束和非视觉配置行为的测试覆盖。不影响用户可见的 TUI 界面。上次审查中维护者的真实 E2E 验证(使用模拟限流 provider)已确认底层功能端到端可用。 — Qwen Code · qwen3.8-max-preview Reviewed at |
|
Confidence: 4/5 — clean, minimal polish on an already-merged feature; the only nit is a near-duplicate test that doesn't affect correctness. The feature this PR set out to build — configurable stream rate-limit retry delays — is already in main via #7674. What remains in the diff is the finishing work: My independent proposal before reading the diff was identical: schema constraint, provider-override test, docs. No simpler path exists. The one thing I'd fix before merge if I were the author: the renamed "should use configured delay" test in Title mismatch noted in Stage 1: the diff no longer "configures" anything that isn't already configured. A title update would keep the changelog accurate, but this is hygiene, not a merge gate. Approval deferred until CI lands green on 中文说明置信度:4/5 —— 在已合并功能之上干净、最小化的完善;唯一的注意点是近乎重复的测试,不影响正确性。 本 PR 最初要构建的功能——可配置的流式限流重试延迟——已通过 #7674 合并到 main。diff 中剩余的是收尾工作: 我在阅读 diff 之前的独立方案与此完全一致:schema 约束、provider 覆盖测试、文档。不存在更简路径。 如果我是作者,合并前会修的一件事: Stage 1 中提到的标题不匹配:diff 不再"配置"任何尚未配置的东西。更新标题可以保持 changelog 准确,但这属于命名规范,不是合并门禁。 批准推迟到 CI 在 — Qwen Code · qwen3.8-max-preview Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
— qwen3.7-max via Qwen Code /review
Maintainer local verification — real end-to-end, not just the suiteI built this PR locally and drove the real CLI against a mock OpenAI-compatible provider that throttles the way DashScope does (HTTP 200 + Verdict: works as advertised, no blockers. Recommend merge. Two small follow-ups noted at the end — neither needs to hold this PR.
1. Real end-to-end run
The second delay in the PR run is the interesting one: Settings were supplied through the documented path ( 2. Independent scenarios + mutation matrixI wrote 10 scenarios of my own (not part of the PR) and ran each twice: once on the PR head, once on the same tree with the four changed source files reverted to the merge base while keeping the tests. 8 of 10 discriminate; the two that pass both ways are deliberate regression guards ( Worth calling out from that set:
The mutation matrix confirms the PR's test bites: dropping either override, or swapping them, is caught. One mutation survives — see below. 3. Gates re-run locally on the PR head
Follow-ups (non-blocking)(a) This is consistent with how sibling numeric (b) Small coverage delta from repurposing the existing test. (c) One documentation sentence. Worth noting in Verification harness (mock provider, E2E driver, scenarios, mutation script) is throwaway and was not committed; the PR worktree was restored to a pristine 中文说明维护者本地验证 —— 真实端到端,而非仅跑测试套件我在本地构建了该 PR,并用真实 CLI 对接一个模拟 OpenAI 兼容 Provider,该 Provider 以 DashScope 的方式返回限流(HTTP 200 + 结论:行为与描述一致,无阻塞问题,建议合并。 文末有两点后续建议,均无需卡住本 PR。
1. 真实端到端运行
PR 运行中的第二次延迟最能说明问题: 配置通过文档中的路径( 2. 独立场景 + 变异矩阵我自己编写了 10 个场景(不属于本 PR),每个都跑两遍:一遍在 PR head 上,一遍在把四个被改动的源文件回退到 merge base、但保留测试的同一棵树上。10 个中有 8 个具备判别力;两个双向通过的是刻意设计的回归保护( 其中值得一提的:
变异矩阵确认 PR 自带测试确实「咬得住」:删除任一 override、或把两者对调,都会被捕获。有一个变异存活,见下文。 3. 在 PR head 上本地重跑各项门禁core 与 cli 的 后续建议(非阻塞)(a) 这与现有同类数值型 (b) 改写既有测试带来的小幅覆盖损失。 (c) 补一句文档。 建议在 验证用的脚手架(模拟 Provider、E2E 驱动脚本、场景用例、变异脚本)均为一次性产物,未提交;PR worktree 事后已恢复到干净的 |
|
@qwen-code /resolve |
- settingsSchema.ts: keep minimum:1 validation from PR, adopt main's 'Retry Max Delay' label - geminiChat.ts: use main's pre-computed retryInitialDelayMs / retryMaxDelayMs variables instead of inline expressions - settings.schema.json: keep minimum:1 on both retry delay fields
|
Qwen Code resolved the merge conflicts and pushed the branch update. Merge resolution for PR #7666Root causeThe feature from this PR — configurable stream rate-limit retry delays — was already merged to main via a separate PR (#7674, commit Textual or semanticAll three conflicts were textual — both sides agreed on the semantics; only the surface form differed.
const retryInitialDelayMs =
cgConfig?.retryInitialDelayMs ?? RATE_LIMIT_RETRY_OPTIONS.initialDelayMs;
const retryMaxDelayMs =
cgConfig?.retryMaxDelayMs ?? RATE_LIMIT_RETRY_OPTIONS.maxDelayMs;used at the call site as
What is load-bearing
What I could not verifyNo build, typecheck, or tests were run. The 中文说明PR #7666 合并冲突解决根本原因此 PR 的功能(可配置的流速率限制重试延迟)已通过另一个 PR #7674(提交 解决策略三处冲突均为文本冲突,语义一致:
关键约束
未能验证未运行构建或测试。若有测试传入 |
7db0012
|
@qwen-code /triage |
|
Triage re-run completed without a new review. The stage comments above were updated with the latest result. View workflow run. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
— qwen3.7-max via Qwen Code /review
| it('should use configured delay across repeated streamed rate-limit errors', async () => { | ||
| vi.useFakeTimers(); | ||
|
|
||
| try { | ||
| vi.mocked(mockConfig.getContentGeneratorConfig).mockReturnValue({ | ||
| authType: AuthType.USE_OPENAI, | ||
| model: 'test-model', | ||
| retryInitialDelayMs: 3_000, | ||
| retryMaxDelayMs: 5_000, | ||
| }); |
There was a problem hiding this comment.
[Suggestion] This test was renamed and rewritten from testing default exponential backoff (60 000 → 120 000 ms) to testing configured delays (3 000 → 5 000 ms), but the existing test at line 7984 ("uses configured stream rate-limit retry delays") already covers the same configured-delay path with the same values and the same two-429-then-recovery structure. Meanwhile the default-path fallback (cgConfig?.retryInitialDelayMs ?? RATE_LIMIT_RETRY_OPTIONS.initialDelayMs) no longer has a dedicated stream-level test for the OpenAI-compatible path — the GLM test at line 7808 covers the fallback mechanically but through a different provider branch.
Consider restoring the original test's default-delay assertions (60 000, 120 000) so both the default and configured paths are covered, or adding a separate test for the default path.
— qwen3.7-max via Qwen Code /review
|
Released in v0.21.1. |
|
|


What this PR does
Adds optional
retryInitialDelayMsandretryMaxDelayMsgeneration settings for SSE stream rate-limit retries. Provider-specific generation config is routed through the existing model configuration resolver, and omitted values preserve the current 60-second initial delay and 5-minute maximum.Why it's needed
Providers use different quota windows. The current fixed 60s → 120s → 240s backoff can make a short-lived per-minute rate limit feel unnecessarily slow, while the existing defaults remain appropriate for users who do not configure the new settings.
Reviewer Test Plan
How to verify
Configure a model provider with
retryInitialDelayMs: 3000andretryMaxDelayMs: 5000, then simulate two consecutive classified rate-limit errors during an SSE stream. The retry events should report delays of 3000ms and 5000ms, with the second delay capped by the configured maximum. Confirm that provider-specific values override global generation settings and that omitting both fields retains the existing defaults.Commands run locally:
npx vitest run src/core/geminiChat.test.ts src/models/modelConfigResolver.test.ts --coverage.enabled=false— 294 tests passednpm run build— passednpm run lint— passednpm run typecheck— passednpm run generate:settings-schema— passednpm run preflight— install, formatting, CI lint, build, typecheck, core tests, and web-shell tests passed; the CLI suite reported three unrelated failures that reproduce unchanged onmain(agent-prompt.test.tspath matching in a workspace containing spaces and oneAuthDialog.test.tsxselection-timing assertion)Evidence (Before & After)
N/A — this is non-visual configuration behavior covered by regression tests.
Tested on
Environment (optional)
Ubuntu Linux, Node.js/npm workspace.
Risk & Scope
Linked Issues
Closes #7658
中文说明
本 PR 的内容
为 SSE 流式限流重试新增可选的
retryInitialDelayMs和retryMaxDelayMs生成设置。Provider 专属的生成配置通过现有模型配置解析器传递;如果省略这些值,则继续使用当前 60 秒初始延迟和 5 分钟最大延迟。为什么需要此改动
不同 Provider 使用不同的配额窗口。当前固定的 60 秒 → 120 秒 → 240 秒退避会让短暂的分钟级限流产生不必要的等待;未配置新设置的用户仍会保留现有默认行为。
Reviewer 测试计划
验证方法
为某个模型 Provider 配置
retryInitialDelayMs: 3000和retryMaxDelayMs: 5000,然后在 SSE 流中模拟两次连续且已分类的限流错误。重试事件应分别报告 3000ms 和 5000ms 延迟,其中第二次延迟受配置的最大值限制。确认 Provider 专属值覆盖全局生成设置,并确认省略两个字段时保留现有默认值。本地运行的命令:
npx vitest run src/core/geminiChat.test.ts src/models/modelConfigResolver.test.ts --coverage.enabled=false— 294 个测试通过npm run build— 通过npm run lint— 通过npm run typecheck— 通过npm run generate:settings-schema— 通过npm run preflight— 安装、格式检查、CI lint、构建、类型检查、core 测试和 web-shell 测试均通过;CLI 测试报告了三个与本改动无关的失败,并且这些失败在未修改的main上同样可复现(agent-prompt.test.ts在包含空格的工作区中的路径匹配,以及AuthDialog.test.tsx的一个选择时序断言)证据(修改前与修改后)
不适用——这是由回归测试覆盖的非视觉配置行为。
测试平台
环境(可选)
Ubuntu Linux,Node.js/npm workspace。
风险与范围
关联 Issue
关闭 #7658