Skip to content

Commit a4a2c79

Browse files
committed
fix(zhipu): 修复 send_message_stream yield-in-try-except 及测试死代码;
- 将 send_message_stream 中 yield 移至 try/except 外部,避免 async generator 意外捕获外部 athrow 抛入的 HTTPStatusError; - 删除 test_stream_429_retries_and_succeeds 中未生效的首段 mock 代码。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
1 parent c43f7b9 commit a4a2c79

2 files changed

Lines changed: 13 additions & 35 deletions

File tree

‎src/coding/proxy/vendors/zhipu.py‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,11 @@ async def send_message_stream(
115115

116116
for attempt in range(max_attempts):
117117
try:
118-
async for chunk in super().send_message_stream(request_body, headers):
119-
yield chunk
118+
# 429 在 status code 检查阶段即 raise(在任何 chunk 之前),
119+
# 因此 __anext__ 安全:要么拿到首个 chunk,要么抛异常。
120+
ait = super().send_message_stream(request_body, headers)
121+
head = await ait.__anext__()
122+
except StopAsyncIteration:
120123
return
121124
except httpx.HTTPStatusError as exc:
122125
if exc.response is None or exc.response.status_code != 429:
@@ -136,6 +139,13 @@ async def send_message_stream(
136139
delay,
137140
)
138141
await asyncio.sleep(delay / 1000.0)
142+
continue
143+
144+
# yield 在 try/except 之外,避免捕获外部 athrow 的异常
145+
yield head
146+
async for chunk in ait:
147+
yield chunk
148+
return
139149

140150
# ── 延迟计算 ────────────────────────────────────────────
141151

‎tests/test_zhipu.py‎

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -430,39 +430,7 @@ async def mock_post(*args, **kwargs):
430430

431431
@pytest.mark.asyncio
432432
async def test_stream_429_retries_and_succeeds(self):
433-
"""流式 429 一次后成功."""
434-
vendor = _make_zhipu_vendor()
435-
call_count = 0
436-
437-
async def mock_stream(method, url, **kwargs):
438-
nonlocal call_count
439-
call_count += 1
440-
if call_count == 1:
441-
resp = _make_429_response()
442-
raise httpx.HTTPStatusError(
443-
"429",
444-
request=resp.request,
445-
response=resp,
446-
)
447-
# 成功响应
448-
resp = httpx.Response(
449-
status_code=200,
450-
request=httpx.Request("POST", "https://example.com"),
451-
)
452-
resp._stream = httpx.ByteStream(b'data: {"type":"content_block_start"}\n\n')
453-
return resp
454-
455-
with patch.object(vendor, "_get_client") as mock_client:
456-
client = AsyncMock()
457-
client.stream = mock_stream
458-
mock_client.return_value = client
459-
460-
# NativeAnthropicVendor.send_message_stream 的 super() 调用
461-
# 需要完整的 BaseVendor 流式路径,这里直接验证 retry 逻辑
462-
# 通过 mock super().send_message_stream 更简洁
463-
pass
464-
465-
# 使用更直接的方式测试流式重试
433+
"""流式 429 两次后成功."""
466434
call_count = 0
467435

468436
async def fake_stream(self, body, headers):

0 commit comments

Comments
 (0)