review: add comments for manual iteration rationale, mask password in test print, clarify Anthropic URL/models support
This commit is contained in:
parent
f86a567a72
commit
379a9c920f
2 changed files with 22 additions and 4 deletions
|
|
@ -117,6 +117,14 @@ class ExternalProviderClient:
|
|||
)
|
||||
return
|
||||
|
||||
# NOTE: manual __anext__ loop instead of `async for` is intentional.
|
||||
# On Python 3.13 + httpcore 1.0.x, `async for` auto-calls aclose() on
|
||||
# early exit (break/return/GeneratorExit) BEFORE our finally block runs.
|
||||
# That propagates GeneratorExit into PoolByteStream.__aiter__() while it
|
||||
# calls `await self.aclose()` inside `with AsyncShieldCancellation()`,
|
||||
# triggering "RuntimeError: async generator ignored GeneratorExit".
|
||||
# Fix: call response.aclose() FIRST (sets PoolByteStream._closed=True),
|
||||
# then lines_gen.aclose() is a no-op and GeneratorExit re-raises cleanly.
|
||||
lines_gen = response.aiter_lines().__aiter__()
|
||||
try:
|
||||
while True:
|
||||
|
|
@ -217,7 +225,8 @@ class ExternalProviderClient:
|
|||
}
|
||||
)
|
||||
else:
|
||||
# Remote URL — Anthropic supports url source type natively
|
||||
# Remote URL — Anthropic supports url source type natively.
|
||||
# See: https://docs.anthropic.com/en/docs/build-with-claude/vision#url-based-images
|
||||
anthropic_parts.append(
|
||||
{
|
||||
"type": "image",
|
||||
|
|
@ -273,6 +282,7 @@ class ExternalProviderClient:
|
|||
)
|
||||
return
|
||||
|
||||
# NOTE: same manual __anext__ loop as stream_chat_completion — see comment there.
|
||||
lines_gen = response.aiter_lines().__aiter__()
|
||||
try:
|
||||
while True:
|
||||
|
|
@ -375,7 +385,12 @@ class ExternalProviderClient:
|
|||
max_tokens: Optional[int] = None,
|
||||
presence_penalty: float = 0.0,
|
||||
) -> dict[str, Any]:
|
||||
"""Non-streaming chat completion. Returns the full response dict."""
|
||||
"""Non-streaming chat completion. Returns the full response dict.
|
||||
|
||||
Note: only valid for OpenAI-compatible providers. Anthropic requires its
|
||||
own Messages API; use stream_chat_completion (with stream=False) instead
|
||||
if a non-streaming Anthropic path is needed in the future.
|
||||
"""
|
||||
body: dict[str, Any] = {
|
||||
"model": model,
|
||||
"messages": messages,
|
||||
|
|
@ -401,6 +416,10 @@ class ExternalProviderClient:
|
|||
|
||||
Returns a list of model dicts with at least 'id' and optionally
|
||||
'created', 'owned_by', etc.
|
||||
|
||||
All supported providers expose a /models endpoint:
|
||||
- OpenAI-compatible: standard {"data": [...]} response
|
||||
- Anthropic: https://api.anthropic.com/v1/models — same {"data": [...]} shape
|
||||
"""
|
||||
try:
|
||||
response = await self._client.get(
|
||||
|
|
|
|||
|
|
@ -148,8 +148,7 @@ def auth_headers() -> dict[str, str]:
|
|||
token = change_resp.json()["access_token"]
|
||||
print(
|
||||
f"\n NOTE: Bootstrap password changed automatically.\n"
|
||||
f" New password: {new_password!r}\n"
|
||||
f" Set STUDIO_TEST_PASSWORD={new_password!r} for future runs."
|
||||
f" Set STUDIO_TEST_PASSWORD to your STUDIO_TEST_NEW_PASSWORD value for future runs."
|
||||
)
|
||||
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue