diff --git a/examples/samples/stream_all.py b/examples/samples/stream_all.py new file mode 100644 index 00000000..491924f1 --- /dev/null +++ b/examples/samples/stream_all.py @@ -0,0 +1,44 @@ +"""Streaming across all available adapter""" + +import asyncio + +import ai + +MODELS: list[tuple[str, ai.Provider, str]] = [ + ("ai_gateway", ai.ai_gateway, "anthropic/claude-sonnet-4.6"), + ("anthropic", ai.anthropic, "claude-sonnet-4-6"), + ("openai", ai.openai, "gpt-5.5"), +] + +messages = [ + ai.system_message("Be concise."), + ai.user_message("Explain why the sky is blue in two sentences."), +] + + +async def _run(name: str, provider: ai.Provider, model_id: str) -> None: + print(f"\n{name} / {model_id}") + + if provider.client().api_key is None: + print(f"[SKIP] {provider.api_key_env} not set") + return + + model = provider(model_id) + + try: + async with ai.stream(model, messages) as s: + async for event in s: + if isinstance(event, ai.TextDelta): + print(event.chunk, end="", flush=True) + print() + except Exception as exc: + print(f"[ERR] {type(exc).__name__}: {exc}") + + +async def main() -> None: + for name, provider, model_id in MODELS: + await _run(name, provider, model_id) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/src/ai/models/anthropic/__init__.py b/src/ai/models/anthropic/__init__.py index 659ce7c9..c99b6bfd 100644 --- a/src/ai/models/anthropic/__init__.py +++ b/src/ai/models/anthropic/__init__.py @@ -22,7 +22,7 @@ if TYPE_CHECKING: pass -_BASE_URL = "https://api.anthropic.com/v1" +_BASE_URL = "https://api.anthropic.com" _API_KEY_ENV = "ANTHROPIC_API_KEY" _ANTHROPIC_VERSION = "2023-06-01" @@ -83,7 +83,9 @@ async def list(self, *, client: client_.Client | None = None) -> list[str]: "x-api-key": c.api_key or "", "anthropic-version": _ANTHROPIC_VERSION, } - response = await c.http.get(f"{c.base_url.rstrip('/')}/models", headers=headers) + response = await c.http.get( + f"{c.base_url.rstrip('/')}/v1/models", headers=headers + ) response.raise_for_status() data: list[dict[str, object]] = response.json().get("data", []) return sorted(str(m["id"]) for m in data) diff --git a/src/ai/models/anthropic/check.py b/src/ai/models/anthropic/check.py index 4b1fd2fd..2e7a4159 100644 --- a/src/ai/models/anthropic/check.py +++ b/src/ai/models/anthropic/check.py @@ -1,7 +1,7 @@ """Anthropic connection check. Verifies that the client's credentials are valid and that the model -exists on the Anthropic API by hitting ``GET /v1/models/{model_id}``. +exists on the Anthropic API by hitting ``GET {base_url}/v1/models/{model_id}``. The ``anthropic-version`` header is added by the check function itself so that :class:`~ai.models.core.client.Client` stays provider-agnostic. @@ -24,7 +24,7 @@ async def check(client: client_.Client, model: model_.Model) -> bool: """Return ``True`` if *client* can reach Anthropic and *model* exists.""" if not client.api_key: return False - url = f"{client.base_url.rstrip('/')}/models/{model.id}" + url = f"{client.base_url.rstrip('/')}/v1/models/{model.id}" headers = { "x-api-key": client.api_key, "anthropic-version": _ANTHROPIC_VERSION,