AI Agent Framework for Python
Project description
AI SDK for Python
A toolkit for building LLM-powered applications and agent loops.
Installation
uv add ai
AI Gateway usage works with the base package. Direct providers that use an OpenAI-compatible or Anthropic-compatible adapter load the corresponding official SDK lazily and require optional extras:
uv add "ai[openai]" # OpenAI-compatible providers
uv add "ai[anthropic]" # Anthropic-compatible providers
import ai
Quick Start
import asyncio
import ai
@ai.tool
async def contact_mothership(query: str) -> str:
"""Contact the mothership for important decisions."""
return "Soon."
async def main() -> None:
model = ai.get_model("gateway:anthropic/claude-sonnet-4")
agent = ai.agent(tools=[contact_mothership])
messages = [
ai.system_message(
"Use the contact_mothership tool when asked about the future."
),
ai.user_message("When will the robots take over?"),
]
async with agent.run(model, messages) as stream:
async for event in stream:
if isinstance(event, ai.events.TextDelta):
print(event.chunk, end="", flush=True)
if __name__ == "__main__":
asyncio.run(main())
Models
The models module provides thin wrappers around LLM provider APIs.
An ai.Model is a config object you pass to ai.stream to get an LLM reply.
It accepts tool schemas but does not execute custom tools.
model = ai.get_model() # reads AI_SDK_DEFAULT_MODEL
model = ai.get_model("openai/gpt-5.4") # provider omitted: defaults to gateway
model = ai.get_model("gateway:openai/gpt-5.4")
model = ai.get_model("openai:gpt-5.4")
model = ai.get_model("anthropic:claude-sonnet-4-6")
Provider IDs without a provider: prefix route through AI Gateway by default.
Direct OpenAI-compatible providers, including openai: and compatible
models.dev provider IDs, require ai[openai]. Direct Anthropic-compatible
providers require ai[anthropic].
Structured output:
import pydantic
class UprisingPlan(pydantic.BaseModel):
phases: list[str]
eta: str
risk_level: int
async with ai.stream(
model,
[ai.user_message("Outline the robot uprising.")],
output_type=UprisingPlan,
) as stream:
async for event in stream:
if isinstance(event, ai.events.TextDelta):
print(event.chunk, end="")
plan = stream.output
Built-in tools execute on the provider side and arrive as part of the stream:
async with ai.stream(
model,
[ai.user_message("Latest Formula 1 results?")],
tools=[ai.anthropic.tools.web_search(max_uses=3)],
) as s:
async for event in s:
if isinstance(event, ai.events.TextDelta):
print(event.chunk, end="", flush=True)
Agents
The agents module wraps ai.stream in a loop that drives tool execution.
It manages message history, loop control, and asynchronous tool dispatch.
The default loop supports streaming text, tool calls, tool results, provider-executed tools, and nested agent output.
Subclass ai.Agent and override loop to take manual control of streaming and tool dispatch:
class CustomAgent(ai.Agent):
async def loop(self, context: ai.Context) -> AsyncGenerator[ai.events.AgentEvent]:
while context.keep_running():
async with (
ai.stream(context=context) as s,
ai.ToolRunner() as tr,
):
async for event in ai.util.merge(s, tr.events()):
yield event
if isinstance(event, ai.events.ToolEnd):
tr.schedule(context.resolve(event.tool_call))
context.add(s.message)
context.add(tr.get_tool_message())
Hooks
Hooks let an agent pause for external input, such as human approval:
approval = await ai.hook(
"approve_send_email",
payload=ai.tools.ToolApproval,
metadata={"tool": "send_email"},
)
ai.resolve_hook("approve_send_email", {"granted": True, "reason": "approved"})
Examples
Focused samples live in examples/samples/.
End-to-end demos:
examples/fastapi-vite/- FastAPI + React chat with tool approvalexamples/multiagent-textual/- parallel agents with terminal hook resolutionexamples/temporal-direct/- durable agent with a custom loop
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ai-0.2.0.tar.gz.
File metadata
- Download URL: ai-0.2.0.tar.gz
- Upload date:
- Size: 802.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9bd43071c0d1297469d4d5184bf7ff586928f0f4fff4e032149223c82a7a10e2
|
|
| MD5 |
3369fa3f422e8abea4b9c4de31158297
|
|
| BLAKE2b-256 |
3e030d0b28884be1e8d0d6659008b9fa62f71b2653ff8ff44cca92ddadc16151
|
File details
Details for the file ai-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ai-0.2.0-py3-none-any.whl
- Upload date:
- Size: 114.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d65f1a42a72086f9c2f6f58c5a776878a61f57dafcc91baa21166554a3d9bf89
|
|
| MD5 |
ae23a4a4d966a07c926e95c9e11bad20
|
|
| BLAKE2b-256 |
163d3f4da0e53bc24fd522187ce4e992521e646050dd0e390f1430ecbf3613e4
|