Repository navigation
fix: 为 LLM Provider 增加超时与重试预算边界 - #162
Merged
rojim666 merged 1 commit intoSep 13, 2026
Merged
Conversation
Signed-off-by: Ace <[email protected]>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Recheck deadlines before SDK calls and handle SDK-level connection exceptions in both providers' retry paths.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds runtime-budget-aware timeout and retry boundaries for Anthropic and OpenAI-compatible providers.
Changes:
- Caps request timeouts by remaining budget.
- Coordinates provider retries and backoff with the remaining budget.
- Adds coverage for budget, retry, rate-limit, and cancellation behavior.
File summaries
| File | Description |
|---|---|
py-runtime/tests/unit/test_openai_provider.py |
OpenAI budget and retry tests |
py-runtime/tests/unit/test_llm_provider.py |
Anthropic budget and retry tests |
py-runtime/src/sztu_code/core/llm/provider.py |
Anthropic timeout and retry handling |
py-runtime/src/sztu_code/core/llm/openai_provider.py |
OpenAI timeout and retry handling |
Review details
Suppressed comments (2)
py-runtime/src/sztu_code/core/llm/openai_provider.py:659
- The exhaustion check runs before
_stream_oncebuilds the request, but with a very small positive budget this timeout calculation can occur after the deadline; it clamps to0.0and the subsequentcreatecall is still invoked. Re-check the deadline immediately before the SDK call and raise the budget timeout when it has expired, so direct budgeted calls cannot start a request after their deadline.
timeout_s=_request_timeout(self._timeout_s, deadline),
py-runtime/src/sztu_code/core/llm/provider.py:257
- The exhaustion check runs before request setup, but this
_request_timeoutcalculation can happen after a very small positive budget has elapsed; it clamps the timeout to0.0and the code still proceeds to invokemessages.stream. Re-check the deadline immediately before the SDK call and raise the budget timeout when it has expired, so direct budgeted calls cannot start a request after their deadline.
request_timeout = _request_timeout(self._timeout_s, deadline)
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+663
to
+666
| # The provider owns the outer retry policy. Disable SDK-level | ||
| # retries for budgeted calls so one attempt cannot consume the | ||
| # same remaining budget multiple times internally. | ||
| request_client = self._client.with_options(max_retries=0) |
Comment on lines
+260
to
+264
| # The provider owns the outer retry policy. Disable SDK-level | ||
| # retries for budgeted calls so one attempt cannot consume the | ||
| # same remaining budget multiple times internally. | ||
| request_client = self._client.with_options(max_retries=0) | ||
| request_kwargs["timeout"] = request_timeout |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
关联 #69。
Agent Loop 传入运行时剩余预算后,Provider 仍可能让单次 SDK 请求使用过长 timeout,或让 SDK 内部 retry 与 Provider 自身 retry 叠加,导致请求超出本轮运行预算。
本 PR 仅处理 Anthropic/OpenAI-compatible Provider 的超时与重试边界,不声称完整解决 #69。
Behavior
min(Provider 默认 timeout, remaining_s)。asyncio.CancelledError正常向上层传播,不被误判为可重试网络错误。remaining_s=None继续保持原有 Provider 默认 timeout/retry 行为。Validation
运行环境:
uv锁定依赖环境,Python 3.12.13。专项测试:
完整两个 Provider 单测:
上述 25 个失败均为同一个主线基线问题:
调用链在进入实际 Provider 请求逻辑前即失败:
当前 Python prompt 资源实际仍为
workbuddy.py和workbuddy/,而system_prompt.py导入Sztubuddy。该命名/目录大小写不一致属于主线已有问题,本 PR 未混入该独立修复。仅在测试进程中临时将
workbuddy.py/workbuddy/映射为Sztubuddy后,两个 Provider 的 60 个测试全部通过;该映射仅用于诊断,不是本 PR 的正式代码修复。其他检查:
CI 基线说明
本 PR 的两个 GitHub CI 工作流均已完成,但均以失败结束:
作为对照,同一仓库
main基线提交2e9a3136081c2e36a380e761c1bfbbeeba4a6532的对应运行也失败:因此当前没有证据表明 PR-03 引入了这些 CI 失败。PR-03 的 merge-base diff 只有以下 4 个文件,未涉及 prompt、Office 解析、TypeScript 资源模块、图片工具或 Linux 打包:
py-runtime/src/sztu_code/core/llm/provider.pypy-runtime/src/sztu_code/core/llm/openai_provider.pypy-runtime/tests/unit/test_llm_provider.pypy-runtime/tests/unit/test_openai_provider.py失败定位:
parse_document/Office 测试:read_file的 Python office helper 导入sztu_code.core.prompts.Sztubuddy,但基线实际仍是workbuddy.py和workbuddy/;本地最小复现同样失败。image-utils.ts重复声明createRequire,导致 daemon 启动后ECONNREFUSED。Buffer.from("image-bytes")当作 PNG,sharp正确拒绝了无效图片。source.type: "base64"。workbuddy.test.ts:测试导入不存在的Sztubuddy-resources.js。canvas-linux-x64-musl原生模块,linuxdeploy对其执行ldd时退出码为 1。以上是主线基线问题,CI 修复应另行诊断和修复,不与本 PR 混合。
Risk
remaining_s请求的 Provider timeout/retry 边界;没有运行时预算时保留原有行为。Sztubuddy导入失败;该问题应通过独立诊断和修复 PR 处理,不与本 PR 混合。UI evidence
N/A:无 TUI 或桌面端视觉变化。
Checklist
docs/reference/wire-protocol.md。Signed-off-by(DCO)。Refs #69