From 5baab60406371ff76cb5c0f96ebf9d4bd5c8a033 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Mon, 22 Jun 2026 09:23:42 -0700 Subject: [PATCH 01/19] Bump docs to catch up to the relevant version --- README.md | 2 +- docs/ai-python/content/docs/basics/streaming.mdx | 4 ++++ docs/ai-python/content/docs/basics/tools.mdx | 2 +- .../content/docs/core-framework/message-history.mdx | 8 +++++--- skills/ai/SKILL.md | 6 +++++- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 77bcf8db..4b2ff58a 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ 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)], + tools=[ai.providers.anthropic.tools.web_search(max_uses=3)], ) as s: async for event in s: if isinstance(event, ai.events.TextDelta): diff --git a/docs/ai-python/content/docs/basics/streaming.mdx b/docs/ai-python/content/docs/basics/streaming.mdx index 9cee1b9b..f0e9eff7 100644 --- a/docs/ai-python/content/docs/basics/streaming.mdx +++ b/docs/ai-python/content/docs/basics/streaming.mdx @@ -54,6 +54,10 @@ usage = stream.usage Use `stream.message` when you need to append the assistant turn to your own history. Use `stream.text` when you only need the final text. +If a provider stream ends before its finish event, iteration raises +`ai.errors.ProviderIncompleteResponseError`. The partial message is still +available on `stream.message`. + ## Use structured output Pass a Pydantic model as `output_type` when you want the final text parsed as diff --git a/docs/ai-python/content/docs/basics/tools.mdx b/docs/ai-python/content/docs/basics/tools.mdx index 420d8142..a2fbffbb 100644 --- a/docs/ai-python/content/docs/basics/tools.mdx +++ b/docs/ai-python/content/docs/basics/tools.mdx @@ -80,7 +80,7 @@ tool calls but you do not want the SDK to execute them: tool = ai.Tool( kind="function", name="contact_mothership", - args=ai.tools.FunctionToolArgs( + spec=ai.tools.ToolSpec( description="Contact the mothership.", params={ "type": "object", diff --git a/docs/ai-python/content/docs/core-framework/message-history.mdx b/docs/ai-python/content/docs/core-framework/message-history.mdx index b48cf8b0..bb2841d6 100644 --- a/docs/ai-python/content/docs/core-framework/message-history.mdx +++ b/docs/ai-python/content/docs/core-framework/message-history.mdx @@ -67,7 +67,7 @@ integrity.prepare_messages(messages, mode="strict") ## Replay markers -Replay markers are runtime-only flags on assistant messages. They let a resumed +Replay markers are internal flags on assistant messages. They let a resumed agent dispatch existing tool calls without another model request: ```python @@ -76,7 +76,7 @@ if messages[-1].replay: ... ``` -Replay flags are excluded from JSON serialization. +Replay flags are serialized when true and omitted when false. ## Persisted history @@ -88,4 +88,6 @@ restored = [ai.messages.Message.model_validate(item) for item in encoded] ``` Persist messages after each completed or suspended run. Recreate live runtime -objects, providers, and hooks on the next request. +objects, providers, and hooks on the next request. Resume state such as replay +markers, cached tool results, and model-facing tool input is included when +present. diff --git a/skills/ai/SKILL.md b/skills/ai/SKILL.md index 885a58d9..ec79a2f3 100644 --- a/skills/ai/SKILL.md +++ b/skills/ai/SKILL.md @@ -149,6 +149,10 @@ stream.tool_calls # function tool calls from ai.stream stream.usage # latest reported usage ``` +If a provider stream ends before its finish event, iteration raises +`ai.errors.ProviderIncompleteResponseError`. The partial message is still on +the stream object. + Serialize and restore history with Pydantic JSON: ```python @@ -208,7 +212,7 @@ Use schema-only tools with `ai.stream` when the SDK should not execute them: tool = ai.Tool( kind="function", name="get_weather", - args=ai.tools.FunctionToolArgs( + spec=ai.tools.ToolSpec( description="Get current weather for a city.", params={ "type": "object", From 0b959b98daf19eae4b088a36a2e4ae9e18b7e184 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 08:10:47 -0700 Subject: [PATCH 02/19] Restructure the docs into basics and reference --- .../content/docs/basics/custom-loops.mdx | 2 +- docs/ai-python/content/docs/basics/index.mdx | 3 +- .../docs/basics/messages-and-events.mdx | 12 ++ .../content/docs/basics/providers.mdx | 20 +++ .../content/docs/basics/streaming.mdx | 11 ++ docs/ai-python/content/docs/basics/tools.mdx | 21 +++ .../core-framework/adapters-and-providers.mdx | 88 ------------ .../docs/core-framework/agent-loop.mdx | 84 ------------ .../content/docs/core-framework/hooks.mdx | 88 ------------ .../content/docs/core-framework/index.mdx | 55 -------- .../docs/core-framework/message-history.mdx | 93 ------------- .../content/docs/core-framework/meta.json | 13 -- .../docs/core-framework/streaming-tools.mdx | 128 ------------------ .../content/docs/core-framework/streams.mdx | 91 ------------- .../docs/core-framework/tool-dispatch.mdx | 95 ------------- docs/ai-python/content/docs/index.mdx | 8 +- docs/ai-python/content/docs/meta.json | 2 +- .../content/docs/reference/agent.mdx | 80 +++++++++++ .../content/docs/reference/ai-sdk-ui.mdx | 68 ++++++++++ .../content/docs/reference/events.mdx | 96 +++++++++++++ .../content/docs/reference/generate.mdx | 61 +++++++++ .../content/docs/reference/hooks.mdx | 67 +++++++++ .../content/docs/reference/index.mdx | 21 +++ .../content/docs/reference/messages.mdx | 102 ++++++++++++++ .../content/docs/reference/meta.json | 16 +++ .../docs/reference/models-and-providers.mdx | 119 ++++++++++++++++ .../content/docs/reference/stream.mdx | 81 +++++++++++ .../content/docs/reference/tool-runner.mdx | 85 ++++++++++++ .../ai-python/content/docs/reference/tool.mdx | 79 +++++++++++ 29 files changed, 947 insertions(+), 742 deletions(-) delete mode 100644 docs/ai-python/content/docs/core-framework/adapters-and-providers.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/agent-loop.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/hooks.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/index.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/message-history.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/meta.json delete mode 100644 docs/ai-python/content/docs/core-framework/streaming-tools.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/streams.mdx delete mode 100644 docs/ai-python/content/docs/core-framework/tool-dispatch.mdx create mode 100644 docs/ai-python/content/docs/reference/agent.mdx create mode 100644 docs/ai-python/content/docs/reference/ai-sdk-ui.mdx create mode 100644 docs/ai-python/content/docs/reference/events.mdx create mode 100644 docs/ai-python/content/docs/reference/generate.mdx create mode 100644 docs/ai-python/content/docs/reference/hooks.mdx create mode 100644 docs/ai-python/content/docs/reference/index.mdx create mode 100644 docs/ai-python/content/docs/reference/messages.mdx create mode 100644 docs/ai-python/content/docs/reference/meta.json create mode 100644 docs/ai-python/content/docs/reference/models-and-providers.mdx create mode 100644 docs/ai-python/content/docs/reference/stream.mdx create mode 100644 docs/ai-python/content/docs/reference/tool-runner.mdx create mode 100644 docs/ai-python/content/docs/reference/tool.mdx diff --git a/docs/ai-python/content/docs/basics/custom-loops.mdx b/docs/ai-python/content/docs/basics/custom-loops.mdx index 615f448f..4ad8ac65 100644 --- a/docs/ai-python/content/docs/basics/custom-loops.mdx +++ b/docs/ai-python/content/docs/basics/custom-loops.mdx @@ -102,7 +102,7 @@ You can also route specific tools through custom wrappers: ```python if tool_call.name == "contact_mothership": - tool_runner.schedule(GatedToolCall(tool_call)) + tool_runner.schedule(ai.agents.GatedToolCall(tool_call)) else: tool_runner.schedule(tool_call) ``` diff --git a/docs/ai-python/content/docs/basics/index.mdx b/docs/ai-python/content/docs/basics/index.mdx index 82a8d4bd..4344cbbc 100644 --- a/docs/ai-python/content/docs/basics/index.mdx +++ b/docs/ai-python/content/docs/basics/index.mdx @@ -34,7 +34,8 @@ Start with the model call, then add the pieces your app needs: Read providers, messages, streaming, tools, and agents first. Then add custom loops, subagents, human-in-the-loop workflows, and UI integration when your app -needs those control points. +needs those control points. Use Reference when you need the exact public API +shape for a symbol. ## Example map diff --git a/docs/ai-python/content/docs/basics/messages-and-events.mdx b/docs/ai-python/content/docs/basics/messages-and-events.mdx index 9eb8db61..be203dde 100644 --- a/docs/ai-python/content/docs/basics/messages-and-events.mdx +++ b/docs/ai-python/content/docs/basics/messages-and-events.mdx @@ -65,6 +65,18 @@ restored = [ai.messages.Message.model_validate(item) for item in encoded] Persist `stream.messages` after an agent run when you want to continue the conversation later. +Before provider calls, the SDK prepares message history by stripping internal +messages, removing non-model parts, repairing invalid tool args to `{}`, and +inserting error results for missing tool calls when possible. Use strict +validation in tests or import pipelines: + +```python +from ai.types import integrity + + +integrity.prepare_messages(messages, mode="strict") +``` + ## Handle stream events Streams and agents both yield event objects from `ai.events`. Most applications diff --git a/docs/ai-python/content/docs/basics/providers.mdx b/docs/ai-python/content/docs/basics/providers.mdx index 36264fa7..ee432784 100644 --- a/docs/ai-python/content/docs/basics/providers.mdx +++ b/docs/ai-python/content/docs/basics/providers.mdx @@ -135,3 +135,23 @@ async with ai.stream(model, messages, params=params) as stream: Provider options pass through to the selected provider. Check the provider documentation for supported fields. + +## Add a provider + +Custom providers subclass `ai.Provider`. A provider owns configuration, +clients, model listing, connection checks, and wire translation through its +protocol: + +```python +class AcmeProvider(ai.Provider[AcmeClient]): + handles = ("acme",) + + async def list_models(self) -> list[str]: + ... + + async def probe(self, model: ai.Model) -> None: + ... +``` + +Most applications only need `ai.get_provider` and `ai.Model`. Add a provider +when you need a new upstream API or custom wire protocol. diff --git a/docs/ai-python/content/docs/basics/streaming.mdx b/docs/ai-python/content/docs/basics/streaming.mdx index f0e9eff7..e49da74f 100644 --- a/docs/ai-python/content/docs/basics/streaming.mdx +++ b/docs/ai-python/content/docs/basics/streaming.mdx @@ -58,6 +58,11 @@ If a provider stream ends before its finish event, iteration raises `ai.errors.ProviderIncompleteResponseError`. The partial message is still available on `stream.message`. +The stream updates `stream.message` as events arrive. Text and reasoning use +start, delta, and end events. Tool calls use `ToolStart`, `ToolDelta`, and +`ToolEnd`. Generated files arrive as `FileEvent` and are added to the final +message. + ## Use structured output Pass a Pydantic model as `output_type` when you want the final text parsed as @@ -153,3 +158,9 @@ result = await ai.generate( image = result.images[0] ``` + +## Replay an existing assistant turn + +When the last message has `replay=True`, `ai.stream` does not call the +provider. It emits replay events from the existing assistant message so resume +flows can dispatch the same tool calls again. diff --git a/docs/ai-python/content/docs/basics/tools.mdx b/docs/ai-python/content/docs/basics/tools.mdx index a2fbffbb..1eccf96d 100644 --- a/docs/ai-python/content/docs/basics/tools.mdx +++ b/docs/ai-python/content/docs/basics/tools.mdx @@ -71,6 +71,27 @@ async with agent.run(model, messages) as stream: The original exception is available on `event.exception` for logging. +## Stream tool output + +Async-generator tools can yield partial output while they run. The agent emits +`PartialToolCallResult` events for those values, then sends the aggregated +result back to the model on the next turn. + +Use `ai.StreamingTextTool` when yielded strings should concatenate into the +tool result: + +```python +@ai.tool +async def draft_reply(topic: str) -> ai.StreamingTextTool: + """Draft a reply.""" + yield "Checking " + yield "records for " + yield topic +``` + +Use `ai.StreamingStatusTool[T]` when intermediate yields are progress updates +and the last yielded value is the final result. + ## Use schema-only tools Pass `ai.Tool` objects directly to `ai.stream` when you want the model to emit diff --git a/docs/ai-python/content/docs/core-framework/adapters-and-providers.mdx b/docs/ai-python/content/docs/core-framework/adapters-and-providers.mdx deleted file mode 100644 index ee29581c..00000000 --- a/docs/ai-python/content/docs/core-framework/adapters-and-providers.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Adapters and Providers -description: Understand provider objects and adapter dispatch. -type: conceptual -summary: Learn how providers, clients, adapters, and wire translations connect models to APIs. ---- - -Providers own configuration and clients. Adapters translate framework messages, -tools, params, and generated files to provider wire formats. - -## Provider objects - -`Model` stores a model ID, adapter key, and provider reference: - -```python -provider = ai.get_provider("openai") -model = ai.Model("gpt-5.4", provider=provider) -``` - -`ai.get_model` resolves a provider from a model ID and defaults unprefixed IDs -to AI Gateway: - -```python -model = ai.get_model("anthropic/claude-sonnet-4") -``` - -## Client creation - -Providers create upstream clients from API keys, base URLs, headers, and env -vars. You can also pass a client that your app owns: - -```python -provider = ai.get_provider( - "openai", - base_url="http://localhost:1234/v1", - api_key="your_access_token_here", - client=http_client, -) -``` - -## Adapter registry - -Provider subclasses register handles such as `openai`, `anthropic`, and -`vercel`. `get_provider` uses models.dev metadata to choose the provider class -for a provider ID. - -## Stream adapters - -Stream adapters implement `provider.stream`. They convert messages and tools to -the provider request, then yield public events: - -```python -async for event in model.provider.stream(model, messages, tools=tools): - yield event -``` - -OpenAI-compatible providers use the OpenAI chat-completions protocol. -Anthropic-compatible providers use the Anthropic messages protocol. AI Gateway -uses the Language Model v3 stream protocol. - -## Generate adapters - -`ai.generate` prepares messages and calls `provider.generate`. AI Gateway -supports image and video generation: - -```python -result = await ai.generate( - model, - [ai.user_message("A mothership over the ocean.")], - ai.ImageParams(n=1), -) -``` - -## Provider wire translation - -Adapters translate the same internal parts differently per provider: - -- `TextPart` and `FilePart` become user content. -- `ToolCallPart` becomes provider tool-call wire data. -- `ToolResultPart.get_model_input()` becomes the tool result sent back to the - model. -- Provider-executed tools become provider tool declarations. - -## Custom adapters - -Add a provider by subclassing `Provider`, setting `handles`, and implementing -`from_modelsdev_provider`, `stream`, `list_models`, and `probe`. Implement -`generate` only if the provider supports non-streaming media generation. diff --git a/docs/ai-python/content/docs/core-framework/agent-loop.mdx b/docs/ai-python/content/docs/core-framework/agent-loop.mdx deleted file mode 100644 index 2ceee08d..00000000 --- a/docs/ai-python/content/docs/core-framework/agent-loop.mdx +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Agent Loop -description: Understand the default agent loop and history lifecycle. -type: conceptual -summary: Learn how agents stream model output, dispatch tools, update history, and decide when to stop. ---- - -`Agent.loop` is the default control flow for model calls and tool execution. It -is intentionally small so you can override it when needed. - -## Default loop lifecycle - -```python -while context.keep_running(): - async with ( - ai.stream(context=context) as stream, - ai.ToolRunner() as tool_runner, - ): - async for event in ai.util.merge(stream, tool_runner.events()): - yield event - if isinstance(event, ai.events.ToolEnd): - tool_runner.schedule(context.resolve(event.tool_call)) - - context.add(stream.message) - context.add(tool_runner.get_tool_message()) -``` - -## Context state - -`Context` holds the model, messages, model-facing tool schemas, structured -output type, request params, and the private executable tool registry. - -```python -context.model -context.messages -context.tools -context.params -``` - -## Keep-running rules - -`context.keep_running()` returns `True` while the last message still needs work: - -- No messages means stop. -- A final assistant message means stop. -- A pending hook result means stop until the hook resolves. -- A replay-marked assistant message means dispatch its tool calls again. - -## Message history updates - -Each model turn adds one assistant message. Each tool batch adds one tool -message: - -```python -context.add(stream.message) -context.add(tool_runner.get_tool_message()) -``` - -Replay-marked assistant messages are skipped to avoid duplicate history. - -## Tool-result turns - -`ToolRunner` collects `ToolCallResult` events and merges their result parts into -one `role="tool"` message: - -```python -tool_message = tool_runner.get_tool_message() -context.add(tool_message) -``` - -The next model turn receives that tool message as context. - -## Final output - -`AgentStream.output` reads the final assistant message. With no `output_type`, -it returns text. With `output_type`, it validates JSON into that Pydantic model: - -```python -async with agent.run(model, messages, output_type=Forecast) as stream: - async for event in stream: - ... - -forecast = stream.output -``` diff --git a/docs/ai-python/content/docs/core-framework/hooks.mdx b/docs/ai-python/content/docs/core-framework/hooks.mdx deleted file mode 100644 index 144958e6..00000000 --- a/docs/ai-python/content/docs/core-framework/hooks.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Hooks -description: Understand hook suspension, resolution, cancellation, and resume. -type: conceptual -summary: Learn how hooks suspend agent work, emit state, accept resolutions, and support replay. ---- - -Hooks are runtime suspension points. They emit internal messages so clients can -render pending, resolved, or cancelled state. - -## Hook lifecycle - -```python -approval = await ai.hook( - "approve_contact_mothership", - payload=ai.tools.ToolApproval, - metadata={"tool": "contact_mothership"}, -) -``` - -The hook checks for a pre-registered resolution first. If none exists, it emits -a pending `HookEvent` and waits on a live future. - -## Live hook registry - -Live hooks are stored by label while an agent run is active. `resolve_hook` -settles the waiting future: - -```python -ai.resolve_hook( - "approve_contact_mothership", - {"granted": True, "reason": "approved"}, -) -``` - -The run removes live hook entries when the hook resolves or the run finishes. - -## Pending resolutions - -When no live hook exists, `resolve_hook` stores the resolution for a later -replay: - -```python -ai.resolve_hook( - "approve_contact_mothership", - ai.tools.ToolApproval(granted=True, reason="approved"), -) -``` - -The next matching `ai.hook` consumes that value and returns immediately. - -## Hook events - -Hooks emit `HookEvent` objects. The event message has role `internal` and -contains a `HookPart`: - -```python -if isinstance(event, ai.events.HookEvent): - print(event.hook.hook_id, event.hook.status) -``` - -## Abort and resume - -Serverless handlers can abort a run after a pending hook event: - -```python -if event.hook.status == "pending": - ai.abort_pending_hook(event.hook) -``` - -Persist the messages, collect the user's response, call `resolve_hook`, and run -the agent again with the restored messages. - -## Cancellation - -Cancel a live hook when the waiting workflow should stop: - -```python -await ai.cancel_hook("approve_contact_mothership", reason="client disconnected") -``` - -Cancellation emits a hook event with `status="cancelled"`. - -## Cleanup - -The runtime tracks hook labels for each run. When the run exits, it removes live -hooks and pending resolutions for those labels, then closes scoped Model Context -Protocol (MCP) connections. diff --git a/docs/ai-python/content/docs/core-framework/index.mdx b/docs/ai-python/content/docs/core-framework/index.mdx deleted file mode 100644 index d7f2830f..00000000 --- a/docs/ai-python/content/docs/core-framework/index.mdx +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Core Framework -description: Understand the internals of streams, agents, tools, hooks, and runtime behavior. -type: conceptual -summary: Learn how the core framework coordinates stream aggregation, agent loops, tools, hooks, history, adapters, and runtime state. ---- - -The core framework is the set of small pieces behind the public APIs. Providers -produce events, streams aggregate those events into messages, agents decide -when to call tools, and hooks suspend work until external input arrives. - -## Architecture overview - -The runtime has four main layers: - -- Providers translate `Message` lists and `Tool` schemas to remote APIs. -- `ai.stream` wraps provider events and builds the assistant message. -- `Agent.loop` runs the stream -> tool -> stream cycle. -- The runtime queue carries agent events, hook events, and partial tool output - to the consumer. - -## Data flow - -```python -messages = [ai.user_message("Ask the mothership for launch status.")] - -async with agent.run(model, messages) as stream: - async for event in stream: - ... - -updated_history = stream.messages -``` - -The flow is: - -1. The model receives prepared messages and tool schemas. -2. The stream yields text, reasoning, tool-call, built-in-tool, file, and usage - events. -3. The stream aggregates events into one assistant message. -4. The agent resolves tool calls, runs tools, appends tool results, and repeats. - -## Extension points - -- Use `params` for request-scoped provider options. -- Define `@ai.tool` functions for agent-executed tools. -- Use provider tool factories for provider-executed tools. -- Override `Agent.loop` when scheduling or history updates need custom logic. -- Add hooks when the loop needs external input. -- Use the AI SDK UI adapter to translate events to UI stream parts. - -## Internal state boundaries - -Messages are the durable boundary. Streams, tool runners, live hook futures, -and provider clients are runtime state. Persist `stream.messages`, not live -runtime objects. diff --git a/docs/ai-python/content/docs/core-framework/message-history.mdx b/docs/ai-python/content/docs/core-framework/message-history.mdx deleted file mode 100644 index bb2841d6..00000000 --- a/docs/ai-python/content/docs/core-framework/message-history.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Message History -description: Understand message parts, internal state, validation, repair, and replay. -type: conceptual -summary: Learn the invariants the framework maintains for model-ready message history. ---- - -Message history is the durable contract between your app, providers, tools, and -resume flows. - -## Message and part model - -Each message has a role and typed parts: - -```python -message = ai.user_message( - "Inspect this mothership diagram.", - ai.file_part(image_bytes, media_type="image/png"), -) -``` - -Common parts include text, reasoning, tool calls, tool results, provider tool -returns, hook state, and files. - -## Internal messages - -Hooks emit `role="internal"` messages with `HookPart` values. They are useful -for UI state and resume flows, but providers do not receive them. - -```python -if message.role == "internal": - hook = message.parts[0] -``` - -## Tool-call invariants - -Provider APIs expect every assistant tool call to have a matching tool result -before the next user or assistant message: - -```python -[ - ai.assistant_message(tool_call_part), - ai.tool_message(tool_result_part), -] -``` - -Duplicate tool-call IDs, duplicate result IDs, and orphaned tool results are -fatal integrity errors. - -## Automatic history repair - -Before provider calls, the framework prepares message history in `auto` mode. It -strips internal messages, removes non-model parts, repairs invalid tool args to -`{}`, and inserts error results for missing tool calls when possible. - -## Strict validation - -Use strict validation in tests or import pipelines when you want repairable -issues to raise: - -```python -from ai.types import integrity - - -integrity.prepare_messages(messages, mode="strict") -``` - -## Replay markers - -Replay markers are internal flags on assistant messages. They let a resumed -agent dispatch existing tool calls without another model request: - -```python -if messages[-1].replay: - async with ai.stream(model, messages) as stream: - ... -``` - -Replay flags are serialized when true and omitted when false. - -## Persisted history - -Persist Pydantic JSON, then restore with `Message.model_validate`: - -```python -encoded = [message.model_dump(mode="json") for message in stream.messages] -restored = [ai.messages.Message.model_validate(item) for item in encoded] -``` - -Persist messages after each completed or suspended run. Recreate live runtime -objects, providers, and hooks on the next request. Resume state such as replay -markers, cached tool results, and model-facing tool input is included when -present. diff --git a/docs/ai-python/content/docs/core-framework/meta.json b/docs/ai-python/content/docs/core-framework/meta.json deleted file mode 100644 index 05e8ea75..00000000 --- a/docs/ai-python/content/docs/core-framework/meta.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Core Framework", - "description": "Understand the internals of streams, agents, tools, hooks, and runtime behavior.", - "pages": [ - "streams", - "agent-loop", - "tool-dispatch", - "hooks", - "streaming-tools", - "message-history", - "adapters-and-providers" - ] -} diff --git a/docs/ai-python/content/docs/core-framework/streaming-tools.mdx b/docs/ai-python/content/docs/core-framework/streaming-tools.mdx deleted file mode 100644 index 72634a84..00000000 --- a/docs/ai-python/content/docs/core-framework/streaming-tools.mdx +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Streaming Tools -description: Understand async-generator tools and aggregation. -type: conceptual -summary: Learn how streaming tools emit partial output while producing a final model-facing result. ---- - -Async-generator tools yield values while they run. An aggregator turns those -values into the final tool result that the model sees on the next turn. - -## Async-generator tools - -Async-generator tools can stream partial output while they run. Use -`ai.StreamingTextTool` when yielded strings should be concatenated into the -tool result: - -```python -@ai.tool -async def draft_mothership_reply(topic: str) -> ai.StreamingTextTool: - """Draft a reply from the mothership.""" - yield "Consulting " - yield "the " - yield "mothership..." -``` - -## Partial tool results - -Partial yields appear as `ai.events.PartialToolCallResult` events. The model -sees the aggregated result on the next turn. - -## Aggregators - -An aggregator receives each yielded value, keeps a snapshot for consumers, and -converts that snapshot to model-facing input: - -```python -from collections.abc import AsyncGenerator -from typing import Annotated - -import ai - - -type Lines = Annotated[ - AsyncGenerator[str], - ai.agents.Aggregate(ai.agents.ConcatAggregator, delim="\n"), -] - - -@ai.tool -async def list_mothership_tasks() -> Lines: - """List pending mothership tasks.""" - yield "Calibrate antenna" - yield "Check orbit" -``` - -## Model-facing input - -`ToolResultPart.result` stores the rich snapshot. `ToolResultPart.get_model_input` -returns the value sent back to the model: - -```python -result_part = event.results[0] -print(result_part.result) -print(result_part.get_model_input()) -``` - -For most tools, those values are the same. For subagents, the result can contain -messages while the model input is the final assistant text. - -## Rich snapshots - -Aggregators can preserve more than text. `MessageAggregator` stores nested -messages from a subagent. The rich snapshot type is -`ai.types.messages.MessageBundle`: - -```python -if isinstance(event, ai.events.ToolCallResult): - result = event.results[0].result - if isinstance(result, ai.types.messages.MessageBundle): - print(result.messages[-1].text) -``` - -## Streaming text tools - -Use `ai.StreamingTextTool` when every yielded string should be concatenated: - -```python -@ai.tool -async def draft_mothership_reply(topic: str) -> ai.StreamingTextTool: - """Draft a reply from the mothership.""" - yield "The " - yield "mothership " - yield f"reports on {topic}." -``` - -## Status tools - -Use `ai.StreamingStatusTool[T]` when intermediate yields are progress updates -and the last yielded value is the final result: - -```python -@ai.tool -async def check_alignment() -> ai.StreamingStatusTool[str]: - """Check orbital alignment.""" - yield "opening channel" - yield "checking telemetry" - yield "alignment stable" -``` - -## Subagent tools - -Use `ai.SubAgentTool` when a tool delegates work to another agent: - -```python -@ai.tool -async def ask_mothership(topic: str) -> ai.SubAgentTool: - """Ask the mothership subagent.""" - subagent = ai.agent() - async with subagent.run( - model, - [ai.user_message(topic)], - ) as stream: - async for event in stream: - yield event -``` - -The parent stream receives the nested events. The parent model receives the -subagent's final assistant text. diff --git a/docs/ai-python/content/docs/core-framework/streams.mdx b/docs/ai-python/content/docs/core-framework/streams.mdx deleted file mode 100644 index a45c36ef..00000000 --- a/docs/ai-python/content/docs/core-framework/streams.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Streams -description: Understand stream events and aggregation. -type: conceptual -summary: Learn how provider events become an aggregated assistant message. ---- - -`ai.stream` turns provider events into a stateful `Stream` object. Iteration -returns events; the stream also keeps the in-progress assistant message. - -## Stream lifecycle - -```python -async with ai.stream(model, messages, tools=tools) as stream: - async for event in stream: - ... - -message = stream.message -``` - -On entry, the framework prepares message history and creates a provider request. -On exit, it closes the underlying async generator. - -## Event aggregation - -`Stream.__anext__` receives one provider event, updates `stream.message`, and -then returns a copy of the event with the current message attached. - -```python -async for event in stream: - print(event.kind, event.message.text) -``` - -## Text and reasoning blocks - -Text and reasoning use start, delta, and end events. Deltas append to the part -with the same block ID: - -```python -if isinstance(event, ai.events.TextDelta): - print(event.chunk, end="", flush=True) -elif isinstance(event, ai.events.ReasoningDelta): - record_reasoning(event.chunk) -``` - -## Tool-call blocks - -Function tool calls stream as `ToolStart`, `ToolDelta`, and `ToolEnd`. -`ToolEnd.tool_call` is the complete `ToolCallPart`: - -```python -if isinstance(event, ai.events.ToolEnd): - call = event.tool_call - print(call.tool_name, call.tool_args) -``` - -## Built-in tool blocks - -Provider-executed tools use separate built-in events. The host does not execute -these calls: - -```python -if isinstance(event, ai.events.BuiltinToolResult): - print(event.result.tool_name, event.result.result) -``` - -## File events - -Generated files arrive as `FileEvent` and become `FilePart` values on the -assistant message: - -```python -if isinstance(event, ai.events.FileEvent): - print(event.media_type, event.filename) -``` - -## Usage and provider metadata - -Usage and provider metadata are latest-wins fields. Events may carry them, and -the stream copies usage onto the assistant message: - -```python -if event.usage is not None: - print(event.usage) -``` - -## Replay streams - -When the last message has `replay=True`, `ai.stream` does not call the provider. -It emits synthetic replay tool-end events from the existing assistant message -so resume flows can dispatch the same tool calls again. diff --git a/docs/ai-python/content/docs/core-framework/tool-dispatch.mdx b/docs/ai-python/content/docs/core-framework/tool-dispatch.mdx deleted file mode 100644 index 22344e6a..00000000 --- a/docs/ai-python/content/docs/core-framework/tool-dispatch.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Tool Dispatch -description: Understand tool binding, validation, scheduling, and results. -type: conceptual -summary: Learn how tool schemas become executable calls and how tool results flow back into history. ---- - -Tool dispatch starts with a streamed `ToolCallPart` and ends with a -`ToolResultPart` in message history. - -## Tool schema creation - -`@ai.tool` inspects the async function signature and creates a Pydantic -validator plus a model-facing `Tool` declaration: - -```python -@ai.tool -async def contact_mothership(query: str) -> str: - """Contact the mothership for important decisions.""" - return "Soon." -``` - -The tool name is the function name. The docstring becomes the description. - -## Bound tool calls - -When the model emits a tool call, `context.resolve` binds the streamed -`ToolCallPart` to the registered `AgentTool`: - -```python -if isinstance(event, ai.events.ToolEnd): - tool_call = context.resolve(event.tool_call) -``` - -The bound call exposes `id`, `name`, `fn`, and validated `kwargs`. - -## Argument validation - -Arguments are JSON-decoded from `tool_args` and validated before the function -runs: - -```python -kwargs = tool_call.kwargs -``` - -Validation failures return an error tool result, so the agent can continue with -the error in history. - -## Concurrent scheduling - -`ToolRunner.schedule` starts each call in a task group. `ToolRunner.events()` -yields results as tasks finish: - -```python -tool_runner.schedule(context.resolve(event.tool_call)) -``` - -This lets multiple tool calls from one assistant turn run concurrently. - -## Tool result aggregation - -Each successful call creates a `ToolResultPart`. `ToolRunner.get_tool_message` -merges all collected results into one tool message: - -```python -message = tool_runner.get_tool_message() -context.add(message) -``` - -## Error results - -Tool exceptions are caught and converted to error results: - -```python -if isinstance(event, ai.events.ToolCallResult) and event.exception: - log_exception(event.exception) -``` - -The model receives a string error result. The event keeps the original -exception for logging. - -## Approval-gated dispatch - -Tools declared with `require_approval=True` are wrapped in an approval hook. -The call runs only after the hook resolves with `granted=True`: - -```python -@ai.tool(require_approval=True) -async def notify_mothership(message: str) -> str: - """Notify the mothership.""" - return f"Sent: {message}" -``` - -If the hook is denied, the agent returns an error tool result. If the run aborts -while the hook is pending, the pending result marks the history for replay. diff --git a/docs/ai-python/content/docs/index.mdx b/docs/ai-python/content/docs/index.mdx index 07f1c717..dbadf7c7 100644 --- a/docs/ai-python/content/docs/index.mdx +++ b/docs/ai-python/content/docs/index.mdx @@ -106,10 +106,10 @@ After iteration, `s.message`, `s.text`, `s.tool_calls`, `s.output`, and ## What's next -- **Core concepts**: Learn the primitives that shape the SDK. -- **Streaming**: Stream model responses and inspect events. -- **Agents**: Add tools, customize the loop, and handle approvals. -- **Samples**: Focused, single-file examples live in +- **Basics**: Learn the main workflows for providers, messages, streams, + tools, agents, hooks, and UI integrations. +- **Reference**: Look up public APIs by the names you import and call. +- **Examples**: Focused, single-file examples live in [`examples/`](https://github.com/vercel-labs/ai-python/tree/main/examples). - **End-to-end demos**: [`fastapi-vite`](https://github.com/vercel-labs/ai-python/tree/main/examples/fastapi-vite) diff --git a/docs/ai-python/content/docs/meta.json b/docs/ai-python/content/docs/meta.json index 54d6837f..91e946f5 100644 --- a/docs/ai-python/content/docs/meta.json +++ b/docs/ai-python/content/docs/meta.json @@ -5,6 +5,6 @@ "pages": [ "index", "basics", - "core-framework" + "reference" ] } diff --git a/docs/ai-python/content/docs/reference/agent.mdx b/docs/ai-python/content/docs/reference/agent.mdx new file mode 100644 index 00000000..5083b60f --- /dev/null +++ b/docs/ai-python/content/docs/reference/agent.mdx @@ -0,0 +1,80 @@ +--- +title: "ai.agent and Agent" +description: Create agents and run the default agent loop. +type: reference +summary: Reference for ai.agent, Agent, Agent.run, Agent.loop, and AgentStream. +--- + +`ai.agent` creates an `Agent`. An agent streams model output, dispatches Python +tools, appends tool results to history, and repeats until the model returns a +final assistant message. + +```python +agent = ai.agent(tools=[contact_mothership]) +``` + +## Function + +```python +ai.agent(*, tools=None) -> ai.Agent +``` + +`tools` accepts `AgentTool` values from `@ai.tool` and schema-only `ai.Tool` +values for provider-executed tools. + +## Agent + +```python +agent = ai.Agent(tools=[...]) +agent.tools +``` + +`agent.tools` returns a copy of registered executable tools. + +## Agent.run + +```python +async with agent.run( + model, + messages, + output_type=None, + params=None, +) as stream: + async for event in stream: + ... +``` + +Arguments: + +- `model`: `ai.Model`. +- `messages`: initial list of `ai.messages.Message`. +- `output_type`: optional Pydantic model for final JSON output. +- `params`: optional `ai.InferenceRequestParams`. + +## AgentStream + +`Agent.run` yields an `AgentStream`. + +```python +stream.context +stream.messages +stream.output +``` + +`stream.messages` is the updated message history. `stream.output` reads the +final assistant message. With no `output_type`, it returns text. + +## Agent.loop + +Override `Agent.loop(context)` to customize control flow. The default loop uses +`ai.stream`, `ToolRunner`, `Context.resolve`, and `Context.add`. + +```python +class CustomAgent(ai.Agent): + async def loop(self, context: ai.Context): + while context.keep_running(): + ... +``` + +Keep messages as the durable boundary. Streams, tool runners, hook futures, and +provider clients are runtime state. diff --git a/docs/ai-python/content/docs/reference/ai-sdk-ui.mdx b/docs/ai-python/content/docs/reference/ai-sdk-ui.mdx new file mode 100644 index 00000000..a2ad87db --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai-sdk-ui.mdx @@ -0,0 +1,68 @@ +--- +title: "ai.agents.ui.ai_sdk" +description: Reference for AI SDK UI message and SSE adapters. +type: reference +summary: Reference for to_messages, to_sse, to_stream, to_ui_messages, approvals, headers, and UIMessage. +--- + +`ai.agents.ui.ai_sdk` converts between AI SDK UI message streams and the Python +runtime. + +## UIMessage + +```python +class ChatRequest(pydantic.BaseModel): + messages: list[ai.agents.ui.ai_sdk.UIMessage] +``` + +Use `UIMessage` as the request model for AI SDK UI clients. + +## to_messages + +```python +messages, approvals = ai.agents.ui.ai_sdk.to_messages(ui_messages) +``` + +Converts UI messages into runtime messages and extracts approval responses. + +## apply_approvals + +```python +ai.agents.ui.ai_sdk.apply_approvals(approvals) +``` + +Registers extracted approval responses before an agent run resumes. + +## to_sse + +```python +async for chunk in ai.agents.ui.ai_sdk.to_sse(agent_stream): + yield chunk +``` + +Converts agent events to Server-Sent Events for AI SDK UI. + +## to_stream + +```python +async for part in ai.agents.ui.ai_sdk.to_stream(agent_stream): + yield part +``` + +Converts agent events to UI stream parts without SSE framing. + +## to_ui_messages + +```python +ui_messages = ai.agents.ui.ai_sdk.to_ui_messages(messages) +``` + +Converts stored runtime messages back to AI SDK UI messages. + +## Headers + +```python +headers = ai.agents.ui.ai_sdk.UI_MESSAGE_STREAM_HEADERS +``` + +Return these headers on streamed AI SDK UI responses. diff --git a/docs/ai-python/content/docs/reference/events.mdx b/docs/ai-python/content/docs/reference/events.mdx new file mode 100644 index 00000000..55207bf8 --- /dev/null +++ b/docs/ai-python/content/docs/reference/events.mdx @@ -0,0 +1,96 @@ +--- +title: "ai.events" +description: Reference for stream, agent, tool, and hook events. +type: reference +summary: Reference for ai.events event classes and aggregation helpers. +--- + +Streams and agents yield event objects from `ai.events`. Events are Pydantic +models. + +## Model Stream Events + +Text: + +- `StreamStart` +- `TextStart` +- `TextDelta` +- `TextEnd` +- `StreamEnd` + +Reasoning: + +- `ReasoningStart` +- `ReasoningDelta` +- `ReasoningEnd` + +Python tool calls: + +- `ToolStart` +- `ToolDelta` +- `ToolEnd` + +Provider-executed tools: + +- `BuiltinToolStart` +- `BuiltinToolDelta` +- `BuiltinToolEnd` +- `BuiltinToolResult` + +Files and hooks: + +- `FileEvent` +- `HookSuspension` +- `HookResolution` + +## Common Event Fields + +Model stream events inherit from `BaseEvent`: + +```python +event.message +event.usage +event.provider_metadata +``` + +`event.message` is the current aggregated assistant message. + +## Agent Events + +Agents can also emit: + +- `ToolCallResult` +- `PartialToolCallResult` +- `HookEvent` + +`ToolCallResult` carries the tool result message and result parts. +`PartialToolCallResult` carries values yielded by streaming tools and +`yield_from`. `HookEvent` carries an internal hook message and `HookPart`. + +## Replay Message Events + +```python +async for event in ai.events.replay_message_events(message): + ... +``` + +`replay_message_events` synthesizes stream events from a complete `Message`. +Use it when cached, durable, or test messages need to flow through code that +expects stream events. + +## Aggregator + +`ai.events.Aggregator[Item, Result, ModelInput]` is the interface used by +streaming tools and `yield_from`. + +```python +class MyAggregator(ai.events.Aggregator[Item, Result, ModelInput]): + def feed(self, item: Item) -> None: ... + def snapshot(self) -> Result: ... + + @classmethod + def to_model_input(cls, snapshot: Result) -> ModelInput: ... +``` + +`snapshot()` is the rich value stored in tool results. `get_model_input()` is +the value sent back to the model. diff --git a/docs/ai-python/content/docs/reference/generate.mdx b/docs/ai-python/content/docs/reference/generate.mdx new file mode 100644 index 00000000..66a8911f --- /dev/null +++ b/docs/ai-python/content/docs/reference/generate.mdx @@ -0,0 +1,61 @@ +--- +title: "ai.generate" +description: Generate non-streaming media responses. +type: reference +summary: Reference for ai.generate and media generation params. +--- + +`ai.generate` calls non-streaming generation APIs, such as image and video +models, and returns a `Message`. + +```python +result = await ai.generate( + model, + [ai.user_message("A watercolor mothership over a quiet city.")], + ai.ImageParams(n=1, aspect_ratio="16:9"), +) +``` + +## Function + +```python +await ai.generate(model, messages, params) +``` + +## Arguments + +- `model`: `ai.Model`. +- `messages`: list of `ai.messages.Message`. +- `params`: `ai.ImageParams` or `ai.VideoParams`. + +## ImageParams + +```python +ai.ImageParams( + n=1, + size=None, + aspect_ratio=None, + seed=None, + provider_options={}, +) +``` + +## VideoParams + +```python +ai.VideoParams( + n=1, + aspect_ratio=None, + resolution=None, + duration=None, + fps=None, + seed=None, + provider_options={}, +) +``` + +## Return Value + +`ai.generate` returns an assistant `Message`. Read generated files through +`message.files` or use the normal message helpers for text, reasoning, and +metadata. diff --git a/docs/ai-python/content/docs/reference/hooks.mdx b/docs/ai-python/content/docs/reference/hooks.mdx new file mode 100644 index 00000000..7840e1ab --- /dev/null +++ b/docs/ai-python/content/docs/reference/hooks.mdx @@ -0,0 +1,67 @@ +--- +title: "ai.hook, resolve_hook, and cancel_hook" +description: Suspend, resolve, abort, and cancel hooks. +type: reference +summary: Reference for ai.hook, resolve_hook, abort_pending_hook, cancel_hook, and HookEvent. +--- + +Hooks suspend an agent workflow until external input arrives. Tool approvals use +the same hook mechanism. + +## ai.hook + +```python +approval = await ai.hook( + "approve_contact_mothership", + payload=ai.tools.ToolApproval, + metadata={"tool": "contact_mothership"}, +) +``` + +Arguments: + +- `label`: unique hook identifier. +- `payload`: Pydantic model class used to validate the resolution. +- `metadata`: optional data surfaced to clients. + +The return value is an instance of `payload`. + +## resolve_hook + +```python +ai.resolve_hook(label, data, payload=None) +``` + +`data` can be a dict, a Pydantic model, or an exception. If a live hook exists, +it resolves immediately. If no live hook exists, the resolution is stored and +consumed by the next matching `ai.hook` call. + +## abort_pending_hook + +```python +ai.abort_pending_hook(hook_part) +``` + +Aborts the hook identified by `hook_part.hook_id` by registering a +pending-hook exception. This is the common serverless resume pattern after a +pending hook event is persisted. + +## cancel_hook + +```python +await ai.cancel_hook(label, reason="client disconnected") +``` + +Cancels a live hook and emits a cancelled hook event. It raises `ValueError` +when no hook with that label is currently pending. + +## Events and Messages + +Hooks emit `ai.events.HookEvent`. The event message has role `internal` and +contains a `HookPart` with: + +- `hook_id` +- `hook_type` +- `status`: `pending`, `resolved`, or `cancelled` +- `metadata` +- `resolution` diff --git a/docs/ai-python/content/docs/reference/index.mdx b/docs/ai-python/content/docs/reference/index.mdx new file mode 100644 index 00000000..0f651871 --- /dev/null +++ b/docs/ai-python/content/docs/reference/index.mdx @@ -0,0 +1,21 @@ +--- +title: Reference +description: Public API reference for the AI SDK for Python. +type: reference +summary: Look up public APIs by the names you import and call. +--- + +Reference pages are organized around public APIs. Use Basics for workflows and +this section for call shapes, return values, and object fields. + +## API groups + +- `ai.stream`, `ai.Stream`, `ai.generate`, and `ai.probe` +- `ai.agent`, `ai.Agent`, `Agent.run`, and `Agent.loop` +- `@ai.tool`, `AgentTool`, streaming tool aliases, and tool result helpers +- `ToolRunner`, `ToolCall`, and `Context` +- `ai.hook`, `resolve_hook`, `abort_pending_hook`, and `cancel_hook` +- `Message`, message parts, and message builders +- `ai.events` +- `get_model`, `Model`, `get_provider`, and `Provider` +- `ai.agents.ui.ai_sdk` diff --git a/docs/ai-python/content/docs/reference/messages.mdx b/docs/ai-python/content/docs/reference/messages.mdx new file mode 100644 index 00000000..bb13e1b4 --- /dev/null +++ b/docs/ai-python/content/docs/reference/messages.mdx @@ -0,0 +1,102 @@ +--- +title: "Message and message builders" +description: Reference for Message, message parts, and message builder helpers. +type: reference +summary: Reference for Message, parts, builders, serialization, and message history invariants. +--- + +Messages are Pydantic models. They are the durable state shared by model calls, +agents, tools, UI adapters, and resume flows. + +## Message + +```python +message.role +message.parts +message.id +message.turn_id +message.usage +message.provider_metadata +message.replay +``` + +Roles are `user`, `assistant`, `system`, `tool`, and `internal`. + +## Convenience Properties + +```python +message.text +message.reasoning +message.tool_calls +message.tool_results +message.builtin_tool_calls +message.builtin_tool_returns +message.files +message.images +message.videos +message.get_output(output_type=None) +``` + +`get_output()` returns text by default. With a Pydantic model, it validates the +message text as JSON and returns that model. + +## Builders + +```python +ai.system_message("...") +ai.user_message("...", ai.file_part(data, media_type="image/png")) +ai.assistant_message("...") +ai.tool_message(tool_call_id="tc_1", result="done", tool_name="lookup") +``` + +Part builders: + +```python +ai.text_part("hello") +ai.file_part(data, media_type="image/png", filename="image.png") +ai.thinking("reasoning text") +ai.content_output("caption", ai.file_part(png_bytes, media_type="image/png")) +ai.tool_result_part("tc_1", result={"ok": True}, tool_name="lookup") +``` + +## Parts + +Common message parts are: + +- `TextPart` +- `FilePart` +- `ReasoningPart` +- `ToolCallPart` +- `ToolResultPart` +- `BuiltinToolCallPart` +- `BuiltinToolReturnPart` +- `HookPart` + +`ToolResultPart.get_model_input()` returns the value sent back to the model. For +most tools this is the same as `result`. Aggregator-backed tools can store a +rich `result` while sending a simpler model-facing value. + +## Serialization + +```python +encoded = [message.model_dump(mode="json") for message in messages] +restored = [ai.messages.Message.model_validate(item) for item in encoded] +``` + +Persist messages after completed or suspended runs. Recreate providers, hooks, +streams, and other live runtime objects on the next request. + +## History Preparation + +Before provider calls, the SDK prepares message history. It strips internal +messages, removes non-model parts, repairs invalid tool args to `{}`, and +inserts error results for missing tool calls when possible. + +Use strict validation when you want repairable issues to raise: + +```python +from ai.types import integrity + + +integrity.prepare_messages(messages, mode="strict") +``` diff --git a/docs/ai-python/content/docs/reference/meta.json b/docs/ai-python/content/docs/reference/meta.json new file mode 100644 index 00000000..05f1cff0 --- /dev/null +++ b/docs/ai-python/content/docs/reference/meta.json @@ -0,0 +1,16 @@ +{ + "title": "Reference", + "description": "API reference for public AI SDK for Python APIs.", + "pages": [ + "stream", + "generate", + "agent", + "tool", + "tool-runner", + "hooks", + "messages", + "events", + "models-and-providers", + "ai-sdk-ui" + ] +} diff --git a/docs/ai-python/content/docs/reference/models-and-providers.mdx b/docs/ai-python/content/docs/reference/models-and-providers.mdx new file mode 100644 index 00000000..953cf8f3 --- /dev/null +++ b/docs/ai-python/content/docs/reference/models-and-providers.mdx @@ -0,0 +1,119 @@ +--- +title: "get_model, Model, get_provider, and Provider" +description: Reference for get_model, Model, get_provider, Provider, params, and probe. +type: reference +summary: Reference for model resolution, provider configuration, provider APIs, and request params. +--- + +Models identify what to call. Providers own credentials, clients, endpoints, +model listing, and wire translation. + +## get_model + +```python +model = ai.get_model("anthropic/claude-sonnet-4") +model = ai.get_model("openai:gpt-5") +model = ai.get_model() +``` + +Unprefixed IDs route through AI Gateway. Calling `get_model()` with no argument +reads `AI_SDK_DEFAULT_MODEL`. + +## Model + +```python +model = ai.Model("gpt-5", provider=provider) +model.id +model.provider +model.protocol +model.with_protocol(protocol) +``` + +`Model` is a lightweight reference. It does not own network state. + +## get_provider + +```python +provider = ai.get_provider("openai") +provider = ai.get_provider( + "openai", + base_url="http://localhost:1234/v1", + api_key="your_access_token_here", +) +``` + +Known providers include AI Gateway, OpenAI-compatible providers, and +Anthropic-compatible providers. + +## Provider + +Provider instances expose: + +```python +provider.name +provider.base_url +provider.default_base_url +provider.api_key +provider.api_key_env +provider.base_url_env +provider.headers +provider.client +provider.is_configured() +await provider.list_models() +await provider.probe(model) +await provider.aclose() +``` + +`provider.stream(...)` and `provider.generate(...)` are usually called through +`ai.stream` and `ai.generate`. + +## probe + +```python +await ai.probe(model) +``` + +`probe` raises a provider error unless the provider is reachable and the model +exists. + +## InferenceRequestParams + +Pass request options to `ai.stream` or `Agent.run` with `params=`. + +```python +params = ai.InferenceRequestParams().with_temperature(0) + +async with ai.stream(model, messages, params=params) as stream: + ... +``` + +Common param groups include: + +- `ReasoningParams` +- `ToolCallingParams` +- `OutputParams` +- `CacheParams` +- `RoutingParams` +- `ProviderServiceParams` +- `ContextManagementParams` + +Use `with_provider_params(...)` for typed provider-specific params. + +## Custom Providers + +Add a provider by subclassing `ai.Provider`, setting `handles`, and +implementing provider-specific behavior. + +```python +class AcmeProvider(ai.Provider[AcmeClient]): + handles = ("acme",) + + async def list_models(self) -> list[str]: + ... + + async def probe(self, model: ai.Model) -> None: + ... +``` + +Protocols translate messages, tools, params, and generated files to provider +wire formats. diff --git a/docs/ai-python/content/docs/reference/stream.mdx b/docs/ai-python/content/docs/reference/stream.mdx new file mode 100644 index 00000000..f3566ae9 --- /dev/null +++ b/docs/ai-python/content/docs/reference/stream.mdx @@ -0,0 +1,81 @@ +--- +title: "ai.stream and Stream" +description: Stream model responses and inspect the aggregated result. +type: reference +summary: Reference for ai.stream, Stream, stream events, aggregation, and replay. +--- + +`ai.stream` calls a model and returns an async context manager whose value is a +`Stream`. + +```python +async with ai.stream(model, messages, tools=tools) as stream: + async for event in stream: + ... +``` + +## Function + +```python +ai.stream( + model, + messages, + *, + tools=None, + output_type=None, + params=None, +) +``` + +You can also pass `context=` from an agent loop: + +```python +async with ai.stream(context=context) as stream: + ... +``` + +Pass either `model` and `messages`, or `context=`, not both. + +## Arguments + +- `model`: `ai.Model`. +- `messages`: list of `ai.messages.Message`. +- `tools`: optional model-facing `ai.Tool` declarations. +- `output_type`: optional Pydantic model for JSON output validation. +- `params`: optional `ai.InferenceRequestParams`. + +## Stream + +`Stream` is an async iterator of `ai.events.Event` values. It aggregates events +into an assistant message while you iterate. + +```python +message = stream.message +text = stream.text +tool_calls = stream.tool_calls +usage = stream.usage +output = stream.output +``` + +`stream.output` returns text by default. When `output_type` is set, it validates +the final text as JSON and returns the parsed Pydantic model. + +## Event Aggregation + +Text and reasoning blocks are built from start, delta, and end events. Tool +calls are built from `ToolStart`, `ToolDelta`, and `ToolEnd`. Provider-executed +tools use built-in tool events. Generated files arrive as `FileEvent`. + +Each yielded event has the current aggregated `event.message`. + +## Replay + +If the last input message has `replay=True`, `ai.stream` does not call the +provider. It emits replay tool-end events from the existing assistant message +so resumable agent flows can dispatch the same tool calls again. + +## Errors + +If the provider stream ends before a finish event, iteration raises +`ai.errors.ProviderIncompleteResponseError`. The partial message is still on +`stream.message`. diff --git a/docs/ai-python/content/docs/reference/tool-runner.mdx b/docs/ai-python/content/docs/reference/tool-runner.mdx new file mode 100644 index 00000000..a6c7e36e --- /dev/null +++ b/docs/ai-python/content/docs/reference/tool-runner.mdx @@ -0,0 +1,85 @@ +--- +title: "ToolRunner, ToolCall, and Context" +description: Resolve, schedule, and collect tool calls in custom loops. +type: reference +summary: Reference for ToolRunner, ToolCall, ai.agents.BoundToolCall, ai.agents.GatedToolCall, and Context. +--- + +Custom loops use `Context` to resolve model tool calls and `ToolRunner` to run +them. + +## Context + +`Context` contains the state for one agent run. + +```python +context.model +context.messages +context.tools +context.output_type +context.params +``` + +## Context.keep_running + +```python +while context.keep_running(): + ... +``` + +`keep_running()` returns `True` while the last message still needs work. A final +assistant message stops the loop. A pending hook result also stops the loop +until the hook resolves. + +## Context.resolve + +```python +tool_call = context.resolve(event.tool_call) +tool_calls = context.resolve(message.tool_calls) +``` + +`resolve` converts `ToolCallPart` values into callable `ToolCall` objects. If +the registered tool has `require_approval=True`, the returned call is wrapped +with approval behavior. + +## Context.add + +```python +context.add(stream.message) +context.add(tool_runner.get_tool_message()) +``` + +`add` appends messages to history. Replay-marked assistant messages are skipped +to avoid duplicate history during resume flows. + +## ToolCall + +`ToolCall` is a protocol for executable tool calls. + +```python +tool_call.id +tool_call.name +tool_call.fn +tool_call.kwargs +result = await tool_call() +``` + +`ai.agents.BoundToolCall` is the default implementation. +`ai.agents.GatedToolCall` wraps another tool call with an approval hook. + +## ToolRunner + +```python +async with ai.ToolRunner() as runner: + runner.schedule(tool_call) + async for result in runner.events(): + ... + message = runner.get_tool_message() +``` + +`schedule` starts the call in the runner's task group. `events()` yields +`ToolCallResult` values as calls finish. `get_tool_message()` merges collected +results into one `role="tool"` message. + +Use `add_result(result)` when a custom loop executes a tool itself but still +wants the runner to aggregate the result message. diff --git a/docs/ai-python/content/docs/reference/tool.mdx b/docs/ai-python/content/docs/reference/tool.mdx new file mode 100644 index 00000000..cf21fb1d --- /dev/null +++ b/docs/ai-python/content/docs/reference/tool.mdx @@ -0,0 +1,79 @@ +--- +title: "@ai.tool and AgentTool" +description: Define executable tools and tool result values. +type: reference +summary: Reference for @ai.tool, AgentTool, streaming tool aliases, and tool result helpers. +--- + +`@ai.tool` turns an async Python function into an executable `AgentTool` plus a +model-facing `ai.Tool` declaration. + +```python +@ai.tool +async def contact_mothership(query: str) -> str: + """Contact the mothership.""" + return "Soon." +``` + +## Decorator + +```python +@ai.tool +async def name(...) -> Result: ... + +@ai.tool(require_approval=True) +async def name(...) -> Result: ... + +@ai.tool(aggregator=...) +async def name(...) -> AsyncGenerator[Item]: ... +``` + +The function name becomes the tool name. The docstring becomes the tool +description. The function signature becomes a Pydantic validator and JSON +schema. + +## AgentTool + +```python +tool.name +tool.tool +tool.fn +tool.validator +tool.require_approval +``` + +Pass `AgentTool` values to `ai.agent(tools=[...])`. + +## Streaming Tools + +Async-generator tools can yield partial output while they run. The agent emits +`ai.events.PartialToolCallResult` events for yielded values. + +Use built-in return aliases for common aggregation behavior: + +- `ai.StreamingTextTool`: concatenate yielded strings. +- `ai.StreamingStatusTool[T]`: treat intermediate yields as status updates and + the last yielded value as the final result. +- `ai.SubAgentTool`: forward nested agent events and use the nested final text + as model input. + +Custom aggregators use `ai.agents.Aggregate` with an +`ai.events.Aggregator` implementation. + +## Tool Result Helpers + +```python +ai.tool_result(tool_call_id="tc_1", tool_name="lookup", result={"ok": True}) +ai.pending_tool_result(hook_part, tool_call_id="tc_1", tool_name="lookup") +ai.tool_message(tool_call_id="tc_1", tool_name="lookup", result="done") +ai.tool_result_part("tc_1", tool_name="lookup", result="done") +``` + +`tool_result` creates a `ToolCallResult` event. `tool_message` and +`tool_result_part` create message-layer values. + +## Provider Tools + +Schema-only and provider-executed tools are `ai.Tool` values. Pass them to +`ai.stream(..., tools=[...])` or to an agent when the provider should receive +the declaration. From ecba635b87c4d73175dbb572ceaa69d282222b21 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 09:25:37 -0700 Subject: [PATCH 03/19] Update the skills directory structure --- skills/ai/SKILL.md | 498 ++------------------------- skills/ai_sdk_ui_adapter/SKILL.md | 63 ++++ skills/custom_loop/SKILL.md | 41 +++ skills/custom_provider/SKILL.md | 84 +++++ skills/durable_execution/SKILL.md | 44 +++ skills/serverless_execution/SKILL.md | 57 +++ skills/streaming_tools/SKILL.md | 53 +++ skills/subagents/SKILL.md | 40 +++ 8 files changed, 411 insertions(+), 469 deletions(-) create mode 100644 skills/ai_sdk_ui_adapter/SKILL.md create mode 100644 skills/custom_loop/SKILL.md create mode 100644 skills/custom_provider/SKILL.md create mode 100644 skills/durable_execution/SKILL.md create mode 100644 skills/serverless_execution/SKILL.md create mode 100644 skills/streaming_tools/SKILL.md create mode 100644 skills/subagents/SKILL.md diff --git a/skills/ai/SKILL.md b/skills/ai/SKILL.md index ec79a2f3..46a277d7 100644 --- a/skills/ai/SKILL.md +++ b/skills/ai/SKILL.md @@ -1,507 +1,67 @@ --- name: ai -description: Python `ai` SDK — models, providers, streams, events, tools, agents, hooks, MCP, AI SDK UI, structured output, and media generation +description: Use for Python ai SDK basics: models, messages, streaming, tools, agents, and the minimal happy path. --- # ai -Use this skill when working with the Python `ai` SDK. +Install with `uv add ai`. -```bash -uv add ai -``` - -Direct OpenAI-compatible and Anthropic-compatible providers require optional -extras: `uv add "ai[openai]"` or `uv add "ai[anthropic]"`. AI Gateway works -with the base package. - -```python -import ai -``` - -## Quick start - -```python -import asyncio -import ai - - -@ai.tool -async def get_weather(city: str) -> str: - """Get current weather for a city.""" - return f"Sunny, 72F in {city}" - - -async def main() -> None: - model = ai.get_model("gateway:anthropic/claude-sonnet-4") - agent = ai.agent(tools=[get_weather]) - - messages = [ - ai.system_message("You are a helpful weather assistant."), - ai.user_message("What's the weather in Tokyo?"), - ] - - 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) - - print(stream.output) - - -if __name__ == "__main__": - asyncio.run(main()) -``` - -`ai.stream(...)` and `agent.run(...)` are async context managers. Iterate events -inside the context. After iteration, read final state from the stream object. - -## Models and providers - -```python -model = ai.get_model() # reads AI_SDK_DEFAULT_MODEL -model = ai.get_model("anthropic/claude-sonnet-4") # unprefixed: gateway route -model = ai.get_model("gateway:anthropic/claude-sonnet-4") -model = ai.get_model("openai:gpt-5.4") # direct provider route -model = ai.get_model("anthropic:claude-sonnet-4-6") -``` - -- Gateway credentials use `AI_GATEWAY_API_KEY`. -- Direct providers use provider-specific env vars such as `OPENAI_API_KEY` and - `ANTHROPIC_API_KEY`. -- Use `ai.get_provider(...)` when you need a custom base URL, API key, headers, - or client. -- Use `await ai.probe(model)` to check credentials and model availability. - -```python -provider = ai.get_provider( - "openai", - base_url="http://localhost:1234/v1", - api_key="your_access_token_here", -) -model = ai.Model("local-model", provider=provider) - -models = await ai.get_provider("anthropic").list_models() -``` - -Request-scoped provider options go through `params`: - -```python -params = { - "providerOptions": { - "gateway": {"sort": "cost"}, - "anthropic": {"speed": "fast"}, - } -} - -async with ai.stream(model, messages, params=params) as stream: - async for event in stream: - ... -``` - -## Messages and events - -Messages are Pydantic models with typed parts. Use builders for common roles -and parts: - -```python -ai.system_message("Be concise.") -ai.user_message("Describe this image:", ai.file_part(image_bytes, media_type="image/png")) -ai.assistant_message(ai.thinking("scratchpad"), "Final answer") -ai.tool_result_part("tc-1", result={"temp": 72}, tool_name="get_weather") -ai.tool_message(tool_call_id="tc-1", result=72, tool_name="get_weather") -``` - -Common message properties: - -- `message.text`, `message.reasoning`. -- `message.tool_calls`, `message.tool_results`. -- `message.builtin_tool_calls`, `message.builtin_tool_returns`. -- `message.files`, `message.images`, `message.videos`. -- `message.get_output()` or `message.get_output(MyModel)`. +Use `import ai`. -Streams and agents yield event objects from `ai.events`: +Use gateway model IDs unless you need a direct provider: ```python -async with ai.stream(model, messages, tools=tools) as stream: - async for event in stream: - if isinstance(event, ai.events.TextDelta): - print(event.chunk, end="", flush=True) - elif isinstance(event, ai.events.ToolEnd): - print(event.tool_call.tool_name, event.tool_call.tool_args) - elif isinstance(event, ai.events.ToolCallResult): - for result in event.results: - print(result.tool_name, result.result) - elif isinstance(event, ai.events.HookEvent): - print(event.hook.hook_id, event.hook.status) - elif isinstance(event, ai.events.PartialToolCallResult): - print(event.label, event.value) +model = ai.get_model("anthropic/claude-sonnet-4") ``` -After iteration: +Direct providers need extras: -```python -stream.message # final assistant message for ai.stream -stream.messages # updated agent history for agent.run -stream.text # text output for ai.stream -stream.output # text or parsed Pydantic output -stream.tool_calls # function tool calls from ai.stream -stream.usage # latest reported usage +```bash +uv add "ai[openai]" +uv add "ai[anthropic]" ``` -If a provider stream ends before its finish event, iteration raises -`ai.errors.ProviderIncompleteResponseError`. The partial message is still on -the stream object. - -Serialize and restore history with Pydantic JSON: +Messages are typed Python objects: ```python -encoded = [message.model_dump(mode="json") for message in stream.messages] -restored = [ai.messages.Message.model_validate(item) for item in encoded] +messages = [ + ai.system_message("Be concise."), + ai.user_message("Write a haiku about rain."), +] ``` -## Direct streaming - -Use `ai.stream` when you want one model response and will handle any function -tool calls yourself: +For one model call, use `ai.stream`: ```python -async with ai.stream(model, messages, tools=[get_weather.tool]) as stream: +async with ai.stream(model, messages) as stream: async for event in stream: if isinstance(event, ai.events.TextDelta): print(event.chunk, end="", flush=True) -for call in stream.tool_calls: - print(call.tool_name, call.tool_args) -``` - -Use structured output with a Pydantic model: - -```python -import pydantic - - -class Forecast(pydantic.BaseModel): - city: str - temperature: float - - -async with ai.stream(model, messages, output_type=Forecast) as stream: - async for event in stream: - ... - -forecast = stream.output -``` - -## Tools - -A function tool is an async Python function decorated with `@ai.tool`. The -function name becomes the tool name, the docstring becomes the description, and -the signature becomes a Pydantic-validated JSON schema. - -```python -@ai.tool -async def scan_sector(sector: str, depth: int = 1) -> str: - """Scan a sector at the requested depth.""" - return f"{sector}: clear at depth {depth}" -``` - -Use schema-only tools with `ai.stream` when the SDK should not execute them: - -```python -tool = ai.Tool( - kind="function", - name="get_weather", - spec=ai.tools.ToolSpec( - description="Get current weather for a city.", - params={ - "type": "object", - "properties": {"city": {"type": "string"}}, - "required": ["city"], - }, - ), -) -``` - -Provider-executed tools run outside your process: - -```python -tools = [ai.providers.anthropic.tools.web_search(max_uses=3)] - -async with ai.stream(model, messages, tools=tools) as stream: - async for event in stream: - if isinstance(event, ai.events.BuiltinToolResult): - print(event.result.tool_name, event.result.result) -``` - -Tool validation failures and exceptions become `ToolCallResult` events with -error result parts. The original exception is on `event.exception` for logging. - -```python -if isinstance(event, ai.events.ToolCallResult) and event.exception: - log_exception(event.exception) +answer = stream.output +messages.append(stream.message) ``` -## Streaming tools - -Async-generator tools yield partial values while they run. An aggregator turns -those values into the final tool result the model sees. +For Python tools, use an agent: ```python @ai.tool -async def draft_reply(topic: str) -> ai.StreamingTextTool: - """Draft a reply.""" - yield "Checking " - yield f"records for {topic}." -``` - -```python -@ai.tool -async def fetch(url: str) -> ai.StreamingStatusTool[str]: - """Fetch a URL with status updates.""" - yield "connecting" - yield "downloading" - yield body # last yield is the tool result -``` - -```python -@ai.tool -async def research(topic: str) -> ai.SubAgentTool: - """Research a topic with a subagent.""" - subagent = ai.agent(tools=[...]) - async with subagent.run(model, [ai.user_message(topic)]) as stream: - async for event in stream: - yield event -``` - -For custom aggregation, annotate an async-generator return type with -`Annotated[AsyncGenerator[T], ai.agents.Aggregate(...)]`. Built-in -aggregators: `ai.agents.ConcatAggregator`, `ai.agents.LastAggregator`, and -`ai.agents.MessageAggregator`. - -## Agents - -Use an agent when the SDK should execute Python tools, append tool results, and -continue until the assistant returns a final answer. +async def get_weather(city: str) -> str: + """Get the weather for a city.""" + return "Sunny" -```python agent = ai.agent(tools=[get_weather]) -async with agent.run(model, messages) as stream: - async for event in stream: +async with agent.run(model, messages) as run: + async for event in run: if isinstance(event, ai.events.TextDelta): print(event.chunk, end="", flush=True) -history = stream.messages -answer = stream.output -``` - -Pass structured output and provider params through `agent.run`: - -```python -async with agent.run( - model, - [ai.user_message("Return a JSON forecast.")], - output_type=Forecast, - params={"temperature": 0}, -) as stream: - async for event in stream: - ... - -forecast = stream.output -``` - -## Custom agent loops - -Subclass `ai.Agent` and override `loop` for custom scheduling, routing, -logging, persistence, or approval logic. - -```python -from collections.abc import AsyncGenerator - - -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 stream, - ai.ToolRunner() as tool_runner, - ): - async for event in ai.util.merge(stream, tool_runner.events()): - yield event - - if isinstance(event, ai.events.ToolEnd): - tool_call = context.resolve(event.tool_call) - tool_runner.schedule(tool_call) - - context.add(stream.message) - context.add(tool_runner.get_tool_message()) -``` - -Loop helpers: `context.model`, `context.messages`, `context.tools`, -`context.output_type`, `context.params`, `context.resolve(...)`, -`context.keep_running()`, and `context.add(...)`. - -## Multi-agent - -Use `ai.SubAgentTool` for agent-as-tool workflows. Use `ai.yield_from(...)` -inside custom loops to fan out streams and forward nested events as -`PartialToolCallResult` values with labels. - -```python -async with ( - researcher.run(model, research_messages) as research_stream, - analyst.run(model, analyst_messages) as analyst_stream, -): - research_text, analyst_text = await asyncio.gather( - ai.yield_from( - research_stream, - label="researcher", - aggregator=ai.agents.MessageAggregator, - ), - ai.yield_from( - analyst_stream, - label="analyst", - aggregator=ai.agents.MessageAggregator, - ), - ) -``` - -Route labels in the consumer: - -```python -if isinstance(event, ai.events.PartialToolCallResult): - if event.label == "researcher": - route_research(event.value) -``` - -## Hooks - -Hooks are runtime suspension points. Tool approvals are the built-in workflow. - -```python -@ai.tool(require_approval=True) -async def delete_file(path: str) -> str: - """Delete a file.""" - ... -``` - -The default loop gates each call behind an approval hook with label -`approve_{tool_call_id}` and payload `ai.tools.ToolApproval`. - -```python -async with agent.run(model, messages) as stream: - async for event in stream: - if isinstance(event, ai.events.HookEvent) and event.hook.status == "pending": - ai.resolve_hook( - event.hook.hook_id, - ai.tools.ToolApproval(granted=True, reason="approved"), - ) -``` - -Resolve with `granted=False` to deny the call and return an error tool result. - -Manual hooks block until resolved in live flows: - -```python -approval = await ai.hook( - "approve_send_email", - payload=ai.tools.ToolApproval, - metadata={"tool": "send_email"}, -) -``` - -Resolve or cancel from another task, request handler, or UI callback: - -```python -ai.resolve_hook("approve_send_email", {"granted": True, "reason": "approved"}) -await ai.cancel_hook("approve_send_email", reason="client disconnected") -``` - -Hooks emit `HookEvent` objects. Their messages use `role="internal"` and contain -`HookPart` values. - -Serverless resume flow: - -```python -async with agent.run(model, messages) as stream: - async for event in stream: - if isinstance(event, ai.events.HookEvent) and event.hook.status == "pending": - ai.abort_pending_hook(event.hook) - yield event - -persist(stream.messages) - -# Later, restore messages, pre-register the resolution, and rerun. -ai.resolve_hook(hook_id, ai.tools.ToolApproval(granted=True, reason="approved")) -``` - -## MCP - -MCP adapters return `AgentTool` objects usable in `ai.agent(...)`. - -```python -tools = await ai.mcp.get_http_tools( - "https://mcp.example.com/mcp", - headers={"Authorization": "Bearer token"}, - tool_prefix="docs", -) - -tools = await ai.mcp.get_stdio_tools( - "npx", - "-y", - "@anthropic/mcp-server-filesystem", - "/tmp", - tool_prefix="fs", -) - -agent = ai.agent(tools=tools) -``` - -## AI SDK UI adapter - -Use `ai.agents.ui.ai_sdk` to convert between AI SDK UI messages and Python -runtime messages/events. - -```python -class ChatRequest(pydantic.BaseModel): - messages: list[ai.agents.ui.ai_sdk.UIMessage] - - -@app.post("/chat") -async def chat(request: ChatRequest): - messages, approvals = ai.agents.ui.ai_sdk.to_messages(request.messages) - ai.agents.ui.ai_sdk.apply_approvals(approvals) - - async def stream_response(): - async with chat_agent.run(model, messages) as stream: - async for chunk in ai.agents.ui.ai_sdk.to_sse(stream): - yield chunk - - return fastapi.responses.StreamingResponse( - stream_response(), - headers=ai.agents.ui.ai_sdk.UI_MESSAGE_STREAM_HEADERS, - ) -``` - -Use `ai.agents.ui.ai_sdk.to_ui_messages(messages)` to rebuild UI history from -stored runtime messages. - -For serverless approvals, monitor `HookEvent` before passing events to `to_sse` -and call `ai.abort_pending_hook(event.hook)` on pending hooks. - -## Media generation - -Use `ai.generate` for dedicated image and video models: - -```python -image_message = await ai.generate( - ai.get_model("gateway:google/imagen-4.0-generate-001"), - [ai.user_message("A watercolor mothership over a quiet city.")], - ai.ImageParams(n=1, aspect_ratio="16:9"), -) - -image = image_message.images[0] +answer = run.output +history = run.messages ``` -For video generation, pass `ai.VideoParams(...)` and read `message.videos`. +Use `custom_loop`, `subagents`, `streaming_tools`, `serverless_execution`, +`durable_execution`, `ai_sdk_ui_adapter`, and `custom_provider` for advanced +patterns. diff --git a/skills/ai_sdk_ui_adapter/SKILL.md b/skills/ai_sdk_ui_adapter/SKILL.md new file mode 100644 index 00000000..14052629 --- /dev/null +++ b/skills/ai_sdk_ui_adapter/SKILL.md @@ -0,0 +1,63 @@ +--- +name: ai_sdk_ui_adapter +description: Use when connecting Python ai SDK agents to AI SDK UI useChat clients, UIMessage history, streamed responses, and approvals. +--- + +# ai_sdk_ui_adapter + +Frontend: + +```tsx +const chat = useChat({ + transport: new DefaultChatTransport({ api: "/api/chat" }), + sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses, +}); +``` + +Use `chat.sendMessage(...)` to send user input. Use +`chat.addToolApprovalResponse(...)` from approval buttons. + +Backend request: + +```python +class ChatRequest(pydantic.BaseModel): + messages: list[ai.agents.ui.ai_sdk.UIMessage] + +messages, approvals = ai.agents.ui.ai_sdk.to_messages(request.messages) +ai.agents.ui.ai_sdk.apply_approvals(approvals) +``` + +Backend stream: + +```python +async def body(): + async with agent.run(model, messages) as stream: + async def events(): + async for event in stream: + if ( + isinstance(event, ai.events.HookEvent) + and event.hook.status == "pending" + ): + ai.abort_pending_hook(event.hook) + yield event + + async for chunk in ai.agents.ui.ai_sdk.to_sse(events()): + yield chunk + +return StreamingResponse( + body(), + headers=ai.agents.ui.ai_sdk.UI_MESSAGE_STREAM_HEADERS, +) +``` + +The adapter handles `UIMessage` parsing, message IDs, tool state, approvals, +subagent `MessageBundle` values, and AI SDK UI stream events. + +You handle the HTTP route, auth, storage, session lookup, frontend rendering, +and when to abort pending hooks. + +For saved UI history, use: + +```python +ui_messages = ai.agents.ui.ai_sdk.to_ui_messages(messages) +``` diff --git a/skills/custom_loop/SKILL.md b/skills/custom_loop/SKILL.md new file mode 100644 index 00000000..6857db7f --- /dev/null +++ b/skills/custom_loop/SKILL.md @@ -0,0 +1,41 @@ +--- +name: custom_loop +description: Use when changing a Python ai SDK agent loop for custom tool order, routing, logging, hooks, replay, or scheduling. +--- + +# custom_loop + +Keep the default shape unless you must change control flow: + +```python +class MyAgent(ai.Agent): + async def loop(self, context: ai.Context): + while context.keep_running(): + async with ( + ai.stream(context=context) as stream, + ai.ToolRunner() as runner, + ): + async for event in ai.util.merge(stream, runner.events()): + yield event + + if isinstance(event, ai.events.ToolEnd): + runner.schedule(context.resolve(event.tool_call)) + + context.add(stream.message) + context.add(runner.get_tool_message()) +``` + +Rules: + +- Call `context.keep_running()` at the top of each turn. +- Use `ai.stream(context=context)` so model, messages, tools, output type, and params stay together. +- Yield events from the loop. `Agent.run` hides replay events from callers. +- On `ToolEnd`, use `context.resolve(event.tool_call)`. It handles validation, approval gates, and cached replay results. +- Do not call `tool.fn` directly unless you also handle validation, approvals, and cached results. +- Schedule resolved calls with `ToolRunner.schedule(...)`. +- `ToolRunner.schedule(...)` also accepts a zero-arg async callable that returns `ai.events.ToolCallResult`. +- If you make a result yourself, use `runner.add_result(ai.tool_result(...))`. +- Add `stream.message`, then `runner.get_tool_message()`. `context.add(...)` skips replay messages. +- Every tool call must get one tool result. +- For hooks, let `context.resolve(...)` build the gated call. Use `serverless_execution` for request boundaries. +- For durable calls, keep this shape and wrap only model or tool I/O. Use `durable_execution`. diff --git a/skills/custom_provider/SKILL.md b/skills/custom_provider/SKILL.md new file mode 100644 index 00000000..63c57506 --- /dev/null +++ b/skills/custom_provider/SKILL.md @@ -0,0 +1,84 @@ +--- +name: custom_provider +description: Use for writing custom Python ai SDK providers and protocols. +--- + +# custom_provider + +Providers emit model events. They do not run Python tools. `ai.stream` collects +events into a `Message`. `ai.Agent` adds tool execution, hooks, and replay. + +Minimal shape: + +```python +from collections.abc import AsyncGenerator, Sequence +from typing import Any + +import pydantic +import ai + + +class MyProtocol(ai.ProviderProtocol[Any]): + def stream( + self, + client: Any, + model: ai.Model, + messages: list[ai.messages.Message], + *, + tools: Sequence[ai.tools.Tool] | None = None, + output_type: type[pydantic.BaseModel] | None = None, + params: ai.InferenceRequestParams | None = None, + provider: str, + ) -> AsyncGenerator[ai.events.Event]: + return self._stream(client, model, messages, tools=tools) + + async def _stream( + self, + client: Any, + model: ai.Model, + messages: list[ai.messages.Message], + *, + tools: Sequence[ai.tools.Tool] | None, + ) -> AsyncGenerator[ai.events.Event]: + yield ai.events.StreamStart() + yield ai.events.TextStart(block_id="text") + yield ai.events.TextDelta(block_id="text", chunk="Hello") + yield ai.events.TextEnd(block_id="text") + yield ai.events.StreamEnd() + + +class MyProvider(ai.Provider[Any]): + def __init__(self, client: Any) -> None: + super().__init__( + name="my", + base_url="", + protocol=MyProtocol(), + client=client, + ) + + async def list_models(self) -> list[str]: + return ["my-model"] + + async def probe(self, model: ai.Model) -> None: + return None + + +model = ai.Model("my-model", provider=MyProvider(client)) +``` + +For Python tool calls, emit `ToolStart`, `ToolDelta`, and `ToolEnd`: + +```python +yield ai.events.ToolStart(tool_call_id=tcid, tool_name=name) +yield ai.events.ToolDelta(tool_call_id=tcid, chunk=args_json) +yield ai.events.ToolEnd( + tool_call_id=tcid, + tool_call=ai.messages.DUMMY_TOOL_CALL, +) +``` + +The stream collector fills `event.tool_call` with the aggregated tool call. +Then `Agent` resolves and runs the tool. + +If the provider runs its own built-in tool, emit `BuiltinToolStart`, +`BuiltinToolDelta`, `BuiltinToolEnd`, and `BuiltinToolResult` instead. diff --git a/skills/durable_execution/SKILL.md b/skills/durable_execution/SKILL.md new file mode 100644 index 00000000..251cdfde --- /dev/null +++ b/skills/durable_execution/SKILL.md @@ -0,0 +1,44 @@ +--- +name: durable_execution +description: Use for Python ai SDK durable execution, serialization boundaries, replay, and workflow engines such as Temporal. +--- + +# durable_execution + +Durability belongs at I/O boundaries. Keep the framework pieces when possible: +`Agent`, `Context`, messages, `ai.stream`, `ToolRunner`, and `@ai.tool`. + +Serialize only data: + +- Messages with `message.model_dump(mode="json")`. +- Restore with `ai.messages.Message.model_validate(...)`. +- Model IDs, tool schemas, params, and plain tool arguments. + +Do not serialize live clients, provider instances with open clients, streams, +tasks, or sockets. Recreate those inside activities or other durable I/O calls. + +For a durable model call, run the real model call in the durability API and +return a complete assistant `Message`. Feed it back through the normal stream +machinery: + +```python +message = ai.messages.Message.model_validate(saved_message) + +async with ( + ai.Stream(ai.events.replay_message_events(message)) as stream, + ai.ToolRunner() as runner, +): + async for event in ai.util.merge(stream, runner.events()): + yield event + if isinstance(event, ai.events.ToolEnd): + runner.schedule(context.resolve(event.tool_call)) + + context.add(stream.message) + context.add(runner.get_tool_message()) +``` + +For durable tools, pass `ToolRunner.schedule(...)` a zero-arg async callable +that calls the durability API and returns `ai.tool_result(...)`. + +You do not need to rewrite the whole loop. Usually only the model call and tool +body need durable wrappers. diff --git a/skills/serverless_execution/SKILL.md b/skills/serverless_execution/SKILL.md new file mode 100644 index 00000000..b2e34920 --- /dev/null +++ b/skills/serverless_execution/SKILL.md @@ -0,0 +1,57 @@ +--- +name: serverless_execution +description: Use for Python ai SDK hook interruptions, approvals, replay, and resume across stateless requests. +--- + +# serverless_execution + +Use hooks to stop a run, save messages, then replay from the same assistant +turn. + +For tool approval, mark the tool: + +```python +@ai.tool(require_approval=True) +async def delete_file(path: str) -> str: + return f"Deleted {path}" +``` + +First request: + +```python +async with agent.run(model, messages) as stream: + async for event in stream: + if ( + isinstance(event, ai.events.HookEvent) + and event.hook.status == "pending" + ): + save_hook_id(event.hook.hook_id) + ai.abort_pending_hook(event.hook) + yield event + +saved_messages = stream.messages +``` + +Next request: + +```python +messages = [ + ai.messages.Message.model_validate(m) + for m in load_messages_json() +] + +ai.resolve_hook( + hook_id, + ai.tools.ToolApproval(granted=True, reason="approved"), +) + +async with agent.run(model, messages) as stream: + async for event in stream: + yield event +``` + +Do not ask the model to make the tool call again. `Agent.run` prepares replay: +it marks the interrupted assistant turn with `replay=True` and keeps completed +sibling tool results on `cached_result`. + +Persist messages, not the hook registry. diff --git a/skills/streaming_tools/SKILL.md b/skills/streaming_tools/SKILL.md new file mode 100644 index 00000000..964571fd --- /dev/null +++ b/skills/streaming_tools/SKILL.md @@ -0,0 +1,53 @@ +--- +name: streaming_tools +description: Use for Python ai SDK tools that stream partial output, nested agent events, MessageBundle values, or preliminary UI output. +--- + +# streaming_tools + +Make a streaming tool an async generator. + +Use `StreamingTextTool` when yielded strings join into the result: + +```python +@ai.tool +async def draft(topic: str) -> ai.StreamingTextTool: + yield "Drafting " + yield topic +``` + +Use `StreamingStatusTool[T]` when only the last yield is the result: + +```python +@ai.tool +async def fetch(url: str) -> ai.StreamingStatusTool[str]: + yield "connecting" + yield "downloading" + yield body +``` + +Use `SubAgentTool` for nested agent events: + +```python +@ai.tool +async def research(topic: str) -> ai.SubAgentTool: + async with child.run(model, [ai.user_message(topic)]) as stream: + async for event in stream: + yield event +``` + +Live values arrive as `ai.events.PartialToolCallResult`. + +`SubAgentTool` stores a `MessageBundle` as the tool result. The model sees the +last child assistant text, not the raw bundle. Keep the bundle typed when you +save history: + +```python +data = message.model_dump(mode="json") +message = ai.messages.Message.model_validate(data) +``` + +Do not stringify `MessageBundle` or drop `result_kind`. The UI adapter uses it +to round-trip subagent output. + +For custom aggregation, use `ai.agents.Aggregate` on the return type. diff --git a/skills/subagents/SKILL.md b/skills/subagents/SKILL.md new file mode 100644 index 00000000..1475b467 --- /dev/null +++ b/skills/subagents/SKILL.md @@ -0,0 +1,40 @@ +--- +name: subagents +description: Use for the subagent-as-a-tool pattern and other Python ai SDK multi-agent handoffs. +--- + +# subagents + +Use a subagent tool when the parent model should choose when to call another +agent. + +```python +@ai.tool +async def research(topic: str) -> ai.SubAgentTool: + child = ai.agent(tools=[lookup]) + messages = [ + ai.system_message("Research briefly."), + ai.user_message(topic), + ] + + async with child.run(model, messages) as stream: + async for event in stream: + yield event +``` + +The parent model sees the child agent's final assistant text as the tool +result. The caller sees child events as `ai.events.PartialToolCallResult`. + +Render nested output from `event.value`: + +```python +if isinstance(event, ai.events.PartialToolCallResult): + if isinstance(event.value, ai.events.TextDelta): + print(event.value.chunk, end="", flush=True) +``` + +Do not append child messages to the parent history yourself. The tool result +stores the child transcript as a `MessageBundle`. + +For `MessageBundle`, preliminary output, and streaming tool details, use +`streaming_tools`. From 92f4b60cba6ce66825af205cd5a7472ebcfe291c Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 10:25:27 -0700 Subject: [PATCH 04/19] Restructure docs reference to mirror reexport patterns --- .../content/docs/reference/ai-sdk-ui.mdx | 68 ---------- .../docs/reference/ai.agents/aggregators.mdx | 20 +++ .../reference/ai.agents/gated-tool-call.mdx | 12 ++ .../docs/reference/ai.agents/index.mdx | 21 ++++ .../docs/reference/ai.agents/meta.json | 9 ++ .../ai.agents/ui/ai-sdk/approvals.mdx | 20 +++ .../ai.agents/ui/ai-sdk/inbound-messages.mdx | 15 +++ .../reference/ai.agents/ui/ai-sdk/index.mdx | 20 +++ .../reference/ai.agents/ui/ai-sdk/meta.json | 11 ++ .../ai.agents/ui/ai-sdk/outbound-messages.mdx | 14 +++ .../ai.agents/ui/ai-sdk/outbound-stream.mdx | 20 +++ .../ai.agents/ui/ai-sdk/ui-message.mdx | 16 +++ .../docs/reference/ai.agents/ui/meta.json | 7 ++ .../docs/reference/ai.errors/base-errors.mdx | 15 +++ .../docs/reference/ai.errors/helpers.mdx | 24 ++++ .../docs/reference/ai.errors/index.mdx | 15 +++ .../docs/reference/ai.errors/meta.json | 10 ++ .../reference/ai.errors/provider-errors.mdx | 21 ++++ .../reference/ai.errors/status-errors.mdx | 25 ++++ .../docs/reference/ai.events/agent-events.mdx | 18 +++ .../docs/reference/ai.events/aggregators.mdx | 21 ++++ .../docs/reference/ai.events/index.mdx | 16 +++ .../docs/reference/ai.events/meta.json | 10 ++ .../ai.events/replay-message-events.mdx | 16 +++ .../reference/ai.events/stream-events.mdx | 44 +++++++ .../reference/ai.mcp/close-connections.mdx | 11 ++ .../docs/reference/ai.mcp/http-tools.mdx | 15 +++ .../content/docs/reference/ai.mcp/index.mdx | 14 +++ .../content/docs/reference/ai.mcp/meta.json | 9 ++ .../docs/reference/ai.mcp/stdio-tools.mdx | 23 ++++ .../docs/reference/ai.messages/index.mdx | 17 +++ .../reference/ai.messages/message-bundle.mdx | 14 +++ .../reference/ai.messages/message-ids.mdx | 15 +++ .../docs/reference/ai.messages/message.mdx | 38 ++++++ .../docs/reference/ai.messages/meta.json | 12 ++ .../docs/reference/ai.messages/parts.mdx | 23 ++++ .../reference/ai.messages/serialization.mdx | 16 +++ .../docs/reference/ai.messages/tool-parts.mdx | 21 ++++ .../docs/reference/ai.models/index.mdx | 35 ++++++ .../docs/reference/ai.models/meta.json | 5 + .../ai.providers/ai-gateway/index.mdx | 14 +++ .../ai.providers/ai-gateway/meta.json | 10 ++ .../ai.providers/ai-gateway/params.mdx | 13 ++ .../ai.providers/ai-gateway/protocol.mdx | 9 ++ .../ai.providers/ai-gateway/provider.mdx | 10 ++ .../ai.providers/ai-gateway/tools.mdx | 19 +++ .../ai.providers/anthropic/index.mdx | 17 +++ .../ai.providers/anthropic/meta.json | 9 ++ .../ai.providers/anthropic/protocol.mdx | 9 ++ .../ai.providers/anthropic/provider.mdx | 17 +++ .../ai.providers/anthropic/tools.mdx | 24 ++++ .../docs/reference/ai.providers/index.mdx | 19 +++ .../docs/reference/ai.providers/meta.json | 9 ++ .../reference/ai.providers/openai/index.mdx | 17 +++ .../reference/ai.providers/openai/meta.json | 9 ++ .../ai.providers/openai/protocols.mdx | 14 +++ .../ai.providers/openai/provider.mdx | 16 +++ .../reference/ai.providers/openai/tools.mdx | 28 +++++ .../content/docs/reference/ai.tools/index.mdx | 24 ++++ .../content/docs/reference/ai.tools/meta.json | 9 ++ .../docs/reference/ai.tools/tool-approval.mdx | 13 ++ .../docs/reference/ai.tools/tool-config.mdx | 11 ++ .../docs/reference/ai.tools/tool-spec.mdx | 14 +++ .../content/docs/reference/ai.types/index.mdx | 16 +++ .../docs/reference/ai.types/integrity.mdx | 24 ++++ .../content/docs/reference/ai.types/media.mdx | 27 ++++ .../content/docs/reference/ai.types/meta.json | 9 ++ .../content/docs/reference/ai.types/usage.mdx | 20 +++ .../docs/reference/ai.util/decouple.mdx | 11 ++ .../content/docs/reference/ai.util/index.mdx | 17 +++ .../docs/reference/ai.util/lifecycle.mdx | 14 +++ .../content/docs/reference/ai.util/merge.mdx | 14 +++ .../content/docs/reference/ai.util/meta.json | 10 ++ .../content/docs/reference/ai.util/queues.mdx | 15 +++ .../docs/reference/ai/agent-factory.mdx | 21 ++++ .../content/docs/reference/ai/agent-tool.mdx | 19 +++ .../content/docs/reference/{ => ai}/agent.mdx | 35 ++---- .../{tool-runner.mdx => ai/context.mdx} | 40 +----- .../docs/reference/{ => ai}/generate.mdx | 34 +---- .../content/docs/reference/ai/get-model.mdx | 26 ++++ .../docs/reference/ai/get-provider.mdx | 20 +++ .../content/docs/reference/ai/hooks.mdx | 47 +++++++ .../content/docs/reference/ai/index.mdx | 28 +++++ .../reference/ai/media-generation-params.mdx | 38 ++++++ .../docs/reference/ai/message-builders.mdx | 15 +++ .../content/docs/reference/ai/meta.json | 31 +++++ .../docs/reference/ai/model-params.mdx | 46 +++++++ .../content/docs/reference/ai/model.mdx | 30 +++++ .../docs/reference/ai/part-builders.mdx | 16 +++ .../content/docs/reference/ai/probe.mdx | 15 +++ .../docs/reference/ai/provider-protocol.mdx | 11 ++ .../content/docs/reference/ai/provider.mdx | 32 +++++ .../docs/reference/ai/routing-params.mdx | 19 +++ .../docs/reference/{ => ai}/stream.mdx | 0 .../docs/reference/ai/streaming-tools.mdx | 17 +++ .../content/docs/reference/ai/tool-call.mdx | 24 ++++ .../docs/reference/ai/tool-decorator.mdx | 33 +++++ .../docs/reference/ai/tool-results.mdx | 17 +++ .../content/docs/reference/ai/tool-runner.mdx | 24 ++++ .../content/docs/reference/ai/tool.mdx | 22 ++++ .../content/docs/reference/ai/yield-from.mdx | 16 +++ .../content/docs/reference/events.mdx | 96 -------------- .../content/docs/reference/hooks.mdx | 67 ---------- .../content/docs/reference/index.mdx | 24 ++-- .../content/docs/reference/messages.mdx | 102 --------------- .../content/docs/reference/meta.json | 21 ++-- .../docs/reference/models-and-providers.mdx | 119 ------------------ .../ai-python/content/docs/reference/tool.mdx | 79 ------------ 108 files changed, 1800 insertions(+), 651 deletions(-) delete mode 100644 docs/ai-python/content/docs/reference/ai-sdk-ui.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/approvals.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/inbound-messages.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-messages.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-stream.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/ui-message.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.agents/ui/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.errors/helpers.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.errors/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.errors/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.events/agent-events.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.events/aggregators.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.events/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.events/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.events/stream-events.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.mcp/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.mcp/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/message.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.messages/parts.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/serialization.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.models/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.models/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.tools/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.tools/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.types/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.types/integrity.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.types/media.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.types/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.types/usage.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.util/decouple.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.util/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.util/merge.mdx create mode 100644 docs/ai-python/content/docs/reference/ai.util/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai.util/queues.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/agent-factory.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/agent-tool.mdx rename docs/ai-python/content/docs/reference/{ => ai}/agent.mdx (55%) rename docs/ai-python/content/docs/reference/{tool-runner.mdx => ai/context.mdx} (50%) rename docs/ai-python/content/docs/reference/{ => ai}/generate.mdx (61%) create mode 100644 docs/ai-python/content/docs/reference/ai/get-model.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/get-provider.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/hooks.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/index.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/media-generation-params.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/message-builders.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/meta.json create mode 100644 docs/ai-python/content/docs/reference/ai/model-params.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/model.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/part-builders.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/probe.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/provider-protocol.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/provider.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/routing-params.mdx rename docs/ai-python/content/docs/reference/{ => ai}/stream.mdx (100%) create mode 100644 docs/ai-python/content/docs/reference/ai/streaming-tools.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/tool-call.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/tool-decorator.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/tool-results.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/tool-runner.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/tool.mdx create mode 100644 docs/ai-python/content/docs/reference/ai/yield-from.mdx delete mode 100644 docs/ai-python/content/docs/reference/events.mdx delete mode 100644 docs/ai-python/content/docs/reference/hooks.mdx delete mode 100644 docs/ai-python/content/docs/reference/messages.mdx delete mode 100644 docs/ai-python/content/docs/reference/models-and-providers.mdx delete mode 100644 docs/ai-python/content/docs/reference/tool.mdx diff --git a/docs/ai-python/content/docs/reference/ai-sdk-ui.mdx b/docs/ai-python/content/docs/reference/ai-sdk-ui.mdx deleted file mode 100644 index a2ad87db..00000000 --- a/docs/ai-python/content/docs/reference/ai-sdk-ui.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: "ai.agents.ui.ai_sdk" -description: Reference for AI SDK UI message and SSE adapters. -type: reference -summary: Reference for to_messages, to_sse, to_stream, to_ui_messages, approvals, headers, and UIMessage. ---- - -`ai.agents.ui.ai_sdk` converts between AI SDK UI message streams and the Python -runtime. - -## UIMessage - -```python -class ChatRequest(pydantic.BaseModel): - messages: list[ai.agents.ui.ai_sdk.UIMessage] -``` - -Use `UIMessage` as the request model for AI SDK UI clients. - -## to_messages - -```python -messages, approvals = ai.agents.ui.ai_sdk.to_messages(ui_messages) -``` - -Converts UI messages into runtime messages and extracts approval responses. - -## apply_approvals - -```python -ai.agents.ui.ai_sdk.apply_approvals(approvals) -``` - -Registers extracted approval responses before an agent run resumes. - -## to_sse - -```python -async for chunk in ai.agents.ui.ai_sdk.to_sse(agent_stream): - yield chunk -``` - -Converts agent events to Server-Sent Events for AI SDK UI. - -## to_stream - -```python -async for part in ai.agents.ui.ai_sdk.to_stream(agent_stream): - yield part -``` - -Converts agent events to UI stream parts without SSE framing. - -## to_ui_messages - -```python -ui_messages = ai.agents.ui.ai_sdk.to_ui_messages(messages) -``` - -Converts stored runtime messages back to AI SDK UI messages. - -## Headers - -```python -headers = ai.agents.ui.ai_sdk.UI_MESSAGE_STREAM_HEADERS -``` - -Return these headers on streamed AI SDK UI responses. diff --git a/docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx b/docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx new file mode 100644 index 00000000..1b011b19 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx @@ -0,0 +1,20 @@ +--- +title: "ai.agents aggregators" +description: Reference for streaming tool aggregation helpers. +type: reference +summary: Reference for Aggregate, yield_from, and built-in aggregators. +--- + +Aggregators collect yielded values from streaming tools and decide what value is +stored and what value is sent back to the model. + +## APIs + +- `Aggregate` +- `yield_from` +- `SimpleAggregator` +- `ConcatAggregator` +- `LastAggregator` +- `MessageAggregator` + +Custom aggregators implement `ai.events.Aggregator`. diff --git a/docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx b/docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx new file mode 100644 index 00000000..3f9d4260 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx @@ -0,0 +1,12 @@ +--- +title: "ai.agents.GatedToolCall" +description: "Gate a tool call before execution." +type: reference +summary: "Reference for ai.agents.GatedToolCall." +--- + +`GatedToolCall` wraps a tool call that requires approval or another gate +before execution. + +Use it in custom agent loops when you need to delay or externally approve a +scheduled tool call. diff --git a/docs/ai-python/content/docs/reference/ai.agents/index.mdx b/docs/ai-python/content/docs/reference/ai.agents/index.mdx new file mode 100644 index 00000000..a35948bb --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/index.mdx @@ -0,0 +1,21 @@ +--- +title: "ai.agents" +description: "Reference for advanced agent namespace APIs." +type: reference +summary: "Reference for public APIs that are intentionally used from ai.agents." +--- + +Most agent APIs are documented as top-level `ai` exports. Use `ai.agents` +for advanced agent namespace APIs and types that are not promoted to the +top-level namespace. + +Public advanced APIs: + +- `Aggregate` +- `SimpleAggregator` +- `ConcatAggregator` +- `LastAggregator` +- `MessageAggregator` +- `BoundToolCall` +- `GatedToolCall` +- `ToolCallCallable` diff --git a/docs/ai-python/content/docs/reference/ai.agents/meta.json b/docs/ai-python/content/docs/reference/ai.agents/meta.json new file mode 100644 index 00000000..64546d58 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.agents", + "description": "Reference for advanced agent namespace APIs.", + "pages": [ + "aggregators", + "gated-tool-call", + "ui" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/approvals.mdx b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/approvals.mdx new file mode 100644 index 00000000..75e4db39 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/approvals.mdx @@ -0,0 +1,20 @@ +--- +title: "ai.agents.ui.ai_sdk approvals" +description: Apply AI SDK UI approval responses. +type: reference +summary: Reference for ApprovalResponse, extract_approvals, and apply_approvals. +--- + +Approval helpers bridge AI SDK UI tool approval responses into the hook +registry. + +## APIs + +- `ApprovalResponse` +- `extract_approvals` +- `apply_approvals` + +```python +approvals = ai.agents.ui.ai_sdk.extract_approvals(ui_messages) +ai.agents.ui.ai_sdk.apply_approvals(approvals) +``` diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/inbound-messages.mdx b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/inbound-messages.mdx new file mode 100644 index 00000000..5511295d --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/inbound-messages.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.agents.ui.ai_sdk.to_messages" +description: Convert UI messages to runtime messages. +type: reference +summary: Reference for inbound AI SDK UI message conversion. +--- + +`to_messages` converts AI SDK UI messages into runtime messages and extracts +approval responses. + +```python +messages, approvals = ai.agents.ui.ai_sdk.to_messages(ui_messages) +``` + +Call `apply_approvals` before resuming an agent run with extracted approvals. diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/index.mdx b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/index.mdx new file mode 100644 index 00000000..fea3c252 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/index.mdx @@ -0,0 +1,20 @@ +--- +title: "ai.agents.ui.ai_sdk" +description: Reference for AI SDK UI message and SSE adapters. +type: reference +summary: Reference for ai.agents.ui.ai_sdk. +--- + +`ai.agents.ui.ai_sdk` converts between AI SDK UI message streams and the Python +runtime. + +## APIs + +- `UIMessage` +- `to_messages` +- `extract_approvals` +- `apply_approvals` +- `to_sse` +- `to_stream` +- `to_ui_messages` +- `UI_MESSAGE_STREAM_HEADERS` diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/meta.json b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/meta.json new file mode 100644 index 00000000..f984c94f --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/meta.json @@ -0,0 +1,11 @@ +{ + "title": "ai.agents.ui.ai_sdk", + "description": "Reference for AI SDK UI adapters.", + "pages": [ + "ui-message", + "inbound-messages", + "approvals", + "outbound-stream", + "outbound-messages" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-messages.mdx b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-messages.mdx new file mode 100644 index 00000000..acd6ce36 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-messages.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.agents.ui.ai_sdk.to_ui_messages" +description: Convert runtime messages to AI SDK UI messages. +type: reference +summary: Reference for ai.agents.ui.ai_sdk.to_ui_messages. +--- + +`to_ui_messages` converts stored runtime messages back to AI SDK UI messages. + +```python +ui_messages = ai.agents.ui.ai_sdk.to_ui_messages(messages) +``` + +Use it when loading durable conversation history for a UI client. diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-stream.mdx b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-stream.mdx new file mode 100644 index 00000000..5fb1d7c2 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/outbound-stream.mdx @@ -0,0 +1,20 @@ +--- +title: "ai.agents.ui.ai_sdk outbound stream" +description: Convert agent streams to AI SDK UI stream parts. +type: reference +summary: Reference for to_sse, to_stream, and UI_MESSAGE_STREAM_HEADERS. +--- + +Use outbound stream helpers to send an agent run to an AI SDK UI client. + +```python +async for chunk in ai.agents.ui.ai_sdk.to_sse(agent_stream): + yield chunk +``` + +```python +async for part in ai.agents.ui.ai_sdk.to_stream(agent_stream): + yield part +``` + +Return `UI_MESSAGE_STREAM_HEADERS` on streamed AI SDK UI responses. diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/ui-message.mdx b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/ui-message.mdx new file mode 100644 index 00000000..682117a1 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/ai-sdk/ui-message.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.agents.ui.ai_sdk.UIMessage" +description: Parse AI SDK UI messages. +type: reference +summary: Reference for ai.agents.ui.ai_sdk.UIMessage. +--- + +Use `UIMessage` as the request model for AI SDK UI clients. + +```python +class ChatRequest(pydantic.BaseModel): + messages: list[ai.agents.ui.ai_sdk.UIMessage] +``` + +AI SDK UI messages use a `parts` array. Tool parts can carry approval state and +provider metadata. diff --git a/docs/ai-python/content/docs/reference/ai.agents/ui/meta.json b/docs/ai-python/content/docs/reference/ai.agents/ui/meta.json new file mode 100644 index 00000000..35bb2cd9 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.agents/ui/meta.json @@ -0,0 +1,7 @@ +{ + "title": "ai.agents.ui", + "description": "Reference for agent UI adapters.", + "pages": [ + "ai-sdk" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx b/docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx new file mode 100644 index 00000000..64e48419 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.errors base errors" +description: Reference for base SDK errors. +type: reference +summary: Reference for AIError, ConfigurationError, InstallationError, and UnsupportedProviderError. +--- + +Base errors are not tied to a provider HTTP response. + +## Types + +- `AIError` +- `ConfigurationError` +- `InstallationError` +- `UnsupportedProviderError` diff --git a/docs/ai-python/content/docs/reference/ai.errors/helpers.mdx b/docs/ai-python/content/docs/reference/ai.errors/helpers.mdx new file mode 100644 index 00000000..fde83a30 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.errors/helpers.mdx @@ -0,0 +1,24 @@ +--- +title: "ai.errors helpers" +description: Reference for error helper types and functions. +type: reference +summary: Reference for HTTPErrorContext and http_status_to_provider_status_error_class. +--- + +Error helpers expose normalized HTTP context and status-code mapping. + +## HTTPErrorContext + +```python +context.status_code +context.request +context.response +``` + +## http_status_to_provider_status_error_class + +```python +error_cls = ai.errors.http_status_to_provider_status_error_class(429) +``` + +Returns the provider status error class for an HTTP status code. diff --git a/docs/ai-python/content/docs/reference/ai.errors/index.mdx b/docs/ai-python/content/docs/reference/ai.errors/index.mdx new file mode 100644 index 00000000..c0c648d3 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.errors/index.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.errors" +description: Reference for SDK error types. +type: reference +summary: Reference for ai.errors. +--- + +`ai.errors` contains the framework and provider error hierarchy. + +## Groups + +- Base framework errors. +- Provider API errors. +- Provider status errors. +- HTTP error helper types. diff --git a/docs/ai-python/content/docs/reference/ai.errors/meta.json b/docs/ai-python/content/docs/reference/ai.errors/meta.json new file mode 100644 index 00000000..0846d994 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.errors/meta.json @@ -0,0 +1,10 @@ +{ + "title": "ai.errors", + "description": "Reference for SDK error types.", + "pages": [ + "base-errors", + "provider-errors", + "status-errors", + "helpers" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx b/docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx new file mode 100644 index 00000000..a4d11c4e --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx @@ -0,0 +1,21 @@ +--- +title: "ai.errors provider errors" +description: Reference for provider API errors. +type: reference +summary: Reference for ProviderError and ProviderAPIError subclasses. +--- + +Provider errors represent failures raised by model providers. + +## Types + +- `ProviderError` +- `ProviderNotConfiguredError` +- `ProviderAPIError` +- `ProviderConnectionError` +- `ProviderTimeoutError` +- `ProviderResponseError` +- `ProviderIncompleteResponseError` + +`ProviderAPIError` includes `request_id`, `http_context`, `body`, `code`, +`param`, `type`, and `is_retryable`. diff --git a/docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx b/docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx new file mode 100644 index 00000000..b34de30d --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx @@ -0,0 +1,25 @@ +--- +title: "ai.errors provider status errors" +description: Reference for provider HTTP status errors. +type: reference +summary: Reference for ProviderStatusError subclasses. +--- + +Status errors represent provider responses with non-success HTTP status codes. + +## Types + +- `ProviderStatusError` +- `ProviderBadRequestError` +- `ProviderAuthenticationError` +- `ProviderPermissionDeniedError` +- `ProviderNotFoundError` +- `ProviderModelNotFoundError` +- `ProviderConflictError` +- `ProviderRequestTooLargeError` +- `ProviderUnprocessableEntityError` +- `ProviderRateLimitError` +- `ProviderInternalServerError` +- `ProviderServiceUnavailableError` +- `ProviderDeadlineExceededError` +- `ProviderOverloadedError` diff --git a/docs/ai-python/content/docs/reference/ai.events/agent-events.mdx b/docs/ai-python/content/docs/reference/ai.events/agent-events.mdx new file mode 100644 index 00000000..b722ce2e --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.events/agent-events.mdx @@ -0,0 +1,18 @@ +--- +title: "ai.events agent events" +description: Reference for agent-level events. +type: reference +summary: Reference for ToolCallResult, PartialToolCallResult, and HookEvent. +--- + +Agents can emit event values that are not raw provider stream events. + +## Types + +- `ToolCallResult` +- `PartialToolCallResult` +- `HookEvent` + +`ToolCallResult` carries the tool result message and result parts. +`PartialToolCallResult` carries values yielded by streaming tools and +`yield_from`. `HookEvent` carries an internal hook message and `HookPart`. diff --git a/docs/ai-python/content/docs/reference/ai.events/aggregators.mdx b/docs/ai-python/content/docs/reference/ai.events/aggregators.mdx new file mode 100644 index 00000000..e9af36f9 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.events/aggregators.mdx @@ -0,0 +1,21 @@ +--- +title: "ai.events.Aggregator" +description: Reference for the streaming tool aggregator protocol. +type: reference +summary: Reference for ai.events.Aggregator. +--- + +`Aggregator[Item, Result, ModelInput]` is the interface used by streaming tools +and `yield_from`. + +```python +class MyAggregator(ai.events.Aggregator[Item, Result, ModelInput]): + def feed(self, item: Item) -> None: ... + def snapshot(self) -> Result: ... + + @classmethod + def to_model_input(cls, snapshot: Result) -> ModelInput: ... +``` + +`snapshot()` is the rich value stored in tool results. `get_model_input()` is +the value sent back to the model. diff --git a/docs/ai-python/content/docs/reference/ai.events/index.mdx b/docs/ai-python/content/docs/reference/ai.events/index.mdx new file mode 100644 index 00000000..8a029099 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.events/index.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.events" +description: Reference for stream, agent, tool, and hook events. +type: reference +summary: Reference for ai.events. +--- + +Streams and agents yield event objects from `ai.events`. This is the public +event-model namespace, and events are Pydantic models. + +## Event groups + +- Model stream events. +- Agent events. +- Replay helpers. +- Aggregator protocol. diff --git a/docs/ai-python/content/docs/reference/ai.events/meta.json b/docs/ai-python/content/docs/reference/ai.events/meta.json new file mode 100644 index 00000000..f35da284 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.events/meta.json @@ -0,0 +1,10 @@ +{ + "title": "ai.events", + "description": "Reference for event classes and event helpers.", + "pages": [ + "stream-events", + "agent-events", + "aggregators", + "replay-message-events" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx b/docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx new file mode 100644 index 00000000..0983c1e1 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.events.replay_message_events" +description: Replay a completed message as stream events. +type: reference +summary: Reference for ai.events.replay_message_events. +--- + +`replay_message_events` synthesizes stream events from a complete `Message`. + +```python +async for event in ai.events.replay_message_events(message): + ... +``` + +Use it when cached, durable, or test messages need to flow through code that +expects stream events. diff --git a/docs/ai-python/content/docs/reference/ai.events/stream-events.mdx b/docs/ai-python/content/docs/reference/ai.events/stream-events.mdx new file mode 100644 index 00000000..baf72329 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.events/stream-events.mdx @@ -0,0 +1,44 @@ +--- +title: "ai.events stream events" +description: Reference for model stream events. +type: reference +summary: Reference for model stream event classes. +--- + +Model stream events inherit from `BaseEvent`. + +```python +event.message +event.usage +event.provider_metadata +``` + +## Text + +- `StreamStart` +- `TextStart` +- `TextDelta` +- `TextEnd` +- `StreamEnd` + +## Reasoning + +- `ReasoningStart` +- `ReasoningDelta` +- `ReasoningEnd` + +## Tools + +- `ToolStart` +- `ToolDelta` +- `ToolEnd` +- `BuiltinToolStart` +- `BuiltinToolDelta` +- `BuiltinToolEnd` +- `BuiltinToolResult` + +## Files and hooks + +- `FileEvent` +- `HookSuspension` +- `HookResolution` diff --git a/docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx b/docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx new file mode 100644 index 00000000..e051cdac --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx @@ -0,0 +1,11 @@ +--- +title: "ai.mcp.close_connections" +description: "Close MCP client connections for the current run." +type: reference +summary: "Reference for ai.mcp.close_connections." +--- + +`close_connections` closes pooled MCP connections for the active context. + +Agent runs clean up MCP connections automatically. Call this helper only +when you manage MCP tool lifetimes manually. diff --git a/docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx b/docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx new file mode 100644 index 00000000..f2bdb52e --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.mcp.get_http_tools" +description: "Load tools from an MCP HTTP server." +type: reference +summary: "Reference for ai.mcp.get_http_tools." +--- + +`get_http_tools` connects to an MCP HTTP server and returns `AgentTool` +values that can be passed to `ai.agent`. + +```python +tools = await ai.mcp.get_http_tools("https://example.com/mcp") +``` + +Use `tool_prefix` when multiple servers expose overlapping tool names. diff --git a/docs/ai-python/content/docs/reference/ai.mcp/index.mdx b/docs/ai-python/content/docs/reference/ai.mcp/index.mdx new file mode 100644 index 00000000..b26d9c66 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.mcp/index.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.mcp" +description: Reference for MCP tools. +type: reference +summary: Reference for ai.mcp. +--- + +`ai.mcp` loads MCP server tools as `AgentTool` values. + +## APIs + +- `get_stdio_tools` +- `get_http_tools` +- `close_connections` diff --git a/docs/ai-python/content/docs/reference/ai.mcp/meta.json b/docs/ai-python/content/docs/reference/ai.mcp/meta.json new file mode 100644 index 00000000..0a50dca8 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.mcp/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.mcp", + "description": "Reference for MCP tool loading APIs.", + "pages": [ + "stdio-tools", + "http-tools", + "close-connections" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx b/docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx new file mode 100644 index 00000000..4008cda9 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx @@ -0,0 +1,23 @@ +--- +title: "ai.mcp.get_stdio_tools" +description: "Load tools from an MCP stdio server." +type: reference +summary: "Reference for ai.mcp.get_stdio_tools." +--- + +`get_stdio_tools` starts an MCP server subprocess and returns `AgentTool` +values that can be passed to `ai.agent`. + +```python +tools = await ai.mcp.get_stdio_tools( + "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp" +) +``` + +Arguments: + +- `command`: subprocess command. +- `*args`: subprocess arguments. +- `env`: optional environment variables. +- `cwd`: optional working directory. +- `tool_prefix`: optional prefix for tool names. diff --git a/docs/ai-python/content/docs/reference/ai.messages/index.mdx b/docs/ai-python/content/docs/reference/ai.messages/index.mdx new file mode 100644 index 00000000..0472c3f1 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/index.mdx @@ -0,0 +1,17 @@ +--- +title: "ai.messages" +description: Reference for message types. +type: reference +summary: Reference for ai.messages. +--- + +`ai.messages` is the public message-model namespace. Messages are Pydantic +models and durable state shared by model calls, agents, tools, UI adapters, +and resume flows. + +## Public types + +- `Message` +- `MessageBundle` +- `ContentOutput` +- Message part types. diff --git a/docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx b/docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx new file mode 100644 index 00000000..50c6bbeb --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.messages message bundles" +description: Reference for message bundle types. +type: reference +summary: Reference for MessageBundle and ContentOutput. +--- + +Message bundle types are used when a tool or adapter needs to carry multiple +message-layer values as one result. + +## Types + +- `MessageBundle` +- `ContentOutput` diff --git a/docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx b/docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx new file mode 100644 index 00000000..ba9b18a0 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.messages message IDs" +description: "Reference for message ID helpers." +type: reference +summary: "Reference for ai.messages.generate_id." +--- + +`generate_id` creates SDK-style IDs for messages and parts. + +```python +message_id = ai.messages.generate_id("msg") +``` + +Pass a prefix to control the ID family. If no prefix is supplied, the helper +returns an unprefixed generated ID. diff --git a/docs/ai-python/content/docs/reference/ai.messages/message.mdx b/docs/ai-python/content/docs/reference/ai.messages/message.mdx new file mode 100644 index 00000000..8c33e5d6 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/message.mdx @@ -0,0 +1,38 @@ +--- +title: "ai.messages.Message" +description: Reference for conversation messages. +type: reference +summary: Reference for ai.messages.Message. +--- + +`Message` carries one conversation item. + +```python +message.role +message.parts +message.id +message.turn_id +message.usage +message.provider_metadata +message.replay +``` + +Roles are `user`, `assistant`, `system`, `tool`, and `internal`. + +## Convenience properties + +```python +message.text +message.reasoning +message.tool_calls +message.tool_results +message.builtin_tool_calls +message.builtin_tool_returns +message.files +message.images +message.videos +message.get_output(output_type=None) +``` + +`get_output()` returns text by default. With a Pydantic model, it validates the +message text as JSON and returns that model. diff --git a/docs/ai-python/content/docs/reference/ai.messages/meta.json b/docs/ai-python/content/docs/reference/ai.messages/meta.json new file mode 100644 index 00000000..87bafd6c --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/meta.json @@ -0,0 +1,12 @@ +{ + "title": "ai.messages", + "description": "Reference for message models and message parts.", + "pages": [ + "message", + "parts", + "tool-parts", + "message-bundle", + "message-ids", + "serialization" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.messages/parts.mdx b/docs/ai-python/content/docs/reference/ai.messages/parts.mdx new file mode 100644 index 00000000..98c2c905 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/parts.mdx @@ -0,0 +1,23 @@ +--- +title: "ai.messages parts" +description: Reference for message part types. +type: reference +summary: Reference for message part types. +--- + +Message parts store typed content inside a `Message`. + +## Common parts + +- `TextPart` +- `FilePart` +- `ReasoningPart` +- `ToolCallPart` +- `ToolResultPart` +- `BuiltinToolCallPart` +- `BuiltinToolReturnPart` +- `HookPart` + +`ToolResultPart.get_model_input()` returns the value sent back to the model. For +most tools this is the same as `result`. Aggregator-backed tools can store a +rich `result` while sending a simpler model-facing value. diff --git a/docs/ai-python/content/docs/reference/ai.messages/serialization.mdx b/docs/ai-python/content/docs/reference/ai.messages/serialization.mdx new file mode 100644 index 00000000..9eedc3d5 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/serialization.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.messages serialization" +description: Serialize and restore messages. +type: reference +summary: Reference for message serialization. +--- + +Messages serialize through Pydantic. + +```python +encoded = [message.model_dump(mode="json") for message in messages] +restored = [ai.messages.Message.model_validate(item) for item in encoded] +``` + +Persist messages after completed or suspended runs. Recreate providers, hooks, +streams, and other live runtime objects on the next request. diff --git a/docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx b/docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx new file mode 100644 index 00000000..b2105d26 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx @@ -0,0 +1,21 @@ +--- +title: "ai.messages tool parts" +description: "Reference for tool-related message parts." +type: reference +summary: "Reference for tool call, tool result, built-in tool, and hook parts." +--- + +Tool parts store tool calls, results, built-in provider tool activity, and +hook suspensions inside `ai.messages.Message` values. + +## Parts + +- `ToolCallPart` +- `ToolResultPart` +- `BuiltinToolCallPart` +- `BuiltinToolReturnPart` +- `HookPart` + +`ToolResultPart.get_model_input()` returns the value sent back to the model. +Aggregator-backed tools can keep a rich `result` while sending a simpler +model-facing value. diff --git a/docs/ai-python/content/docs/reference/ai.models/index.mdx b/docs/ai-python/content/docs/reference/ai.models/index.mdx new file mode 100644 index 00000000..57f84777 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.models/index.mdx @@ -0,0 +1,35 @@ +--- +title: "ai.models" +description: "Reference for the model namespace." +type: reference +summary: "Namespace mirror for model calls, model objects, and model params." +--- + +`ai.models` reexports the model APIs that are also available from `ai`. +Prefer top-level imports in application code: + +```python +import ai + +model = ai.get_model("anthropic/claude-sonnet-4") +async with ai.stream(model, [ai.user_message("Hello")]) as stream: + ... +``` + +Use `ai.models` when a namespace import makes code clearer, especially in +library code that groups model-layer types separately. + +## Public APIs + +- `stream` +- `generate` +- `probe` +- `get_model` +- `Model` +- `Stream` +- `InferenceRequestParams` +- model, sampler, routing, output, and media generation params +- executor and request protocols + +The deeper `ai.models.core` package is an implementation layout. Public docs +should usually point users at `ai` or `ai.models`. diff --git a/docs/ai-python/content/docs/reference/ai.models/meta.json b/docs/ai-python/content/docs/reference/ai.models/meta.json new file mode 100644 index 00000000..b43ee597 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.models/meta.json @@ -0,0 +1,5 @@ +{ + "title": "ai.models", + "description": "Reference for the model namespace.", + "pages": [] +} diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx new file mode 100644 index 00000000..58bf643e --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.providers.ai_gateway" +description: Reference for AI Gateway provider APIs. +type: reference +summary: Reference for ai.providers.ai_gateway. +--- + +`ai.providers.ai_gateway` contains the Vercel AI Gateway provider, protocol, +params, tools, and error mapping. + +```python +model = ai.get_model("gateway:anthropic/claude-sonnet-4") +ids = await ai.get_provider("vercel").list_models() +``` diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json new file mode 100644 index 00000000..3f10a8fb --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json @@ -0,0 +1,10 @@ +{ + "title": "ai.providers.ai_gateway", + "description": "Reference for AI Gateway provider APIs.", + "pages": [ + "provider", + "protocol", + "params", + "tools" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx new file mode 100644 index 00000000..2d8ba9cf --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx @@ -0,0 +1,13 @@ +--- +title: "ai.providers.ai_gateway params" +description: Reference for AI Gateway provider params. +type: reference +summary: Reference for GatewayParams and ProviderTimeoutsParams. +--- + +AI Gateway params configure gateway-specific request behavior. + +## Types + +- `GatewayParams` +- `ProviderTimeoutsParams` diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx new file mode 100644 index 00000000..ee8a8f91 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx @@ -0,0 +1,9 @@ +--- +title: "ai.providers.ai_gateway.GatewayV3Protocol" +description: Reference for the AI Gateway v3 protocol. +type: reference +summary: Reference for ai.providers.ai_gateway.GatewayV3Protocol. +--- + +`GatewayV3Protocol` translates SDK messages, tools, params, and generated files +to the AI Gateway v3 wire format. diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx new file mode 100644 index 00000000..6a8f1db1 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx @@ -0,0 +1,10 @@ +--- +title: "ai.providers.ai_gateway.GatewayProvider" +description: Reference for the AI Gateway provider. +type: reference +summary: Reference for ai.providers.ai_gateway.GatewayProvider. +--- + +`GatewayProvider` implements `Provider` for Vercel AI Gateway. + +Default configuration uses `AI_GATEWAY_API_KEY`. diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx new file mode 100644 index 00000000..cddb5b1c --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx @@ -0,0 +1,19 @@ +--- +title: "ai.providers.ai_gateway.tools" +description: Reference for AI Gateway provider-executed tools. +type: reference +summary: Reference for AI Gateway provider tool helpers. +--- + +AI Gateway tool helpers create provider-executed `ai.Tool` declarations. + +## Tools + +- `perplexity_search` +- `parallel_search` + +## Option models + +- `SourcePolicy` +- `Excerpts` +- `FetchPolicy` diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx new file mode 100644 index 00000000..ba5408ee --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx @@ -0,0 +1,17 @@ +--- +title: "ai.providers.anthropic" +description: Reference for Anthropic-compatible provider APIs. +type: reference +summary: Reference for ai.providers.anthropic. +--- + +`ai.providers.anthropic` contains the Anthropic-compatible provider, protocol, +and provider-executed tools. + +```python +provider = ai.get_provider("anthropic") +model = ai.Model("claude-sonnet-4-6", provider=provider) +``` + +The optional upstream Anthropic SDK loads lazily when the provider creates or +uses an SDK client. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json b/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json new file mode 100644 index 00000000..b7728e41 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.providers.anthropic", + "description": "Reference for Anthropic-compatible provider APIs.", + "pages": [ + "provider", + "protocol", + "tools" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx new file mode 100644 index 00000000..8a959f83 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx @@ -0,0 +1,9 @@ +--- +title: "ai.providers.anthropic.AnthropicMessagesProtocol" +description: Reference for the Anthropic Messages protocol. +type: reference +summary: Reference for ai.providers.anthropic.AnthropicMessagesProtocol. +--- + +`AnthropicMessagesProtocol` translates SDK messages and params to the Anthropic +Messages API wire format. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx new file mode 100644 index 00000000..f2b8205a --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx @@ -0,0 +1,17 @@ +--- +title: "ai.providers.anthropic.AnthropicCompatibleProvider" +description: Reference for the Anthropic-compatible provider. +type: reference +summary: Reference for ai.providers.anthropic.AnthropicCompatibleProvider. +--- + +`AnthropicCompatibleProvider` implements `Provider` for Anthropic-compatible +APIs. + +Default configuration uses: + +- `ANTHROPIC_API_KEY` +- `ANTHROPIC_BASE_URL` + +Pass `base_url`, `api_key`, or a custom client through `get_provider` when you +need explicit configuration. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx new file mode 100644 index 00000000..232174ce --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx @@ -0,0 +1,24 @@ +--- +title: "ai.providers.anthropic.tools" +description: Reference for Anthropic provider-executed tools. +type: reference +summary: Reference for Anthropic provider tool helpers. +--- + +Anthropic tool helpers create provider-executed `ai.Tool` declarations. + +## Tools + +- `web_search` +- `web_fetch` +- `code_execution` +- `computer_use` +- `text_editor` +- `bash` +- `memory` + +## Option models and constants + +- `UserLocation` +- `Citations` +- `BETA_HEADERS` diff --git a/docs/ai-python/content/docs/reference/ai.providers/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/index.mdx new file mode 100644 index 00000000..2012cfa5 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/index.mdx @@ -0,0 +1,19 @@ +--- +title: "ai.providers" +description: Reference for provider APIs. +type: reference +summary: Reference for ai.providers. +--- + +`ai.get_provider` is the usual entry point for application code. Use +`ai.providers` when you need provider classes, provider protocols, or +provider-specific namespaces. + +## Public APIs + +- `get_provider` +- `Provider` +- `ProviderProtocol` +- `OpenAICompatibleProvider` +- `AnthropicCompatibleProvider` +- `GatewayProvider` diff --git a/docs/ai-python/content/docs/reference/ai.providers/meta.json b/docs/ai-python/content/docs/reference/ai.providers/meta.json new file mode 100644 index 00000000..fdac8296 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.providers", + "description": "Reference for provider APIs.", + "pages": [ + "ai-gateway", + "openai", + "anthropic" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx new file mode 100644 index 00000000..51773b62 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx @@ -0,0 +1,17 @@ +--- +title: "ai.providers.openai" +description: Reference for OpenAI-compatible provider APIs. +type: reference +summary: Reference for ai.providers.openai. +--- + +`ai.providers.openai` contains the OpenAI-compatible provider, protocols, and +provider-executed tools. + +```python +provider = ai.get_provider("openai") +model = ai.Model("gpt-5", provider=provider) +``` + +The optional upstream OpenAI SDK loads lazily when the provider creates or uses +an SDK client. diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json b/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json new file mode 100644 index 00000000..044dd85f --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.providers.openai", + "description": "Reference for OpenAI-compatible provider APIs.", + "pages": [ + "provider", + "protocols", + "tools" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx new file mode 100644 index 00000000..9eb63ca1 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.providers.openai protocols" +description: Reference for OpenAI-compatible protocols. +type: reference +summary: Reference for OpenAIResponsesProtocol and OpenAIChatCompletionsProtocol. +--- + +OpenAI-compatible protocols translate SDK messages and params to OpenAI wire +formats. + +## Types + +- `OpenAIResponsesProtocol` +- `OpenAIChatCompletionsProtocol` diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx new file mode 100644 index 00000000..7e3fa1ea --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.providers.openai.OpenAICompatibleProvider" +description: Reference for the OpenAI-compatible provider. +type: reference +summary: Reference for ai.providers.openai.OpenAICompatibleProvider. +--- + +`OpenAICompatibleProvider` implements `Provider` for OpenAI-compatible APIs. + +Default configuration uses: + +- `OPENAI_API_KEY` +- `OPENAI_BASE_URL` + +Pass `base_url`, `api_key`, or a custom client through `get_provider` when you +need explicit configuration. diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx new file mode 100644 index 00000000..bf6380f6 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx @@ -0,0 +1,28 @@ +--- +title: "ai.providers.openai.tools" +description: Reference for OpenAI provider-executed tools. +type: reference +summary: Reference for OpenAI provider tool helpers. +--- + +OpenAI tool helpers create provider-executed `ai.Tool` declarations. + +## Tools + +- `web_search` +- `web_search_preview` +- `file_search` +- `code_interpreter` +- `image_generation` +- `local_shell` +- `shell` +- `apply_patch` +- `mcp` +- `tool_search` + +## Option models + +- `WebSearchUserLocation` +- `WebSearchFilters` +- `FileSearchRanking` +- `CodeInterpreterContainer` diff --git a/docs/ai-python/content/docs/reference/ai.tools/index.mdx b/docs/ai-python/content/docs/reference/ai.tools/index.mdx new file mode 100644 index 00000000..8e959bab --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.tools/index.mdx @@ -0,0 +1,24 @@ +--- +title: "ai.tools" +description: Reference for schema tool types and approval payloads. +type: reference +summary: Reference for ai.tools. +--- + +`ai.tools` defines model-facing tool declarations and tool approval +payloads. + +Schema-only tools and provider-executed tools are both represented as +`ai.Tool` values. Pass them to `ai.stream(..., tools=[...])` or to an agent +when the provider should receive the declaration. + +Provider-specific built-in tool factories live under provider namespaces such +as `ai.providers.openai.tools`, `ai.providers.anthropic.tools`, and +`ai.providers.ai_gateway.tools`. + +## Types + +- `Tool` +- `ToolSpec` +- `ToolConfig` +- `ToolApproval` diff --git a/docs/ai-python/content/docs/reference/ai.tools/meta.json b/docs/ai-python/content/docs/reference/ai.tools/meta.json new file mode 100644 index 00000000..a0c66531 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.tools/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.tools", + "description": "Reference for schema tool types and approval payloads.", + "pages": [ + "tool-spec", + "tool-config", + "tool-approval" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx b/docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx new file mode 100644 index 00000000..dde8c4f4 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx @@ -0,0 +1,13 @@ +--- +title: "ai.tools.ToolApproval" +description: "Payload model for human tool approvals." +type: reference +summary: "Reference for ai.tools.ToolApproval." +--- + +`ToolApproval` is a Pydantic model used with hooks and UI adapters when a +tool call needs external approval. + +```python +approval = await ai.hook("approve_tool", payload=ai.tools.ToolApproval) +``` diff --git a/docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx b/docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx new file mode 100644 index 00000000..f16e112e --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx @@ -0,0 +1,11 @@ +--- +title: "ai.tools.ToolConfig" +description: "Configure a model-facing tool declaration." +type: reference +summary: "Reference for ai.tools.ToolConfig." +--- + +`ToolConfig` stores provider-facing tool options. + +Use it with `ai.Tool` when a provider-executed tool needs configuration in +addition to its `ToolSpec`. diff --git a/docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx b/docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx new file mode 100644 index 00000000..bd58b6f4 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.tools.ToolSpec" +description: "Describe a model-facing tool schema." +type: reference +summary: "Reference for ai.tools.ToolSpec." +--- + +`ToolSpec` contains the provider-facing schema for a tool. + +Fields: + +- `name` +- `description` +- `input_schema` diff --git a/docs/ai-python/content/docs/reference/ai.types/index.mdx b/docs/ai-python/content/docs/reference/ai.types/index.mdx new file mode 100644 index 00000000..9f0b11e0 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.types/index.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.types" +description: "Reference for lower-level public type helper modules." +type: reference +summary: "Reference for public type helpers that are not top-level imports." +--- + +Most message, event, and tool APIs are documented under the root aliases +`ai.messages`, `ai.events`, and `ai.tools`. Use `ai.types` for lower-level +helper modules that do not have a shorter public alias. + +Public modules: + +- `ai.types.media` +- `ai.types.integrity` +- `ai.types.usage` diff --git a/docs/ai-python/content/docs/reference/ai.types/integrity.mdx b/docs/ai-python/content/docs/reference/ai.types/integrity.mdx new file mode 100644 index 00000000..e1c1d9ab --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.types/integrity.mdx @@ -0,0 +1,24 @@ +--- +title: "ai.types.integrity" +description: Reference for message history preparation. +type: reference +summary: Reference for ai.types.integrity. +--- + +Before provider calls, the SDK prepares message history. It strips internal +messages, removes non-model parts, repairs invalid tool args to `{}`, and +inserts error results for missing tool calls when possible. + +Use strict validation when you want repairable issues to raise: + +```python +from ai.types import integrity + + +integrity.prepare_messages(messages, mode="strict") +``` + +## APIs + +- `prepare_messages` +- `IntegrityError` diff --git a/docs/ai-python/content/docs/reference/ai.types/media.mdx b/docs/ai-python/content/docs/reference/ai.types/media.mdx new file mode 100644 index 00000000..a0a758e4 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.types/media.mdx @@ -0,0 +1,27 @@ +--- +title: "ai.types.media" +description: Reference for media helpers. +type: reference +summary: Reference for ai.types.media. +--- + +`ai.types.media` contains URL, data URL, media type inference, and magic-byte +detection helpers. + +## URL helpers + +- `is_url` +- `is_downloadable_url` +- `split_data_url` + +## Encoding helpers + +- `data_to_base64` +- `data_to_data_url` + +## Media type helpers + +- `infer_media_type` +- `detect_media_type` +- `detect_image_media_type` +- `detect_audio_media_type` diff --git a/docs/ai-python/content/docs/reference/ai.types/meta.json b/docs/ai-python/content/docs/reference/ai.types/meta.json new file mode 100644 index 00000000..06c62ca4 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.types/meta.json @@ -0,0 +1,9 @@ +{ + "title": "ai.types", + "description": "Reference for lower-level public type helper modules.", + "pages": [ + "media", + "integrity", + "usage" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.types/usage.mdx b/docs/ai-python/content/docs/reference/ai.types/usage.mdx new file mode 100644 index 00000000..aa0c5ae0 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.types/usage.mdx @@ -0,0 +1,20 @@ +--- +title: "ai.types.usage" +description: Reference for usage types. +type: reference +summary: Reference for ai.types.usage. +--- + +`Usage` is normalized token usage from a single model call. + +```python +usage.input_tokens +usage.output_tokens +usage.reasoning_tokens +usage.cache_read_tokens +usage.cache_write_tokens +usage.raw +usage.total_tokens +``` + +Use `usage_a + usage_b` to accumulate usage across calls. diff --git a/docs/ai-python/content/docs/reference/ai.util/decouple.mdx b/docs/ai-python/content/docs/reference/ai.util/decouple.mdx new file mode 100644 index 00000000..4970401a --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.util/decouple.mdx @@ -0,0 +1,11 @@ +--- +title: "ai.util.decouple" +description: "Run async iteration through a queue boundary." +type: reference +summary: "Reference for ai.util.decouple." +--- + +`decouple` separates producer and consumer timing for an async iterable. + +Use it when a producer should continue running while another task consumes +items at a different pace. diff --git a/docs/ai-python/content/docs/reference/ai.util/index.mdx b/docs/ai-python/content/docs/reference/ai.util/index.mdx new file mode 100644 index 00000000..16be1be0 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.util/index.mdx @@ -0,0 +1,17 @@ +--- +title: "ai.util" +description: Reference for utilities. +type: reference +summary: Reference for ai.util. +--- + +`ai.util` contains asynchronous utility primitives used by the SDK. + +## Public APIs + +- `AsyncIterableQueue` +- `MultiWaiter` +- `unwrap_generator_exit` +- `maybe_aclosing` +- `decouple` +- `merge` diff --git a/docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx b/docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx new file mode 100644 index 00000000..a1bc2eb6 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.util lifecycle helpers" +description: "Reference for async lifecycle helpers." +type: reference +summary: "Reference for ai.util.unwrap_generator_exit and ai.util.maybe_aclosing." +--- + +Lifecycle helpers: + +- `unwrap_generator_exit` +- `maybe_aclosing` + +Use these helpers when implementing custom async generators or safely +closing optional async resources. diff --git a/docs/ai-python/content/docs/reference/ai.util/merge.mdx b/docs/ai-python/content/docs/reference/ai.util/merge.mdx new file mode 100644 index 00000000..4bb4069b --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.util/merge.mdx @@ -0,0 +1,14 @@ +--- +title: "ai.util.merge" +description: "Merge async iterables into one stream." +type: reference +summary: "Reference for ai.util.merge." +--- + +`merge` consumes multiple async iterables concurrently and yields items as +they become available. + +```python +async for event in ai.util.merge(stream, tool_runner.events()): + ... +``` diff --git a/docs/ai-python/content/docs/reference/ai.util/meta.json b/docs/ai-python/content/docs/reference/ai.util/meta.json new file mode 100644 index 00000000..1181caa9 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.util/meta.json @@ -0,0 +1,10 @@ +{ + "title": "ai.util", + "description": "Reference for async utility helpers.", + "pages": [ + "merge", + "decouple", + "queues", + "lifecycle" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai.util/queues.mdx b/docs/ai-python/content/docs/reference/ai.util/queues.mdx new file mode 100644 index 00000000..a1d3e1c5 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai.util/queues.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.util queues" +description: "Reference for queue and waiter primitives." +type: reference +summary: "Reference for ai.util.AsyncIterableQueue and ai.util.MultiWaiter." +--- + +Queue primitives: + +- `AsyncIterableQueue` +- `MultiWaiter` + +`AsyncIterableQueue` is an async iterable queue that can be closed. +`MultiWaiter` waits for the first completed item across multiple async +sources. diff --git a/docs/ai-python/content/docs/reference/ai/agent-factory.mdx b/docs/ai-python/content/docs/reference/ai/agent-factory.mdx new file mode 100644 index 00000000..01ee01da --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/agent-factory.mdx @@ -0,0 +1,21 @@ +--- +title: "ai.agent" +description: Create an Agent with the default loop. +type: reference +summary: Reference for ai.agent. +--- + +`agent` creates an `Agent`. + +```python +agent = ai.agent(tools=[contact_mothership]) +``` + +## Arguments + +- `tools`: Optional `AgentTool` values from `@ai.tool` and schema-only `ai.Tool` + declarations for provider-executed tools. + +## Return value + +Returns `ai.Agent`. diff --git a/docs/ai-python/content/docs/reference/ai/agent-tool.mdx b/docs/ai-python/content/docs/reference/ai/agent-tool.mdx new file mode 100644 index 00000000..b20c2ed7 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/agent-tool.mdx @@ -0,0 +1,19 @@ +--- +title: "ai.AgentTool" +description: Reference for executable agent tools. +type: reference +summary: Reference for ai.AgentTool. +--- + +`AgentTool` binds a model-facing `Tool` declaration to an executable Python +function. + +```python +tool.name +tool.tool +tool.fn +tool.validator +tool.require_approval +``` + +Pass `AgentTool` values to `ai.agent(tools=[...])`. diff --git a/docs/ai-python/content/docs/reference/agent.mdx b/docs/ai-python/content/docs/reference/ai/agent.mdx similarity index 55% rename from docs/ai-python/content/docs/reference/agent.mdx rename to docs/ai-python/content/docs/reference/ai/agent.mdx index 5083b60f..0a30ccb3 100644 --- a/docs/ai-python/content/docs/reference/agent.mdx +++ b/docs/ai-python/content/docs/reference/ai/agent.mdx @@ -1,28 +1,12 @@ --- -title: "ai.agent and Agent" -description: Create agents and run the default agent loop. +title: "ai.Agent" +description: Run the default agent loop with tools. type: reference -summary: Reference for ai.agent, Agent, Agent.run, Agent.loop, and AgentStream. +summary: Reference for ai.Agent. --- -`ai.agent` creates an `Agent`. An agent streams model output, dispatches Python -tools, appends tool results to history, and repeats until the model returns a -final assistant message. - -```python -agent = ai.agent(tools=[contact_mothership]) -``` - -## Function - -```python -ai.agent(*, tools=None) -> ai.Agent -``` - -`tools` accepts `AgentTool` values from `@ai.tool` and schema-only `ai.Tool` -values for provider-executed tools. - -## Agent +`Agent` streams model output, dispatches Python tools, appends tool results to +history, and repeats until the model returns a final assistant message. ```python agent = ai.Agent(tools=[...]) @@ -31,7 +15,7 @@ agent.tools `agent.tools` returns a copy of registered executable tools. -## Agent.run +## run ```python async with agent.run( @@ -53,7 +37,7 @@ Arguments: ## AgentStream -`Agent.run` yields an `AgentStream`. +`Agent.run` yields an `AgentStream`. Read the final output after iteration. ```python stream.context @@ -61,10 +45,7 @@ stream.messages stream.output ``` -`stream.messages` is the updated message history. `stream.output` reads the -final assistant message. With no `output_type`, it returns text. - -## Agent.loop +## loop Override `Agent.loop(context)` to customize control flow. The default loop uses `ai.stream`, `ToolRunner`, `Context.resolve`, and `Context.add`. diff --git a/docs/ai-python/content/docs/reference/tool-runner.mdx b/docs/ai-python/content/docs/reference/ai/context.mdx similarity index 50% rename from docs/ai-python/content/docs/reference/tool-runner.mdx rename to docs/ai-python/content/docs/reference/ai/context.mdx index a6c7e36e..fe1d7bf8 100644 --- a/docs/ai-python/content/docs/reference/tool-runner.mdx +++ b/docs/ai-python/content/docs/reference/ai/context.mdx @@ -1,15 +1,13 @@ --- -title: "ToolRunner, ToolCall, and Context" -description: Resolve, schedule, and collect tool calls in custom loops. +title: "ai.Context" +description: Resolve and update agent context. type: reference -summary: Reference for ToolRunner, ToolCall, ai.agents.BoundToolCall, ai.agents.GatedToolCall, and Context. +summary: Reference for ai.Context. --- Custom loops use `Context` to resolve model tool calls and `ToolRunner` to run them. -## Context - `Context` contains the state for one agent run. ```python @@ -51,35 +49,3 @@ context.add(tool_runner.get_tool_message()) `add` appends messages to history. Replay-marked assistant messages are skipped to avoid duplicate history during resume flows. - -## ToolCall - -`ToolCall` is a protocol for executable tool calls. - -```python -tool_call.id -tool_call.name -tool_call.fn -tool_call.kwargs -result = await tool_call() -``` - -`ai.agents.BoundToolCall` is the default implementation. -`ai.agents.GatedToolCall` wraps another tool call with an approval hook. - -## ToolRunner - -```python -async with ai.ToolRunner() as runner: - runner.schedule(tool_call) - async for result in runner.events(): - ... - message = runner.get_tool_message() -``` - -`schedule` starts the call in the runner's task group. `events()` yields -`ToolCallResult` values as calls finish. `get_tool_message()` merges collected -results into one `role="tool"` message. - -Use `add_result(result)` when a custom loop executes a tool itself but still -wants the runner to aggregate the result message. diff --git a/docs/ai-python/content/docs/reference/generate.mdx b/docs/ai-python/content/docs/reference/ai/generate.mdx similarity index 61% rename from docs/ai-python/content/docs/reference/generate.mdx rename to docs/ai-python/content/docs/reference/ai/generate.mdx index 66a8911f..3f995515 100644 --- a/docs/ai-python/content/docs/reference/generate.mdx +++ b/docs/ai-python/content/docs/reference/ai/generate.mdx @@ -2,11 +2,11 @@ title: "ai.generate" description: Generate non-streaming media responses. type: reference -summary: Reference for ai.generate and media generation params. +summary: Reference for ai.generate. --- -`ai.generate` calls non-streaming generation APIs, such as image and video -models, and returns a `Message`. +`ai.generate` calls non-streaming generation APIs, such as image and +video models, and returns a `Message`. ```python result = await ai.generate( @@ -28,33 +28,7 @@ await ai.generate(model, messages, params) - `messages`: list of `ai.messages.Message`. - `params`: `ai.ImageParams` or `ai.VideoParams`. -## ImageParams - -```python -ai.ImageParams( - n=1, - size=None, - aspect_ratio=None, - seed=None, - provider_options={}, -) -``` - -## VideoParams - -```python -ai.VideoParams( - n=1, - aspect_ratio=None, - resolution=None, - duration=None, - fps=None, - seed=None, - provider_options={}, -) -``` - -## Return Value +## Return value `ai.generate` returns an assistant `Message`. Read generated files through `message.files` or use the normal message helpers for text, reasoning, and diff --git a/docs/ai-python/content/docs/reference/ai/get-model.mdx b/docs/ai-python/content/docs/reference/ai/get-model.mdx new file mode 100644 index 00000000..193c6217 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/get-model.mdx @@ -0,0 +1,26 @@ +--- +title: "ai.get_model" +description: Resolve a model reference from an id. +type: reference +summary: Reference for ai.get_model. +--- + +`get_model` resolves a model id to a `Model`. + +```python +model = ai.get_model("anthropic/claude-sonnet-4") +model = ai.get_model("openai:gpt-5") +model = ai.get_model() +``` + +Unprefixed ids route through AI Gateway. Calling `get_model()` with no argument +reads `AI_SDK_DEFAULT_MODEL`. + +## Arguments + +- `model_id`: Optional model id. Provider-prefixed ids use `provider:model`. + Gateway model ids can use `provider/model`. + +## Return value + +Returns `ai.Model`. diff --git a/docs/ai-python/content/docs/reference/ai/get-provider.mdx b/docs/ai-python/content/docs/reference/ai/get-provider.mdx new file mode 100644 index 00000000..9189e5de --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/get-provider.mdx @@ -0,0 +1,20 @@ +--- +title: "ai.get_provider" +description: Resolve and configure providers. +type: reference +summary: Reference for ai.get_provider. +--- + +`get_provider` resolves a provider by id. + +```python +provider = ai.get_provider("openai") +provider = ai.get_provider( + "openai", + base_url="http://localhost:1234/v1", + api_key="your_access_token_here", +) +``` + +Known providers include AI Gateway, OpenAI-compatible providers, and +Anthropic-compatible providers. diff --git a/docs/ai-python/content/docs/reference/ai/hooks.mdx b/docs/ai-python/content/docs/reference/ai/hooks.mdx new file mode 100644 index 00000000..1b955cae --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/hooks.mdx @@ -0,0 +1,47 @@ +--- +title: "ai hooks" +description: "Suspend and resume agent workflows for external input." +type: reference +summary: "Reference for ai.hook, ai.resolve_hook, ai.abort_pending_hook, and ai.cancel_hook." +--- + +Hooks let an agent pause while another process or UI supplies a decision. + +## hook + +```python +approval = await ai.hook( + "approve_contact_mothership", + payload=ai.tools.ToolApproval, + metadata={"tool": "contact_mothership"}, +) +``` + +`hook` emits a pending hook event and waits for a matching resolution. The +return value is an instance of the `payload` model. + +## resolve_hook + +```python +ai.resolve_hook(label, data, payload=None) +``` + +`data` can be a dict, a Pydantic model, or an exception. If no live hook +exists, the resolution is stored and consumed by the next matching hook. + +## abort_pending_hook + +```python +ai.abort_pending_hook(hook_part) +``` + +Mark a serialized pending hook as aborted before replaying or continuing a +run. + +## cancel_hook + +```python +await ai.cancel_hook(label, reason="client disconnected") +``` + +Cancel a live hook by label. diff --git a/docs/ai-python/content/docs/reference/ai/index.mdx b/docs/ai-python/content/docs/reference/ai/index.mdx new file mode 100644 index 00000000..90adc8bb --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/index.mdx @@ -0,0 +1,28 @@ +--- +title: "ai" +description: "Reference for top-level ai exports." +type: reference +summary: "Reference for names imported directly from ai." +--- + +Import `ai` for application code. + +```python +import ai + +model = ai.get_model("anthropic/claude-sonnet-4") +messages = [ai.user_message("Hello")] +``` + +This section covers names imported directly from `ai`: model calls, model +objects and params, message builders, agent primitives, tool primitives, +provider lookup, and provider base types. + +Use sibling module sections for public submodule APIs: + +- `ai.events` +- `ai.messages` +- `ai.tools` +- `ai.providers` +- `ai.agents` +- `ai.types` diff --git a/docs/ai-python/content/docs/reference/ai/media-generation-params.mdx b/docs/ai-python/content/docs/reference/ai/media-generation-params.mdx new file mode 100644 index 00000000..13f69d70 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/media-generation-params.mdx @@ -0,0 +1,38 @@ +--- +title: "ai media generation params" +description: Reference for media generation params. +type: reference +summary: Reference for ImageParams, VideoParams, and GenerateParams. +--- + +Media params configure non-streaming generation with `ai.generate`. + +## ImageParams + +```python +ai.ImageParams( + n=1, + size=None, + aspect_ratio=None, + seed=None, + provider_options={}, +) +``` + +## VideoParams + +```python +ai.VideoParams( + n=1, + aspect_ratio=None, + resolution=None, + duration=None, + fps=None, + seed=None, + provider_options={}, +) +``` + +## GenerateParams + +`GenerateParams` is the accepted media params union for `ai.generate`. diff --git a/docs/ai-python/content/docs/reference/ai/message-builders.mdx b/docs/ai-python/content/docs/reference/ai/message-builders.mdx new file mode 100644 index 00000000..88910dc4 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/message-builders.mdx @@ -0,0 +1,15 @@ +--- +title: "ai message builders" +description: Reference for message builder helpers. +type: reference +summary: Reference for system_message, user_message, assistant_message, and tool_message. +--- + +Message builders create `Message` values. + +```python +ai.system_message("You are concise.") +ai.user_message("Hello", ai.file_part(data, media_type="image/png")) +ai.assistant_message("Hi") +ai.tool_message(tool_call_id="tc_1", result="done", tool_name="lookup") +``` diff --git a/docs/ai-python/content/docs/reference/ai/meta.json b/docs/ai-python/content/docs/reference/ai/meta.json new file mode 100644 index 00000000..69fd502b --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/meta.json @@ -0,0 +1,31 @@ +{ + "title": "ai", + "description": "Reference for top-level ai exports.", + "pages": [ + "stream", + "generate", + "probe", + "get-model", + "model", + "model-params", + "routing-params", + "media-generation-params", + "message-builders", + "part-builders", + "tool", + "tool-decorator", + "tool-results", + "agent", + "agent-factory", + "context", + "agent-tool", + "tool-call", + "tool-runner", + "streaming-tools", + "hooks", + "yield-from", + "get-provider", + "provider", + "provider-protocol" + ] +} diff --git a/docs/ai-python/content/docs/reference/ai/model-params.mdx b/docs/ai-python/content/docs/reference/ai/model-params.mdx new file mode 100644 index 00000000..3426a4b8 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/model-params.mdx @@ -0,0 +1,46 @@ +--- +title: "ai model params" +description: "Reference for model request parameter types." +type: reference +summary: "Reference for parameter objects passed to ai.stream, ai.generate, and Agent.run." +--- + +Model params are top-level `ai` types. + +Use `InferenceRequestParams` with `ai.stream` and `Agent.run`. Use +`ImageParams` and `VideoParams` with `ai.generate`. + +## Request params + +- `InferenceRequestParams` +- `ProviderServiceParams` +- `ReasoningParams` +- `OutputParams` +- `CacheParams` +- `ContextManagementParams` + +## Sampling params + +- `TemperatureSamplerParams` +- `TopKSamplerParams` +- `TopPSamplerParams` +- `MinPSamplerParams` +- `RepetitionPenaltyParams` +- `SeedSamplerParams` +- `RandomSeed` +- `RANDOM` +- `DEFAULT` +- `UNSET` + +## Tool calling params + +- `ToolCallingParams` +- `ToolChoiceMode` +- `ToolSelection` +- `ToolRef` + +```python +params = ai.InferenceRequestParams().with_temperature(0) +async with ai.stream(model, messages, params=params) as stream: + ... +``` diff --git a/docs/ai-python/content/docs/reference/ai/model.mdx b/docs/ai-python/content/docs/reference/ai/model.mdx new file mode 100644 index 00000000..cf77c4cc --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/model.mdx @@ -0,0 +1,30 @@ +--- +title: "ai.Model" +description: Reference for model references. +type: reference +summary: Reference for ai.Model. +--- + +`Model` identifies what to call. Providers own credentials, clients, endpoints, +model listing, and wire translation. + +```python +model = ai.Model("gpt-5", provider=provider) +model.id +model.provider +model.protocol +model.with_protocol(protocol) +``` + +`Model` is a lightweight reference. It does not own network state. + +## Fields + +- `id`: Provider model id. +- `provider`: Provider instance or provider id. +- `protocol`: Optional provider protocol override. + +## Methods + +- `with_protocol(protocol)`: Return a copy that uses a specific provider + protocol. diff --git a/docs/ai-python/content/docs/reference/ai/part-builders.mdx b/docs/ai-python/content/docs/reference/ai/part-builders.mdx new file mode 100644 index 00000000..c7021c27 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/part-builders.mdx @@ -0,0 +1,16 @@ +--- +title: "ai part builders" +description: Reference for message part builders. +type: reference +summary: Reference for text_part, file_part, thinking, content_output, and tool_result_part. +--- + +Part builders create message part values. + +```python +ai.text_part("hello") +ai.file_part(data, media_type="image/png", filename="image.png") +ai.thinking("reasoning text") +ai.content_output("caption", ai.file_part(png_bytes, media_type="image/png")) +ai.tool_result_part("tc_1", result={"ok": True}, tool_name="lookup") +``` diff --git a/docs/ai-python/content/docs/reference/ai/probe.mdx b/docs/ai-python/content/docs/reference/ai/probe.mdx new file mode 100644 index 00000000..25ac8518 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/probe.mdx @@ -0,0 +1,15 @@ +--- +title: "ai.probe" +description: Check whether a provider can reach a model. +type: reference +summary: Reference for ai.probe. +--- + +`probe` asks the model provider to verify that a model exists and is reachable. + +```python +await ai.probe(model) +``` + +It raises a provider error unless the provider is configured, reachable, and +able to find the model. diff --git a/docs/ai-python/content/docs/reference/ai/provider-protocol.mdx b/docs/ai-python/content/docs/reference/ai/provider-protocol.mdx new file mode 100644 index 00000000..6d49c377 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/provider-protocol.mdx @@ -0,0 +1,11 @@ +--- +title: "ai.ProviderProtocol" +description: Reference for provider wire protocols. +type: reference +summary: Reference for ai.ProviderProtocol. +--- + +Provider protocols translate messages, tools, params, and generated files to +provider wire formats. + +Provider instances use a protocol for `stream` and `generate` calls. diff --git a/docs/ai-python/content/docs/reference/ai/provider.mdx b/docs/ai-python/content/docs/reference/ai/provider.mdx new file mode 100644 index 00000000..843cbffa --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/provider.mdx @@ -0,0 +1,32 @@ +--- +title: "ai.Provider" +description: Reference for provider instances. +type: reference +summary: Reference for ai.Provider. +--- + +Provider instances own credentials, clients, endpoints, model listing, and wire +translation. + +```python +provider.name +provider.base_url +provider.default_base_url +provider.api_key +provider.api_key_env +provider.base_url_env +provider.headers +provider.client +provider.is_configured() +await provider.list_models() +await provider.probe(model) +await provider.aclose() +``` + +`provider.stream(...)` and `provider.generate(...)` are usually called through +`ai.stream` and `ai.generate`. + +## Custom providers + +Add a provider by subclassing `ai.Provider`, setting `handles`, and +implementing provider-specific behavior. diff --git a/docs/ai-python/content/docs/reference/ai/routing-params.mdx b/docs/ai-python/content/docs/reference/ai/routing-params.mdx new file mode 100644 index 00000000..f67e2e02 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/routing-params.mdx @@ -0,0 +1,19 @@ +--- +title: "ai routing params" +description: Reference for routing parameter types. +type: reference +summary: Reference for RoutingParams, routing targets, regions, and ranking strategies. +--- + +Routing params configure provider or gateway routing behavior. + +## Types + +- `RoutingParams` +- `RoutingTarget` +- `RoutingTargetChain` +- `GeoRegion` +- `CloudRegion` +- `ProviderRankingStrategy` + +Use `GLOBAL` for global routing when supported by the provider. diff --git a/docs/ai-python/content/docs/reference/stream.mdx b/docs/ai-python/content/docs/reference/ai/stream.mdx similarity index 100% rename from docs/ai-python/content/docs/reference/stream.mdx rename to docs/ai-python/content/docs/reference/ai/stream.mdx diff --git a/docs/ai-python/content/docs/reference/ai/streaming-tools.mdx b/docs/ai-python/content/docs/reference/ai/streaming-tools.mdx new file mode 100644 index 00000000..7bf4d8fa --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/streaming-tools.mdx @@ -0,0 +1,17 @@ +--- +title: "ai streaming tools" +description: Reference for streaming tool return aliases. +type: reference +summary: Reference for StreamingTextTool, StreamingStatusTool, and SubAgentTool. +--- + +Async-generator tools can yield partial output while they run. The agent emits +`ai.events.PartialToolCallResult` events for yielded values. + +## Built-in aliases + +- `StreamingTextTool`: Concatenate yielded strings. +- `StreamingStatusTool[T]`: Treat intermediate yields as status updates and the + last yielded value as the final result. +- `SubAgentTool`: Forward nested agent events and use the nested final text as + model input. diff --git a/docs/ai-python/content/docs/reference/ai/tool-call.mdx b/docs/ai-python/content/docs/reference/ai/tool-call.mdx new file mode 100644 index 00000000..4b5c1fa1 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/tool-call.mdx @@ -0,0 +1,24 @@ +--- +title: "ai.agents tool calls" +description: Reference for executable tool calls. +type: reference +summary: Reference for ToolCall, BoundToolCall, and GatedToolCall. +--- + +Tool calls are executable runtime objects produced by `Context.resolve`. + +## ToolCall + +```python +tool_call.id +tool_call.name +tool_call.fn +tool_call.kwargs +result = await tool_call() +``` + +## Implementations + +- `BoundToolCall`: Default executable call. +- `GatedToolCall`: Wraps another call with an approval hook. +- `ToolCallCallable`: Protocol for values a `ToolRunner` can schedule. diff --git a/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx b/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx new file mode 100644 index 00000000..b2c1c48e --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx @@ -0,0 +1,33 @@ +--- +title: "ai.tool" +description: Define executable tools from Python functions. +type: reference +summary: Reference for ai.tool. +--- + +`@ai.tool` turns an async Python function into an executable `AgentTool` plus a +model-facing `ai.Tool` declaration. + +```python +@ai.tool +async def contact_mothership(query: str) -> str: + """Contact the mothership.""" + return "Soon." +``` + +## Forms + +```python +@ai.tool +async def name(...) -> Result: ... + +@ai.tool(require_approval=True) +async def name(...) -> Result: ... + +@ai.tool(aggregator=...) +async def name(...) -> AsyncGenerator[Item]: ... +``` + +The function name becomes the tool name. The docstring becomes the tool +description. The function signature becomes a Pydantic validator and JSON +schema. diff --git a/docs/ai-python/content/docs/reference/ai/tool-results.mdx b/docs/ai-python/content/docs/reference/ai/tool-results.mdx new file mode 100644 index 00000000..b1c58919 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/tool-results.mdx @@ -0,0 +1,17 @@ +--- +title: "ai.agents tool result helpers" +description: Create tool result events and pending tool results. +type: reference +summary: Reference for tool_result and pending_tool_result. +--- + +Tool result helpers create event-layer values used by custom loops and +resumable tool approval flows. + +```python +ai.tool_result(tool_call_id="tc_1", tool_name="lookup", result={"ok": True}) +ai.pending_tool_result(hook_part, tool_call_id="tc_1", tool_name="lookup") +``` + +Use message builders such as `ai.tool_message` and `ai.tool_result_part` for +message-layer values. diff --git a/docs/ai-python/content/docs/reference/ai/tool-runner.mdx b/docs/ai-python/content/docs/reference/ai/tool-runner.mdx new file mode 100644 index 00000000..669fc07b --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/tool-runner.mdx @@ -0,0 +1,24 @@ +--- +title: "ai.ToolRunner" +description: Schedule and collect tool calls in custom loops. +type: reference +summary: Reference for ai.ToolRunner. +--- + +Custom loops use `Context` to resolve model tool calls and `ToolRunner` to run +them. + +```python +async with ai.ToolRunner() as runner: + runner.schedule(tool_call) + async for result in runner.events(): + ... + message = runner.get_tool_message() +``` + +`schedule` starts the call in the runner's task group. `events()` yields +`ToolCallResult` values as calls finish. `get_tool_message()` merges collected +results into one `role="tool"` message. + +Use `add_result(result)` when a custom loop executes a tool itself but still +wants the runner to aggregate the result message. diff --git a/docs/ai-python/content/docs/reference/ai/tool.mdx b/docs/ai-python/content/docs/reference/ai/tool.mdx new file mode 100644 index 00000000..74ccbdb8 --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/tool.mdx @@ -0,0 +1,22 @@ +--- +title: "ai.Tool" +description: "Declare a schema-only or provider-executed tool." +type: reference +summary: "Reference for ai.Tool." +--- + +`Tool` is the model-facing tool declaration used by providers. + +```python +tool = ai.Tool( + spec=ai.tools.ToolSpec( + name="lookup", + description="Look up a value.", + input_schema={"type": "object", "properties": {}}, + ) +) +``` + +Pass `Tool` values to `ai.stream(..., tools=[...])` or to an agent when the +provider should receive the declaration directly. For Python callables, use +`@ai.tool` instead. diff --git a/docs/ai-python/content/docs/reference/ai/yield-from.mdx b/docs/ai-python/content/docs/reference/ai/yield-from.mdx new file mode 100644 index 00000000..270f86cc --- /dev/null +++ b/docs/ai-python/content/docs/reference/ai/yield-from.mdx @@ -0,0 +1,16 @@ +--- +title: "ai.yield_from" +description: "Forward events from nested async generators." +type: reference +summary: "Reference for ai.yield_from." +--- + +`yield_from` forwards events from a nested async generator and returns the +nested generator result. + +It is useful in custom agent loops and streaming tools that compose another +async generator. + +```python +result = await ai.yield_from(generator) +``` diff --git a/docs/ai-python/content/docs/reference/events.mdx b/docs/ai-python/content/docs/reference/events.mdx deleted file mode 100644 index 55207bf8..00000000 --- a/docs/ai-python/content/docs/reference/events.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: "ai.events" -description: Reference for stream, agent, tool, and hook events. -type: reference -summary: Reference for ai.events event classes and aggregation helpers. ---- - -Streams and agents yield event objects from `ai.events`. Events are Pydantic -models. - -## Model Stream Events - -Text: - -- `StreamStart` -- `TextStart` -- `TextDelta` -- `TextEnd` -- `StreamEnd` - -Reasoning: - -- `ReasoningStart` -- `ReasoningDelta` -- `ReasoningEnd` - -Python tool calls: - -- `ToolStart` -- `ToolDelta` -- `ToolEnd` - -Provider-executed tools: - -- `BuiltinToolStart` -- `BuiltinToolDelta` -- `BuiltinToolEnd` -- `BuiltinToolResult` - -Files and hooks: - -- `FileEvent` -- `HookSuspension` -- `HookResolution` - -## Common Event Fields - -Model stream events inherit from `BaseEvent`: - -```python -event.message -event.usage -event.provider_metadata -``` - -`event.message` is the current aggregated assistant message. - -## Agent Events - -Agents can also emit: - -- `ToolCallResult` -- `PartialToolCallResult` -- `HookEvent` - -`ToolCallResult` carries the tool result message and result parts. -`PartialToolCallResult` carries values yielded by streaming tools and -`yield_from`. `HookEvent` carries an internal hook message and `HookPart`. - -## Replay Message Events - -```python -async for event in ai.events.replay_message_events(message): - ... -``` - -`replay_message_events` synthesizes stream events from a complete `Message`. -Use it when cached, durable, or test messages need to flow through code that -expects stream events. - -## Aggregator - -`ai.events.Aggregator[Item, Result, ModelInput]` is the interface used by -streaming tools and `yield_from`. - -```python -class MyAggregator(ai.events.Aggregator[Item, Result, ModelInput]): - def feed(self, item: Item) -> None: ... - def snapshot(self) -> Result: ... - - @classmethod - def to_model_input(cls, snapshot: Result) -> ModelInput: ... -``` - -`snapshot()` is the rich value stored in tool results. `get_model_input()` is -the value sent back to the model. diff --git a/docs/ai-python/content/docs/reference/hooks.mdx b/docs/ai-python/content/docs/reference/hooks.mdx deleted file mode 100644 index 7840e1ab..00000000 --- a/docs/ai-python/content/docs/reference/hooks.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: "ai.hook, resolve_hook, and cancel_hook" -description: Suspend, resolve, abort, and cancel hooks. -type: reference -summary: Reference for ai.hook, resolve_hook, abort_pending_hook, cancel_hook, and HookEvent. ---- - -Hooks suspend an agent workflow until external input arrives. Tool approvals use -the same hook mechanism. - -## ai.hook - -```python -approval = await ai.hook( - "approve_contact_mothership", - payload=ai.tools.ToolApproval, - metadata={"tool": "contact_mothership"}, -) -``` - -Arguments: - -- `label`: unique hook identifier. -- `payload`: Pydantic model class used to validate the resolution. -- `metadata`: optional data surfaced to clients. - -The return value is an instance of `payload`. - -## resolve_hook - -```python -ai.resolve_hook(label, data, payload=None) -``` - -`data` can be a dict, a Pydantic model, or an exception. If a live hook exists, -it resolves immediately. If no live hook exists, the resolution is stored and -consumed by the next matching `ai.hook` call. - -## abort_pending_hook - -```python -ai.abort_pending_hook(hook_part) -``` - -Aborts the hook identified by `hook_part.hook_id` by registering a -pending-hook exception. This is the common serverless resume pattern after a -pending hook event is persisted. - -## cancel_hook - -```python -await ai.cancel_hook(label, reason="client disconnected") -``` - -Cancels a live hook and emits a cancelled hook event. It raises `ValueError` -when no hook with that label is currently pending. - -## Events and Messages - -Hooks emit `ai.events.HookEvent`. The event message has role `internal` and -contains a `HookPart` with: - -- `hook_id` -- `hook_type` -- `status`: `pending`, `resolved`, or `cancelled` -- `metadata` -- `resolution` diff --git a/docs/ai-python/content/docs/reference/index.mdx b/docs/ai-python/content/docs/reference/index.mdx index 0f651871..46c36de7 100644 --- a/docs/ai-python/content/docs/reference/index.mdx +++ b/docs/ai-python/content/docs/reference/index.mdx @@ -1,21 +1,13 @@ --- -title: Reference -description: Public API reference for the AI SDK for Python. +title: "Reference" +description: "Public API reference for the AI SDK for Python." type: reference -summary: Look up public APIs by the names you import and call. +summary: "Look up public APIs by the names you import and call." --- -Reference pages are organized around public APIs. Use Basics for workflows and -this section for call shapes, return values, and object fields. +Reference pages are organized by public module. -## API groups - -- `ai.stream`, `ai.Stream`, `ai.generate`, and `ai.probe` -- `ai.agent`, `ai.Agent`, `Agent.run`, and `Agent.loop` -- `@ai.tool`, `AgentTool`, streaming tool aliases, and tool result helpers -- `ToolRunner`, `ToolCall`, and `Context` -- `ai.hook`, `resolve_hook`, `abort_pending_hook`, and `cancel_hook` -- `Message`, message parts, and message builders -- `ai.events` -- `get_model`, `Model`, `get_provider`, and `Provider` -- `ai.agents.ui.ai_sdk` +Start with `ai` for names imported directly from the top-level package, such +as `ai.stream`, `ai.Agent`, and `ai.Tool`. Use sibling module sections such as +`ai.events`, `ai.messages`, `ai.providers`, and `ai.agents` for public +submodule APIs. diff --git a/docs/ai-python/content/docs/reference/messages.mdx b/docs/ai-python/content/docs/reference/messages.mdx deleted file mode 100644 index bb13e1b4..00000000 --- a/docs/ai-python/content/docs/reference/messages.mdx +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: "Message and message builders" -description: Reference for Message, message parts, and message builder helpers. -type: reference -summary: Reference for Message, parts, builders, serialization, and message history invariants. ---- - -Messages are Pydantic models. They are the durable state shared by model calls, -agents, tools, UI adapters, and resume flows. - -## Message - -```python -message.role -message.parts -message.id -message.turn_id -message.usage -message.provider_metadata -message.replay -``` - -Roles are `user`, `assistant`, `system`, `tool`, and `internal`. - -## Convenience Properties - -```python -message.text -message.reasoning -message.tool_calls -message.tool_results -message.builtin_tool_calls -message.builtin_tool_returns -message.files -message.images -message.videos -message.get_output(output_type=None) -``` - -`get_output()` returns text by default. With a Pydantic model, it validates the -message text as JSON and returns that model. - -## Builders - -```python -ai.system_message("...") -ai.user_message("...", ai.file_part(data, media_type="image/png")) -ai.assistant_message("...") -ai.tool_message(tool_call_id="tc_1", result="done", tool_name="lookup") -``` - -Part builders: - -```python -ai.text_part("hello") -ai.file_part(data, media_type="image/png", filename="image.png") -ai.thinking("reasoning text") -ai.content_output("caption", ai.file_part(png_bytes, media_type="image/png")) -ai.tool_result_part("tc_1", result={"ok": True}, tool_name="lookup") -``` - -## Parts - -Common message parts are: - -- `TextPart` -- `FilePart` -- `ReasoningPart` -- `ToolCallPart` -- `ToolResultPart` -- `BuiltinToolCallPart` -- `BuiltinToolReturnPart` -- `HookPart` - -`ToolResultPart.get_model_input()` returns the value sent back to the model. For -most tools this is the same as `result`. Aggregator-backed tools can store a -rich `result` while sending a simpler model-facing value. - -## Serialization - -```python -encoded = [message.model_dump(mode="json") for message in messages] -restored = [ai.messages.Message.model_validate(item) for item in encoded] -``` - -Persist messages after completed or suspended runs. Recreate providers, hooks, -streams, and other live runtime objects on the next request. - -## History Preparation - -Before provider calls, the SDK prepares message history. It strips internal -messages, removes non-model parts, repairs invalid tool args to `{}`, and -inserts error results for missing tool calls when possible. - -Use strict validation when you want repairable issues to raise: - -```python -from ai.types import integrity - - -integrity.prepare_messages(messages, mode="strict") -``` diff --git a/docs/ai-python/content/docs/reference/meta.json b/docs/ai-python/content/docs/reference/meta.json index 05f1cff0..4953abd9 100644 --- a/docs/ai-python/content/docs/reference/meta.json +++ b/docs/ai-python/content/docs/reference/meta.json @@ -2,15 +2,16 @@ "title": "Reference", "description": "API reference for public AI SDK for Python APIs.", "pages": [ - "stream", - "generate", - "agent", - "tool", - "tool-runner", - "hooks", - "messages", - "events", - "models-and-providers", - "ai-sdk-ui" + "ai", + "ai.models", + "ai.events", + "ai.messages", + "ai.tools", + "ai.providers", + "ai.errors", + "ai.mcp", + "ai.agents", + "ai.types", + "ai.util" ] } diff --git a/docs/ai-python/content/docs/reference/models-and-providers.mdx b/docs/ai-python/content/docs/reference/models-and-providers.mdx deleted file mode 100644 index 953cf8f3..00000000 --- a/docs/ai-python/content/docs/reference/models-and-providers.mdx +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: "get_model, Model, get_provider, and Provider" -description: Reference for get_model, Model, get_provider, Provider, params, and probe. -type: reference -summary: Reference for model resolution, provider configuration, provider APIs, and request params. ---- - -Models identify what to call. Providers own credentials, clients, endpoints, -model listing, and wire translation. - -## get_model - -```python -model = ai.get_model("anthropic/claude-sonnet-4") -model = ai.get_model("openai:gpt-5") -model = ai.get_model() -``` - -Unprefixed IDs route through AI Gateway. Calling `get_model()` with no argument -reads `AI_SDK_DEFAULT_MODEL`. - -## Model - -```python -model = ai.Model("gpt-5", provider=provider) -model.id -model.provider -model.protocol -model.with_protocol(protocol) -``` - -`Model` is a lightweight reference. It does not own network state. - -## get_provider - -```python -provider = ai.get_provider("openai") -provider = ai.get_provider( - "openai", - base_url="http://localhost:1234/v1", - api_key="your_access_token_here", -) -``` - -Known providers include AI Gateway, OpenAI-compatible providers, and -Anthropic-compatible providers. - -## Provider - -Provider instances expose: - -```python -provider.name -provider.base_url -provider.default_base_url -provider.api_key -provider.api_key_env -provider.base_url_env -provider.headers -provider.client -provider.is_configured() -await provider.list_models() -await provider.probe(model) -await provider.aclose() -``` - -`provider.stream(...)` and `provider.generate(...)` are usually called through -`ai.stream` and `ai.generate`. - -## probe - -```python -await ai.probe(model) -``` - -`probe` raises a provider error unless the provider is reachable and the model -exists. - -## InferenceRequestParams - -Pass request options to `ai.stream` or `Agent.run` with `params=`. - -```python -params = ai.InferenceRequestParams().with_temperature(0) - -async with ai.stream(model, messages, params=params) as stream: - ... -``` - -Common param groups include: - -- `ReasoningParams` -- `ToolCallingParams` -- `OutputParams` -- `CacheParams` -- `RoutingParams` -- `ProviderServiceParams` -- `ContextManagementParams` - -Use `with_provider_params(...)` for typed provider-specific params. - -## Custom Providers - -Add a provider by subclassing `ai.Provider`, setting `handles`, and -implementing provider-specific behavior. - -```python -class AcmeProvider(ai.Provider[AcmeClient]): - handles = ("acme",) - - async def list_models(self) -> list[str]: - ... - - async def probe(self, model: ai.Model) -> None: - ... -``` - -Protocols translate messages, tools, params, and generated files to provider -wire formats. diff --git a/docs/ai-python/content/docs/reference/tool.mdx b/docs/ai-python/content/docs/reference/tool.mdx deleted file mode 100644 index cf21fb1d..00000000 --- a/docs/ai-python/content/docs/reference/tool.mdx +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: "@ai.tool and AgentTool" -description: Define executable tools and tool result values. -type: reference -summary: Reference for @ai.tool, AgentTool, streaming tool aliases, and tool result helpers. ---- - -`@ai.tool` turns an async Python function into an executable `AgentTool` plus a -model-facing `ai.Tool` declaration. - -```python -@ai.tool -async def contact_mothership(query: str) -> str: - """Contact the mothership.""" - return "Soon." -``` - -## Decorator - -```python -@ai.tool -async def name(...) -> Result: ... - -@ai.tool(require_approval=True) -async def name(...) -> Result: ... - -@ai.tool(aggregator=...) -async def name(...) -> AsyncGenerator[Item]: ... -``` - -The function name becomes the tool name. The docstring becomes the tool -description. The function signature becomes a Pydantic validator and JSON -schema. - -## AgentTool - -```python -tool.name -tool.tool -tool.fn -tool.validator -tool.require_approval -``` - -Pass `AgentTool` values to `ai.agent(tools=[...])`. - -## Streaming Tools - -Async-generator tools can yield partial output while they run. The agent emits -`ai.events.PartialToolCallResult` events for yielded values. - -Use built-in return aliases for common aggregation behavior: - -- `ai.StreamingTextTool`: concatenate yielded strings. -- `ai.StreamingStatusTool[T]`: treat intermediate yields as status updates and - the last yielded value as the final result. -- `ai.SubAgentTool`: forward nested agent events and use the nested final text - as model input. - -Custom aggregators use `ai.agents.Aggregate` with an -`ai.events.Aggregator` implementation. - -## Tool Result Helpers - -```python -ai.tool_result(tool_call_id="tc_1", tool_name="lookup", result={"ok": True}) -ai.pending_tool_result(hook_part, tool_call_id="tc_1", tool_name="lookup") -ai.tool_message(tool_call_id="tc_1", tool_name="lookup", result="done") -ai.tool_result_part("tc_1", tool_name="lookup", result="done") -``` - -`tool_result` creates a `ToolCallResult` event. `tool_message` and -`tool_result_part` create message-layer values. - -## Provider Tools - -Schema-only and provider-executed tools are `ai.Tool` values. Pass them to -`ai.stream(..., tools=[...])` or to an agent when the provider should receive -the declaration. From f01e44440a836e4d309f4cf2bfccd84734031715 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 10:58:35 -0700 Subject: [PATCH 05/19] Restructure top-level ai module section --- .../docs/reference/ai.models/index.mdx | 35 -- .../docs/reference/ai.models/meta.json | 5 - .../content/docs/reference/ai/agent.mdx | 2 +- .../content/docs/reference/ai/generate.mdx | 2 +- .../content/docs/reference/ai/get-model.mdx | 2 +- .../docs/reference/ai/get-provider.mdx | 2 +- .../content/docs/reference/ai/index.mdx | 413 +++++++++++++++++- .../content/docs/reference/ai/meta.json | 23 +- .../content/docs/reference/ai/stream.mdx | 2 +- .../content/docs/reference/ai/tool.mdx | 39 +- .../content/docs/reference/meta.json | 9 +- 11 files changed, 437 insertions(+), 97 deletions(-) delete mode 100644 docs/ai-python/content/docs/reference/ai.models/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.models/meta.json diff --git a/docs/ai-python/content/docs/reference/ai.models/index.mdx b/docs/ai-python/content/docs/reference/ai.models/index.mdx deleted file mode 100644 index 57f84777..00000000 --- a/docs/ai-python/content/docs/reference/ai.models/index.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: "ai.models" -description: "Reference for the model namespace." -type: reference -summary: "Namespace mirror for model calls, model objects, and model params." ---- - -`ai.models` reexports the model APIs that are also available from `ai`. -Prefer top-level imports in application code: - -```python -import ai - -model = ai.get_model("anthropic/claude-sonnet-4") -async with ai.stream(model, [ai.user_message("Hello")]) as stream: - ... -``` - -Use `ai.models` when a namespace import makes code clearer, especially in -library code that groups model-layer types separately. - -## Public APIs - -- `stream` -- `generate` -- `probe` -- `get_model` -- `Model` -- `Stream` -- `InferenceRequestParams` -- model, sampler, routing, output, and media generation params -- executor and request protocols - -The deeper `ai.models.core` package is an implementation layout. Public docs -should usually point users at `ai` or `ai.models`. diff --git a/docs/ai-python/content/docs/reference/ai.models/meta.json b/docs/ai-python/content/docs/reference/ai.models/meta.json deleted file mode 100644 index b43ee597..00000000 --- a/docs/ai-python/content/docs/reference/ai.models/meta.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "title": "ai.models", - "description": "Reference for the model namespace.", - "pages": [] -} diff --git a/docs/ai-python/content/docs/reference/ai/agent.mdx b/docs/ai-python/content/docs/reference/ai/agent.mdx index 0a30ccb3..aa941271 100644 --- a/docs/ai-python/content/docs/reference/ai/agent.mdx +++ b/docs/ai-python/content/docs/reference/ai/agent.mdx @@ -1,5 +1,5 @@ --- -title: "ai.Agent" +title: "Agent" description: Run the default agent loop with tools. type: reference summary: Reference for ai.Agent. diff --git a/docs/ai-python/content/docs/reference/ai/generate.mdx b/docs/ai-python/content/docs/reference/ai/generate.mdx index 3f995515..79d780d8 100644 --- a/docs/ai-python/content/docs/reference/ai/generate.mdx +++ b/docs/ai-python/content/docs/reference/ai/generate.mdx @@ -1,5 +1,5 @@ --- -title: "ai.generate" +title: "generate" description: Generate non-streaming media responses. type: reference summary: Reference for ai.generate. diff --git a/docs/ai-python/content/docs/reference/ai/get-model.mdx b/docs/ai-python/content/docs/reference/ai/get-model.mdx index 193c6217..db033605 100644 --- a/docs/ai-python/content/docs/reference/ai/get-model.mdx +++ b/docs/ai-python/content/docs/reference/ai/get-model.mdx @@ -1,5 +1,5 @@ --- -title: "ai.get_model" +title: "get_model" description: Resolve a model reference from an id. type: reference summary: Reference for ai.get_model. diff --git a/docs/ai-python/content/docs/reference/ai/get-provider.mdx b/docs/ai-python/content/docs/reference/ai/get-provider.mdx index 9189e5de..f6de5162 100644 --- a/docs/ai-python/content/docs/reference/ai/get-provider.mdx +++ b/docs/ai-python/content/docs/reference/ai/get-provider.mdx @@ -1,5 +1,5 @@ --- -title: "ai.get_provider" +title: "get_provider" description: Resolve and configure providers. type: reference summary: Reference for ai.get_provider. diff --git a/docs/ai-python/content/docs/reference/ai/index.mdx b/docs/ai-python/content/docs/reference/ai/index.mdx index 90adc8bb..689020bf 100644 --- a/docs/ai-python/content/docs/reference/ai/index.mdx +++ b/docs/ai-python/content/docs/reference/ai/index.mdx @@ -2,10 +2,11 @@ title: "ai" description: "Reference for top-level ai exports." type: reference -summary: "Reference for names imported directly from ai." +summary: "Full record of names imported directly from ai." --- -Import `ai` for application code. +`ai` is the application-facing namespace. This page mirrors the public names +re-exported from `ai.__all__`. ```python import ai @@ -14,15 +15,403 @@ model = ai.get_model("anthropic/claude-sonnet-4") messages = [ai.user_message("Hello")] ``` -This section covers names imported directly from `ai`: model calls, model -objects and params, message builders, agent primitives, tool primitives, -provider lookup, and provider base types. +## Linked pages -Use sibling module sections for public submodule APIs: +These top-level exports have their own pages under `ai`. -- `ai.events` -- `ai.messages` -- `ai.tools` -- `ai.providers` -- `ai.agents` -- `ai.types` +- [`stream`](/docs/reference/ai/stream): Call a model and iterate response + events. The same page documents `Stream`. +- [`generate`](/docs/reference/ai/generate): Call non-streaming media + generation models. +- [`get_model`](/docs/reference/ai/get-model): Resolve a model id into a + `Model`. +- [`get_provider`](/docs/reference/ai/get-provider): Resolve and configure a + provider. +- [`tool`](/docs/reference/ai/tool): Define executable tools from Python + functions. +- [`Agent`](/docs/reference/ai/agent): Run the default agent loop. + +## Module aliases + +These module aliases are also re-exported from `ai`. + +- [`errors`](/docs/reference/ai.errors): Error classes and HTTP error helpers. +- [`events`](/docs/reference/ai.events): Stream, agent, tool, and hook events. +- [`messages`](/docs/reference/ai.messages): Message and message part models. +- `models`: Model namespace used by the top-level model exports on this page. +- [`mcp`](/docs/reference/ai.mcp): MCP tool loading helpers. +- [`providers`](/docs/reference/ai.providers): Provider classes and + provider-specific namespaces. +- [`tools`](/docs/reference/ai.tools): Model-facing tool schema types. +- [`util`](/docs/reference/ai.util): Async utility helpers. + +## Models + +### Model + +`Model` identifies what to call. Providers own credentials, clients, +endpoints, model listing, and wire translation. + +```python +model = ai.Model("gpt-5", provider=provider) +model.id +model.provider +model.protocol +model.with_protocol(protocol) +``` + +`Model` is a lightweight reference. It does not own network state. + +Fields: + +- `id`: Provider model id. +- `provider`: Provider instance or provider id. +- `protocol`: Optional provider protocol override. + +Methods: + +- `with_protocol(protocol)`: Return a copy that uses a specific provider + protocol. + +### probe + +`probe` asks the model provider to verify that a model exists and is reachable. + +```python +await ai.probe(model) +``` + +## Providers + +### Provider + +`Provider` is the base class for provider instances. Providers own credentials, +clients, endpoints, model listing, and wire translation. + +```python +provider.name +provider.base_url +provider.api_key +provider.headers +provider.protocol +await provider.list_models() +await provider.probe(model) +``` + +Subclasses implement provider-specific configuration and clients. Application +code usually gets a provider with `get_provider`. + +### ProviderProtocol + +`ProviderProtocol` translates messages, tools, params, and generated files to +provider wire formats. + +Provider instances use a protocol for `stream` and `generate` calls. + +```python +protocol.stream(client, model, messages, tools=tools, params=params) +await protocol.generate(client, model, messages, params) +``` + +## Request Params + +Model params are top-level `ai` types. + +Use `InferenceRequestParams` with `stream` and `Agent.run`. Use `ImageParams` +and `VideoParams` with `generate`. + +```python +params = ai.InferenceRequestParams().with_temperature(0) +async with ai.stream(model, messages, params=params) as stream: + ... +``` + +Request params: + +- `InferenceRequestParams`: Inference request options. +- `ProviderServiceParams`: Provider service tier options. +- `ReasoningParams`: Provider reasoning or thinking options. +- `OutputParams`: Output token, include, verbosity, and reasoning summary + options. +- `CacheParams`: Prompt cache options. +- `ContextManagementParams`: Server-side context management options. +- `TokenThreshold`: Token count used as a trigger threshold. + +Sampling params: + +- `TemperatureSamplerParams` +- `TopKSamplerParams` +- `TopPSamplerParams` +- `MinPSamplerParams` +- `RepetitionPenaltyParams` +- `SeedSamplerParams` +- `RandomSeed` +- `RANDOM` +- `DEFAULT` +- `UNSET` +- `ModelProviderDefault` +- `Unset` + +Tool calling params: + +- `ToolCallingParams` +- `ToolChoiceMode` +- `ToolSelection` +- `ToolRef` + +Routing params: + +- `RoutingParams` +- `RoutingTarget` +- `RoutingTargetChain` +- `GeoRegion` +- `CloudRegion` +- `ProviderRankingStrategy` +- `GLOBAL` + +Media generation params: + +```python +ai.ImageParams( + n=1, + size=None, + aspect_ratio=None, + seed=None, + provider_options={}, +) + +ai.VideoParams( + n=1, + aspect_ratio=None, + resolution=None, + duration=None, + fps=None, + seed=None, + provider_options={}, +) +``` + +## Messages + +Message builders create `Message` values. + +```python +ai.system_message("You are concise.") +ai.user_message("Hello", ai.file_part(data, media_type="image/png")) +ai.assistant_message("Hi") +ai.tool_message(tool_call_id="tc_1", result="done", tool_name="lookup") +``` + +Message builder exports: + +- `system_message` +- `user_message` +- `assistant_message` +- `tool_message` + +Part builders create message part values. + +```python +ai.text_part("hello") +ai.file_part(data, media_type="image/png", filename="image.png") +ai.thinking("reasoning text") +ai.content_output("caption", ai.file_part(png_bytes, media_type="image/png")) +ai.tool_result_part("tc_1", result={"ok": True}, tool_name="lookup") +``` + +Part builder exports: + +- `text_part` +- `file_part` +- `thinking` +- `content_output` +- `tool_result_part` + +## Tools and Agents + +### Tool + +`Tool` is the model-facing tool declaration used by providers. + +```python +tool = ai.Tool( + kind="function", + name="lookup", + spec=ai.tools.ToolSpec( + description="Look up a value.", + params={"type": "object", "properties": {}}, + ), +) +``` + +Pass `Tool` values to `stream(..., tools=[...])` or to an agent when the +provider should receive the declaration directly. For Python callables, use +`tool` instead. + +### agent + +`agent` creates an `Agent`. + +```python +agent = ai.agent(tools=[contact_mothership]) +``` + +Arguments: + +- `tools`: Optional `AgentTool` values from `tool` and schema-only `Tool` + declarations for provider-executed tools. + +Returns `Agent`. + +### AgentTool + +`AgentTool` binds a model-facing `Tool` declaration to an executable Python +function. + +```python +tool.name +tool.tool +tool.fn +tool.validator +tool.require_approval +``` + +Pass `AgentTool` values to `agent(tools=[...])`. + +### Context + +Custom loops use `Context` to resolve model tool calls and `ToolRunner` to run +them. + +```python +context.model +context.messages +context.tools +context.output_type +context.params +``` + +Useful methods: + +- `keep_running()`: Return `True` while the last message still needs work. +- `resolve(tool_call)`: Convert model tool call parts into executable + `ToolCall` objects. +- `add(message)`: Append messages to history. + +### ToolCall + +`ToolCall` is the executable runtime object produced by `Context.resolve`. + +```python +tool_call.id +tool_call.name +tool_call.fn +tool_call.kwargs +result = await tool_call() +``` + +### ToolRunner + +`ToolRunner` schedules tool calls and collects their result messages. + +```python +async with ai.ToolRunner() as runner: + runner.schedule(tool_call) + async for result in runner.events(): + ... + message = runner.get_tool_message() +``` + +Use `add_result(result)` when a custom loop executes a tool itself but still +wants the runner to aggregate the result message. + +### Streaming tool aliases + +Async-generator tools can yield partial output while they run. + +- `StreamingTextTool`: Concatenate yielded strings. +- `StreamingStatusTool[T]`: Treat intermediate yields as status updates and + the last yielded value as the final result. +- `SubAgentTool`: Forward nested agent events and use the nested final text as + model input. + +### Tool result helpers + +```python +ai.tool_result(tool_call_id="tc_1", tool_name="lookup", result={"ok": True}) +ai.pending_tool_result(hook_part, tool_call_id="tc_1", tool_name="lookup") +``` + +Exports: + +- `tool_result`: Create a `ToolCallResult`. +- `pending_tool_result`: Create a pending hook placeholder result. + +### Hooks + +Hooks let an agent pause while another process or UI supplies a decision. + +```python +approval = await ai.hook( + "approve_contact_mothership", + payload=ai.tools.ToolApproval, + metadata={"tool": "contact_mothership"}, +) +``` + +Hook exports: + +- `hook`: Emit a pending hook event and wait for a matching resolution. +- `resolve_hook`: Resolve a live or future hook. +- `abort_pending_hook`: Mark a serialized pending hook as aborted. +- `cancel_hook`: Cancel a live hook by label. + +### yield_from + +`yield_from` forwards events from a nested async generator and returns the +nested generator result. + +```python +result = await ai.yield_from(generator) +``` + +## Errors + +Top-level error exports are re-exported from [`ai.errors`](/docs/reference/ai.errors). + +Base errors: + +- `AIError` +- `ConfigurationError` +- `InstallationError` +- `UnsupportedProviderError` + +HTTP context: + +- `HTTPErrorContext` + +Provider errors: + +- `ProviderError` +- `ProviderNotConfiguredError` +- `ProviderAPIError` +- `ProviderConnectionError` +- `ProviderTimeoutError` +- `ProviderResponseError` + +Provider status errors: + +- `ProviderStatusError` +- `ProviderBadRequestError` +- `ProviderAuthenticationError` +- `ProviderPermissionDeniedError` +- `ProviderNotFoundError` +- `ProviderModelNotFoundError` +- `ProviderConflictError` +- `ProviderRequestTooLargeError` +- `ProviderUnprocessableEntityError` +- `ProviderRateLimitError` +- `ProviderInternalServerError` +- `ProviderServiceUnavailableError` +- `ProviderDeadlineExceededError` +- `ProviderOverloadedError` diff --git a/docs/ai-python/content/docs/reference/ai/meta.json b/docs/ai-python/content/docs/reference/ai/meta.json index 69fd502b..0cb23b0a 100644 --- a/docs/ai-python/content/docs/reference/ai/meta.json +++ b/docs/ai-python/content/docs/reference/ai/meta.json @@ -4,28 +4,9 @@ "pages": [ "stream", "generate", - "probe", "get-model", - "model", - "model-params", - "routing-params", - "media-generation-params", - "message-builders", - "part-builders", - "tool", - "tool-decorator", - "tool-results", - "agent", - "agent-factory", - "context", - "agent-tool", - "tool-call", - "tool-runner", - "streaming-tools", - "hooks", - "yield-from", "get-provider", - "provider", - "provider-protocol" + "tool", + "agent" ] } diff --git a/docs/ai-python/content/docs/reference/ai/stream.mdx b/docs/ai-python/content/docs/reference/ai/stream.mdx index f3566ae9..dfb72018 100644 --- a/docs/ai-python/content/docs/reference/ai/stream.mdx +++ b/docs/ai-python/content/docs/reference/ai/stream.mdx @@ -1,5 +1,5 @@ --- -title: "ai.stream and Stream" +title: "stream" description: Stream model responses and inspect the aggregated result. type: reference summary: Reference for ai.stream, Stream, stream events, aggregation, and replay. diff --git a/docs/ai-python/content/docs/reference/ai/tool.mdx b/docs/ai-python/content/docs/reference/ai/tool.mdx index 74ccbdb8..519ee9d6 100644 --- a/docs/ai-python/content/docs/reference/ai/tool.mdx +++ b/docs/ai-python/content/docs/reference/ai/tool.mdx @@ -1,22 +1,33 @@ --- -title: "ai.Tool" -description: "Declare a schema-only or provider-executed tool." +title: "tool" +description: Define executable tools from Python functions. type: reference -summary: "Reference for ai.Tool." +summary: Reference for ai.tool. --- -`Tool` is the model-facing tool declaration used by providers. +`@ai.tool` turns an async Python function into an executable `AgentTool` plus a +model-facing `ai.Tool` declaration. ```python -tool = ai.Tool( - spec=ai.tools.ToolSpec( - name="lookup", - description="Look up a value.", - input_schema={"type": "object", "properties": {}}, - ) -) +@ai.tool +async def contact_mothership(query: str) -> str: + """Contact the mothership.""" + return "Soon." ``` -Pass `Tool` values to `ai.stream(..., tools=[...])` or to an agent when the -provider should receive the declaration directly. For Python callables, use -`@ai.tool` instead. +## Forms + +```python +@ai.tool +async def name(...) -> Result: ... + +@ai.tool(require_approval=True) +async def name(...) -> Result: ... + +@ai.tool(aggregator=...) +async def name(...) -> AsyncGenerator[Item]: ... +``` + +The function name becomes the tool name. The docstring becomes the tool +description. The function signature becomes a Pydantic validator and JSON +schema. diff --git a/docs/ai-python/content/docs/reference/meta.json b/docs/ai-python/content/docs/reference/meta.json index 4953abd9..69f406e5 100644 --- a/docs/ai-python/content/docs/reference/meta.json +++ b/docs/ai-python/content/docs/reference/meta.json @@ -3,14 +3,13 @@ "description": "API reference for public AI SDK for Python APIs.", "pages": [ "ai", - "ai.models", - "ai.events", - "ai.messages", - "ai.tools", "ai.providers", + "ai.agents", + "ai.tools", + "ai.messages", + "ai.events", "ai.errors", "ai.mcp", - "ai.agents", "ai.types", "ai.util" ] From bfe54bc5b844f7fd945288dc757236371bafb221 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 11:22:37 -0700 Subject: [PATCH 06/19] Consolidate very short module pages --- .../docs/reference/ai.errors/base-errors.mdx | 15 --- .../docs/reference/ai.errors/helpers.mdx | 24 ----- .../docs/reference/ai.errors/index.mdx | 15 --- .../docs/reference/ai.errors/meta.json | 10 -- .../reference/ai.errors/provider-errors.mdx | 21 ---- .../reference/ai.errors/status-errors.mdx | 25 ----- .../docs/reference/ai.events/agent-events.mdx | 18 ---- .../docs/reference/ai.events/aggregators.mdx | 21 ---- .../docs/reference/ai.events/index.mdx | 16 --- .../docs/reference/ai.events/meta.json | 10 -- .../ai.events/replay-message-events.mdx | 16 --- .../reference/ai.events/stream-events.mdx | 44 -------- .../reference/ai.mcp/close-connections.mdx | 11 -- .../docs/reference/ai.mcp/http-tools.mdx | 15 --- .../content/docs/reference/ai.mcp/index.mdx | 14 --- .../content/docs/reference/ai.mcp/meta.json | 9 -- .../docs/reference/ai.mcp/stdio-tools.mdx | 23 ---- .../docs/reference/ai.messages/index.mdx | 17 --- .../reference/ai.messages/message-bundle.mdx | 14 --- .../reference/ai.messages/message-ids.mdx | 15 --- .../docs/reference/ai.messages/message.mdx | 38 ------- .../docs/reference/ai.messages/meta.json | 12 --- .../docs/reference/ai.messages/parts.mdx | 23 ---- .../reference/ai.messages/serialization.mdx | 16 --- .../docs/reference/ai.messages/tool-parts.mdx | 21 ---- .../content/docs/reference/ai.tools/index.mdx | 24 ----- .../content/docs/reference/ai.tools/meta.json | 9 -- .../docs/reference/ai.tools/tool-approval.mdx | 13 --- .../docs/reference/ai.tools/tool-config.mdx | 11 -- .../docs/reference/ai.tools/tool-spec.mdx | 14 --- .../content/docs/reference/ai.types/index.mdx | 16 --- .../docs/reference/ai.types/integrity.mdx | 24 ----- .../content/docs/reference/ai.types/media.mdx | 27 ----- .../content/docs/reference/ai.types/meta.json | 9 -- .../content/docs/reference/ai.types/usage.mdx | 20 ---- .../docs/reference/ai.util/decouple.mdx | 11 -- .../content/docs/reference/ai.util/index.mdx | 17 --- .../docs/reference/ai.util/lifecycle.mdx | 14 --- .../content/docs/reference/ai.util/merge.mdx | 14 --- .../content/docs/reference/ai.util/meta.json | 10 -- .../content/docs/reference/ai.util/queues.mdx | 15 --- .../content/docs/reference/ai/index.mdx | 14 +-- .../content/docs/reference/errors.mdx | 70 ++++++++++++ .../content/docs/reference/events.mdx | 98 +++++++++++++++++ docs/ai-python/content/docs/reference/mcp.mdx | 51 +++++++++ .../content/docs/reference/messages.mdx | 102 ++++++++++++++++++ .../content/docs/reference/meta.json | 14 +-- .../content/docs/reference/tools.mdx | 67 ++++++++++++ .../content/docs/reference/types.mdx | 73 +++++++++++++ .../ai-python/content/docs/reference/util.mdx | 45 ++++++++ 50 files changed, 520 insertions(+), 725 deletions(-) delete mode 100644 docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.errors/helpers.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.errors/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.errors/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.events/agent-events.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.events/aggregators.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.events/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.events/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.events/stream-events.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.mcp/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.mcp/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/message.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/parts.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/serialization.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.tools/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.tools/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.types/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.types/integrity.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.types/media.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.types/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.types/usage.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.util/decouple.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.util/index.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.util/merge.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.util/meta.json delete mode 100644 docs/ai-python/content/docs/reference/ai.util/queues.mdx create mode 100644 docs/ai-python/content/docs/reference/errors.mdx create mode 100644 docs/ai-python/content/docs/reference/events.mdx create mode 100644 docs/ai-python/content/docs/reference/mcp.mdx create mode 100644 docs/ai-python/content/docs/reference/messages.mdx create mode 100644 docs/ai-python/content/docs/reference/tools.mdx create mode 100644 docs/ai-python/content/docs/reference/types.mdx create mode 100644 docs/ai-python/content/docs/reference/util.mdx diff --git a/docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx b/docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx deleted file mode 100644 index 64e48419..00000000 --- a/docs/ai-python/content/docs/reference/ai.errors/base-errors.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai.errors base errors" -description: Reference for base SDK errors. -type: reference -summary: Reference for AIError, ConfigurationError, InstallationError, and UnsupportedProviderError. ---- - -Base errors are not tied to a provider HTTP response. - -## Types - -- `AIError` -- `ConfigurationError` -- `InstallationError` -- `UnsupportedProviderError` diff --git a/docs/ai-python/content/docs/reference/ai.errors/helpers.mdx b/docs/ai-python/content/docs/reference/ai.errors/helpers.mdx deleted file mode 100644 index fde83a30..00000000 --- a/docs/ai-python/content/docs/reference/ai.errors/helpers.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "ai.errors helpers" -description: Reference for error helper types and functions. -type: reference -summary: Reference for HTTPErrorContext and http_status_to_provider_status_error_class. ---- - -Error helpers expose normalized HTTP context and status-code mapping. - -## HTTPErrorContext - -```python -context.status_code -context.request -context.response -``` - -## http_status_to_provider_status_error_class - -```python -error_cls = ai.errors.http_status_to_provider_status_error_class(429) -``` - -Returns the provider status error class for an HTTP status code. diff --git a/docs/ai-python/content/docs/reference/ai.errors/index.mdx b/docs/ai-python/content/docs/reference/ai.errors/index.mdx deleted file mode 100644 index c0c648d3..00000000 --- a/docs/ai-python/content/docs/reference/ai.errors/index.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai.errors" -description: Reference for SDK error types. -type: reference -summary: Reference for ai.errors. ---- - -`ai.errors` contains the framework and provider error hierarchy. - -## Groups - -- Base framework errors. -- Provider API errors. -- Provider status errors. -- HTTP error helper types. diff --git a/docs/ai-python/content/docs/reference/ai.errors/meta.json b/docs/ai-python/content/docs/reference/ai.errors/meta.json deleted file mode 100644 index 0846d994..00000000 --- a/docs/ai-python/content/docs/reference/ai.errors/meta.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "ai.errors", - "description": "Reference for SDK error types.", - "pages": [ - "base-errors", - "provider-errors", - "status-errors", - "helpers" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx b/docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx deleted file mode 100644 index a4d11c4e..00000000 --- a/docs/ai-python/content/docs/reference/ai.errors/provider-errors.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "ai.errors provider errors" -description: Reference for provider API errors. -type: reference -summary: Reference for ProviderError and ProviderAPIError subclasses. ---- - -Provider errors represent failures raised by model providers. - -## Types - -- `ProviderError` -- `ProviderNotConfiguredError` -- `ProviderAPIError` -- `ProviderConnectionError` -- `ProviderTimeoutError` -- `ProviderResponseError` -- `ProviderIncompleteResponseError` - -`ProviderAPIError` includes `request_id`, `http_context`, `body`, `code`, -`param`, `type`, and `is_retryable`. diff --git a/docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx b/docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx deleted file mode 100644 index b34de30d..00000000 --- a/docs/ai-python/content/docs/reference/ai.errors/status-errors.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "ai.errors provider status errors" -description: Reference for provider HTTP status errors. -type: reference -summary: Reference for ProviderStatusError subclasses. ---- - -Status errors represent provider responses with non-success HTTP status codes. - -## Types - -- `ProviderStatusError` -- `ProviderBadRequestError` -- `ProviderAuthenticationError` -- `ProviderPermissionDeniedError` -- `ProviderNotFoundError` -- `ProviderModelNotFoundError` -- `ProviderConflictError` -- `ProviderRequestTooLargeError` -- `ProviderUnprocessableEntityError` -- `ProviderRateLimitError` -- `ProviderInternalServerError` -- `ProviderServiceUnavailableError` -- `ProviderDeadlineExceededError` -- `ProviderOverloadedError` diff --git a/docs/ai-python/content/docs/reference/ai.events/agent-events.mdx b/docs/ai-python/content/docs/reference/ai.events/agent-events.mdx deleted file mode 100644 index b722ce2e..00000000 --- a/docs/ai-python/content/docs/reference/ai.events/agent-events.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "ai.events agent events" -description: Reference for agent-level events. -type: reference -summary: Reference for ToolCallResult, PartialToolCallResult, and HookEvent. ---- - -Agents can emit event values that are not raw provider stream events. - -## Types - -- `ToolCallResult` -- `PartialToolCallResult` -- `HookEvent` - -`ToolCallResult` carries the tool result message and result parts. -`PartialToolCallResult` carries values yielded by streaming tools and -`yield_from`. `HookEvent` carries an internal hook message and `HookPart`. diff --git a/docs/ai-python/content/docs/reference/ai.events/aggregators.mdx b/docs/ai-python/content/docs/reference/ai.events/aggregators.mdx deleted file mode 100644 index e9af36f9..00000000 --- a/docs/ai-python/content/docs/reference/ai.events/aggregators.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "ai.events.Aggregator" -description: Reference for the streaming tool aggregator protocol. -type: reference -summary: Reference for ai.events.Aggregator. ---- - -`Aggregator[Item, Result, ModelInput]` is the interface used by streaming tools -and `yield_from`. - -```python -class MyAggregator(ai.events.Aggregator[Item, Result, ModelInput]): - def feed(self, item: Item) -> None: ... - def snapshot(self) -> Result: ... - - @classmethod - def to_model_input(cls, snapshot: Result) -> ModelInput: ... -``` - -`snapshot()` is the rich value stored in tool results. `get_model_input()` is -the value sent back to the model. diff --git a/docs/ai-python/content/docs/reference/ai.events/index.mdx b/docs/ai-python/content/docs/reference/ai.events/index.mdx deleted file mode 100644 index 8a029099..00000000 --- a/docs/ai-python/content/docs/reference/ai.events/index.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai.events" -description: Reference for stream, agent, tool, and hook events. -type: reference -summary: Reference for ai.events. ---- - -Streams and agents yield event objects from `ai.events`. This is the public -event-model namespace, and events are Pydantic models. - -## Event groups - -- Model stream events. -- Agent events. -- Replay helpers. -- Aggregator protocol. diff --git a/docs/ai-python/content/docs/reference/ai.events/meta.json b/docs/ai-python/content/docs/reference/ai.events/meta.json deleted file mode 100644 index f35da284..00000000 --- a/docs/ai-python/content/docs/reference/ai.events/meta.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "ai.events", - "description": "Reference for event classes and event helpers.", - "pages": [ - "stream-events", - "agent-events", - "aggregators", - "replay-message-events" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx b/docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx deleted file mode 100644 index 0983c1e1..00000000 --- a/docs/ai-python/content/docs/reference/ai.events/replay-message-events.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai.events.replay_message_events" -description: Replay a completed message as stream events. -type: reference -summary: Reference for ai.events.replay_message_events. ---- - -`replay_message_events` synthesizes stream events from a complete `Message`. - -```python -async for event in ai.events.replay_message_events(message): - ... -``` - -Use it when cached, durable, or test messages need to flow through code that -expects stream events. diff --git a/docs/ai-python/content/docs/reference/ai.events/stream-events.mdx b/docs/ai-python/content/docs/reference/ai.events/stream-events.mdx deleted file mode 100644 index baf72329..00000000 --- a/docs/ai-python/content/docs/reference/ai.events/stream-events.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "ai.events stream events" -description: Reference for model stream events. -type: reference -summary: Reference for model stream event classes. ---- - -Model stream events inherit from `BaseEvent`. - -```python -event.message -event.usage -event.provider_metadata -``` - -## Text - -- `StreamStart` -- `TextStart` -- `TextDelta` -- `TextEnd` -- `StreamEnd` - -## Reasoning - -- `ReasoningStart` -- `ReasoningDelta` -- `ReasoningEnd` - -## Tools - -- `ToolStart` -- `ToolDelta` -- `ToolEnd` -- `BuiltinToolStart` -- `BuiltinToolDelta` -- `BuiltinToolEnd` -- `BuiltinToolResult` - -## Files and hooks - -- `FileEvent` -- `HookSuspension` -- `HookResolution` diff --git a/docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx b/docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx deleted file mode 100644 index e051cdac..00000000 --- a/docs/ai-python/content/docs/reference/ai.mcp/close-connections.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "ai.mcp.close_connections" -description: "Close MCP client connections for the current run." -type: reference -summary: "Reference for ai.mcp.close_connections." ---- - -`close_connections` closes pooled MCP connections for the active context. - -Agent runs clean up MCP connections automatically. Call this helper only -when you manage MCP tool lifetimes manually. diff --git a/docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx b/docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx deleted file mode 100644 index f2bdb52e..00000000 --- a/docs/ai-python/content/docs/reference/ai.mcp/http-tools.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai.mcp.get_http_tools" -description: "Load tools from an MCP HTTP server." -type: reference -summary: "Reference for ai.mcp.get_http_tools." ---- - -`get_http_tools` connects to an MCP HTTP server and returns `AgentTool` -values that can be passed to `ai.agent`. - -```python -tools = await ai.mcp.get_http_tools("https://example.com/mcp") -``` - -Use `tool_prefix` when multiple servers expose overlapping tool names. diff --git a/docs/ai-python/content/docs/reference/ai.mcp/index.mdx b/docs/ai-python/content/docs/reference/ai.mcp/index.mdx deleted file mode 100644 index b26d9c66..00000000 --- a/docs/ai-python/content/docs/reference/ai.mcp/index.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "ai.mcp" -description: Reference for MCP tools. -type: reference -summary: Reference for ai.mcp. ---- - -`ai.mcp` loads MCP server tools as `AgentTool` values. - -## APIs - -- `get_stdio_tools` -- `get_http_tools` -- `close_connections` diff --git a/docs/ai-python/content/docs/reference/ai.mcp/meta.json b/docs/ai-python/content/docs/reference/ai.mcp/meta.json deleted file mode 100644 index 0a50dca8..00000000 --- a/docs/ai-python/content/docs/reference/ai.mcp/meta.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "title": "ai.mcp", - "description": "Reference for MCP tool loading APIs.", - "pages": [ - "stdio-tools", - "http-tools", - "close-connections" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx b/docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx deleted file mode 100644 index 4008cda9..00000000 --- a/docs/ai-python/content/docs/reference/ai.mcp/stdio-tools.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "ai.mcp.get_stdio_tools" -description: "Load tools from an MCP stdio server." -type: reference -summary: "Reference for ai.mcp.get_stdio_tools." ---- - -`get_stdio_tools` starts an MCP server subprocess and returns `AgentTool` -values that can be passed to `ai.agent`. - -```python -tools = await ai.mcp.get_stdio_tools( - "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp" -) -``` - -Arguments: - -- `command`: subprocess command. -- `*args`: subprocess arguments. -- `env`: optional environment variables. -- `cwd`: optional working directory. -- `tool_prefix`: optional prefix for tool names. diff --git a/docs/ai-python/content/docs/reference/ai.messages/index.mdx b/docs/ai-python/content/docs/reference/ai.messages/index.mdx deleted file mode 100644 index 0472c3f1..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/index.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: "ai.messages" -description: Reference for message types. -type: reference -summary: Reference for ai.messages. ---- - -`ai.messages` is the public message-model namespace. Messages are Pydantic -models and durable state shared by model calls, agents, tools, UI adapters, -and resume flows. - -## Public types - -- `Message` -- `MessageBundle` -- `ContentOutput` -- Message part types. diff --git a/docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx b/docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx deleted file mode 100644 index 50c6bbeb..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/message-bundle.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "ai.messages message bundles" -description: Reference for message bundle types. -type: reference -summary: Reference for MessageBundle and ContentOutput. ---- - -Message bundle types are used when a tool or adapter needs to carry multiple -message-layer values as one result. - -## Types - -- `MessageBundle` -- `ContentOutput` diff --git a/docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx b/docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx deleted file mode 100644 index ba9b18a0..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/message-ids.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai.messages message IDs" -description: "Reference for message ID helpers." -type: reference -summary: "Reference for ai.messages.generate_id." ---- - -`generate_id` creates SDK-style IDs for messages and parts. - -```python -message_id = ai.messages.generate_id("msg") -``` - -Pass a prefix to control the ID family. If no prefix is supplied, the helper -returns an unprefixed generated ID. diff --git a/docs/ai-python/content/docs/reference/ai.messages/message.mdx b/docs/ai-python/content/docs/reference/ai.messages/message.mdx deleted file mode 100644 index 8c33e5d6..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/message.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: "ai.messages.Message" -description: Reference for conversation messages. -type: reference -summary: Reference for ai.messages.Message. ---- - -`Message` carries one conversation item. - -```python -message.role -message.parts -message.id -message.turn_id -message.usage -message.provider_metadata -message.replay -``` - -Roles are `user`, `assistant`, `system`, `tool`, and `internal`. - -## Convenience properties - -```python -message.text -message.reasoning -message.tool_calls -message.tool_results -message.builtin_tool_calls -message.builtin_tool_returns -message.files -message.images -message.videos -message.get_output(output_type=None) -``` - -`get_output()` returns text by default. With a Pydantic model, it validates the -message text as JSON and returns that model. diff --git a/docs/ai-python/content/docs/reference/ai.messages/meta.json b/docs/ai-python/content/docs/reference/ai.messages/meta.json deleted file mode 100644 index 87bafd6c..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/meta.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "ai.messages", - "description": "Reference for message models and message parts.", - "pages": [ - "message", - "parts", - "tool-parts", - "message-bundle", - "message-ids", - "serialization" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.messages/parts.mdx b/docs/ai-python/content/docs/reference/ai.messages/parts.mdx deleted file mode 100644 index 98c2c905..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/parts.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "ai.messages parts" -description: Reference for message part types. -type: reference -summary: Reference for message part types. ---- - -Message parts store typed content inside a `Message`. - -## Common parts - -- `TextPart` -- `FilePart` -- `ReasoningPart` -- `ToolCallPart` -- `ToolResultPart` -- `BuiltinToolCallPart` -- `BuiltinToolReturnPart` -- `HookPart` - -`ToolResultPart.get_model_input()` returns the value sent back to the model. For -most tools this is the same as `result`. Aggregator-backed tools can store a -rich `result` while sending a simpler model-facing value. diff --git a/docs/ai-python/content/docs/reference/ai.messages/serialization.mdx b/docs/ai-python/content/docs/reference/ai.messages/serialization.mdx deleted file mode 100644 index 9eedc3d5..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/serialization.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai.messages serialization" -description: Serialize and restore messages. -type: reference -summary: Reference for message serialization. ---- - -Messages serialize through Pydantic. - -```python -encoded = [message.model_dump(mode="json") for message in messages] -restored = [ai.messages.Message.model_validate(item) for item in encoded] -``` - -Persist messages after completed or suspended runs. Recreate providers, hooks, -streams, and other live runtime objects on the next request. diff --git a/docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx b/docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx deleted file mode 100644 index b2105d26..00000000 --- a/docs/ai-python/content/docs/reference/ai.messages/tool-parts.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "ai.messages tool parts" -description: "Reference for tool-related message parts." -type: reference -summary: "Reference for tool call, tool result, built-in tool, and hook parts." ---- - -Tool parts store tool calls, results, built-in provider tool activity, and -hook suspensions inside `ai.messages.Message` values. - -## Parts - -- `ToolCallPart` -- `ToolResultPart` -- `BuiltinToolCallPart` -- `BuiltinToolReturnPart` -- `HookPart` - -`ToolResultPart.get_model_input()` returns the value sent back to the model. -Aggregator-backed tools can keep a rich `result` while sending a simpler -model-facing value. diff --git a/docs/ai-python/content/docs/reference/ai.tools/index.mdx b/docs/ai-python/content/docs/reference/ai.tools/index.mdx deleted file mode 100644 index 8e959bab..00000000 --- a/docs/ai-python/content/docs/reference/ai.tools/index.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "ai.tools" -description: Reference for schema tool types and approval payloads. -type: reference -summary: Reference for ai.tools. ---- - -`ai.tools` defines model-facing tool declarations and tool approval -payloads. - -Schema-only tools and provider-executed tools are both represented as -`ai.Tool` values. Pass them to `ai.stream(..., tools=[...])` or to an agent -when the provider should receive the declaration. - -Provider-specific built-in tool factories live under provider namespaces such -as `ai.providers.openai.tools`, `ai.providers.anthropic.tools`, and -`ai.providers.ai_gateway.tools`. - -## Types - -- `Tool` -- `ToolSpec` -- `ToolConfig` -- `ToolApproval` diff --git a/docs/ai-python/content/docs/reference/ai.tools/meta.json b/docs/ai-python/content/docs/reference/ai.tools/meta.json deleted file mode 100644 index a0c66531..00000000 --- a/docs/ai-python/content/docs/reference/ai.tools/meta.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "title": "ai.tools", - "description": "Reference for schema tool types and approval payloads.", - "pages": [ - "tool-spec", - "tool-config", - "tool-approval" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx b/docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx deleted file mode 100644 index dde8c4f4..00000000 --- a/docs/ai-python/content/docs/reference/ai.tools/tool-approval.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "ai.tools.ToolApproval" -description: "Payload model for human tool approvals." -type: reference -summary: "Reference for ai.tools.ToolApproval." ---- - -`ToolApproval` is a Pydantic model used with hooks and UI adapters when a -tool call needs external approval. - -```python -approval = await ai.hook("approve_tool", payload=ai.tools.ToolApproval) -``` diff --git a/docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx b/docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx deleted file mode 100644 index f16e112e..00000000 --- a/docs/ai-python/content/docs/reference/ai.tools/tool-config.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "ai.tools.ToolConfig" -description: "Configure a model-facing tool declaration." -type: reference -summary: "Reference for ai.tools.ToolConfig." ---- - -`ToolConfig` stores provider-facing tool options. - -Use it with `ai.Tool` when a provider-executed tool needs configuration in -addition to its `ToolSpec`. diff --git a/docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx b/docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx deleted file mode 100644 index bd58b6f4..00000000 --- a/docs/ai-python/content/docs/reference/ai.tools/tool-spec.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "ai.tools.ToolSpec" -description: "Describe a model-facing tool schema." -type: reference -summary: "Reference for ai.tools.ToolSpec." ---- - -`ToolSpec` contains the provider-facing schema for a tool. - -Fields: - -- `name` -- `description` -- `input_schema` diff --git a/docs/ai-python/content/docs/reference/ai.types/index.mdx b/docs/ai-python/content/docs/reference/ai.types/index.mdx deleted file mode 100644 index 9f0b11e0..00000000 --- a/docs/ai-python/content/docs/reference/ai.types/index.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai.types" -description: "Reference for lower-level public type helper modules." -type: reference -summary: "Reference for public type helpers that are not top-level imports." ---- - -Most message, event, and tool APIs are documented under the root aliases -`ai.messages`, `ai.events`, and `ai.tools`. Use `ai.types` for lower-level -helper modules that do not have a shorter public alias. - -Public modules: - -- `ai.types.media` -- `ai.types.integrity` -- `ai.types.usage` diff --git a/docs/ai-python/content/docs/reference/ai.types/integrity.mdx b/docs/ai-python/content/docs/reference/ai.types/integrity.mdx deleted file mode 100644 index e1c1d9ab..00000000 --- a/docs/ai-python/content/docs/reference/ai.types/integrity.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "ai.types.integrity" -description: Reference for message history preparation. -type: reference -summary: Reference for ai.types.integrity. ---- - -Before provider calls, the SDK prepares message history. It strips internal -messages, removes non-model parts, repairs invalid tool args to `{}`, and -inserts error results for missing tool calls when possible. - -Use strict validation when you want repairable issues to raise: - -```python -from ai.types import integrity - - -integrity.prepare_messages(messages, mode="strict") -``` - -## APIs - -- `prepare_messages` -- `IntegrityError` diff --git a/docs/ai-python/content/docs/reference/ai.types/media.mdx b/docs/ai-python/content/docs/reference/ai.types/media.mdx deleted file mode 100644 index a0a758e4..00000000 --- a/docs/ai-python/content/docs/reference/ai.types/media.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: "ai.types.media" -description: Reference for media helpers. -type: reference -summary: Reference for ai.types.media. ---- - -`ai.types.media` contains URL, data URL, media type inference, and magic-byte -detection helpers. - -## URL helpers - -- `is_url` -- `is_downloadable_url` -- `split_data_url` - -## Encoding helpers - -- `data_to_base64` -- `data_to_data_url` - -## Media type helpers - -- `infer_media_type` -- `detect_media_type` -- `detect_image_media_type` -- `detect_audio_media_type` diff --git a/docs/ai-python/content/docs/reference/ai.types/meta.json b/docs/ai-python/content/docs/reference/ai.types/meta.json deleted file mode 100644 index 06c62ca4..00000000 --- a/docs/ai-python/content/docs/reference/ai.types/meta.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "title": "ai.types", - "description": "Reference for lower-level public type helper modules.", - "pages": [ - "media", - "integrity", - "usage" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.types/usage.mdx b/docs/ai-python/content/docs/reference/ai.types/usage.mdx deleted file mode 100644 index aa0c5ae0..00000000 --- a/docs/ai-python/content/docs/reference/ai.types/usage.mdx +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "ai.types.usage" -description: Reference for usage types. -type: reference -summary: Reference for ai.types.usage. ---- - -`Usage` is normalized token usage from a single model call. - -```python -usage.input_tokens -usage.output_tokens -usage.reasoning_tokens -usage.cache_read_tokens -usage.cache_write_tokens -usage.raw -usage.total_tokens -``` - -Use `usage_a + usage_b` to accumulate usage across calls. diff --git a/docs/ai-python/content/docs/reference/ai.util/decouple.mdx b/docs/ai-python/content/docs/reference/ai.util/decouple.mdx deleted file mode 100644 index 4970401a..00000000 --- a/docs/ai-python/content/docs/reference/ai.util/decouple.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "ai.util.decouple" -description: "Run async iteration through a queue boundary." -type: reference -summary: "Reference for ai.util.decouple." ---- - -`decouple` separates producer and consumer timing for an async iterable. - -Use it when a producer should continue running while another task consumes -items at a different pace. diff --git a/docs/ai-python/content/docs/reference/ai.util/index.mdx b/docs/ai-python/content/docs/reference/ai.util/index.mdx deleted file mode 100644 index 16be1be0..00000000 --- a/docs/ai-python/content/docs/reference/ai.util/index.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: "ai.util" -description: Reference for utilities. -type: reference -summary: Reference for ai.util. ---- - -`ai.util` contains asynchronous utility primitives used by the SDK. - -## Public APIs - -- `AsyncIterableQueue` -- `MultiWaiter` -- `unwrap_generator_exit` -- `maybe_aclosing` -- `decouple` -- `merge` diff --git a/docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx b/docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx deleted file mode 100644 index a1bc2eb6..00000000 --- a/docs/ai-python/content/docs/reference/ai.util/lifecycle.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "ai.util lifecycle helpers" -description: "Reference for async lifecycle helpers." -type: reference -summary: "Reference for ai.util.unwrap_generator_exit and ai.util.maybe_aclosing." ---- - -Lifecycle helpers: - -- `unwrap_generator_exit` -- `maybe_aclosing` - -Use these helpers when implementing custom async generators or safely -closing optional async resources. diff --git a/docs/ai-python/content/docs/reference/ai.util/merge.mdx b/docs/ai-python/content/docs/reference/ai.util/merge.mdx deleted file mode 100644 index 4bb4069b..00000000 --- a/docs/ai-python/content/docs/reference/ai.util/merge.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "ai.util.merge" -description: "Merge async iterables into one stream." -type: reference -summary: "Reference for ai.util.merge." ---- - -`merge` consumes multiple async iterables concurrently and yields items as -they become available. - -```python -async for event in ai.util.merge(stream, tool_runner.events()): - ... -``` diff --git a/docs/ai-python/content/docs/reference/ai.util/meta.json b/docs/ai-python/content/docs/reference/ai.util/meta.json deleted file mode 100644 index 1181caa9..00000000 --- a/docs/ai-python/content/docs/reference/ai.util/meta.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "ai.util", - "description": "Reference for async utility helpers.", - "pages": [ - "merge", - "decouple", - "queues", - "lifecycle" - ] -} diff --git a/docs/ai-python/content/docs/reference/ai.util/queues.mdx b/docs/ai-python/content/docs/reference/ai.util/queues.mdx deleted file mode 100644 index a1d3e1c5..00000000 --- a/docs/ai-python/content/docs/reference/ai.util/queues.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai.util queues" -description: "Reference for queue and waiter primitives." -type: reference -summary: "Reference for ai.util.AsyncIterableQueue and ai.util.MultiWaiter." ---- - -Queue primitives: - -- `AsyncIterableQueue` -- `MultiWaiter` - -`AsyncIterableQueue` is an async iterable queue that can be closed. -`MultiWaiter` waits for the first completed item across multiple async -sources. diff --git a/docs/ai-python/content/docs/reference/ai/index.mdx b/docs/ai-python/content/docs/reference/ai/index.mdx index 689020bf..b3e87d76 100644 --- a/docs/ai-python/content/docs/reference/ai/index.mdx +++ b/docs/ai-python/content/docs/reference/ai/index.mdx @@ -35,15 +35,15 @@ These top-level exports have their own pages under `ai`. These module aliases are also re-exported from `ai`. -- [`errors`](/docs/reference/ai.errors): Error classes and HTTP error helpers. -- [`events`](/docs/reference/ai.events): Stream, agent, tool, and hook events. -- [`messages`](/docs/reference/ai.messages): Message and message part models. +- [`errors`](/docs/reference/errors): Error classes and HTTP error helpers. +- [`events`](/docs/reference/events): Stream, agent, tool, and hook events. +- [`messages`](/docs/reference/messages): Message and message part models. - `models`: Model namespace used by the top-level model exports on this page. -- [`mcp`](/docs/reference/ai.mcp): MCP tool loading helpers. +- [`mcp`](/docs/reference/mcp): MCP tool loading helpers. - [`providers`](/docs/reference/ai.providers): Provider classes and provider-specific namespaces. -- [`tools`](/docs/reference/ai.tools): Model-facing tool schema types. -- [`util`](/docs/reference/ai.util): Async utility helpers. +- [`tools`](/docs/reference/tools): Model-facing tool schema types. +- [`util`](/docs/reference/util): Async utility helpers. ## Models @@ -377,7 +377,7 @@ result = await ai.yield_from(generator) ## Errors -Top-level error exports are re-exported from [`ai.errors`](/docs/reference/ai.errors). +Top-level error exports are re-exported from [`ai.errors`](/docs/reference/errors). Base errors: diff --git a/docs/ai-python/content/docs/reference/errors.mdx b/docs/ai-python/content/docs/reference/errors.mdx new file mode 100644 index 00000000..11546e3f --- /dev/null +++ b/docs/ai-python/content/docs/reference/errors.mdx @@ -0,0 +1,70 @@ +--- +title: "ai.errors" +description: Reference for SDK error types. +type: reference +summary: Reference for ai.errors. +--- + +`ai.errors` contains the framework and provider error hierarchy. + +## Base Errors + +Base errors are not tied to a provider HTTP response. + +- `AIError` +- `ConfigurationError` +- `InstallationError` +- `UnsupportedProviderError` + +## Provider Errors + +Provider errors represent failures raised by model providers. + +- `ProviderError` +- `ProviderNotConfiguredError` +- `ProviderAPIError` +- `ProviderConnectionError` +- `ProviderTimeoutError` +- `ProviderResponseError` +- `ProviderIncompleteResponseError` + +`ProviderAPIError` includes `request_id`, `http_context`, `body`, `code`, +`param`, `type`, and `is_retryable`. + +## Provider Status Errors + +Status errors represent provider responses with non-success HTTP status codes. + +- `ProviderStatusError` +- `ProviderBadRequestError` +- `ProviderAuthenticationError` +- `ProviderPermissionDeniedError` +- `ProviderNotFoundError` +- `ProviderModelNotFoundError` +- `ProviderConflictError` +- `ProviderRequestTooLargeError` +- `ProviderUnprocessableEntityError` +- `ProviderRateLimitError` +- `ProviderInternalServerError` +- `ProviderServiceUnavailableError` +- `ProviderDeadlineExceededError` +- `ProviderOverloadedError` + +## HTTPErrorContext + +`HTTPErrorContext` exposes normalized HTTP context from provider errors. + +```python +context.status_code +context.request +context.response +``` + +## http_status_to_provider_status_error_class + +`http_status_to_provider_status_error_class` returns the provider status error +class for an HTTP status code. + +```python +error_cls = ai.errors.http_status_to_provider_status_error_class(429) +``` diff --git a/docs/ai-python/content/docs/reference/events.mdx b/docs/ai-python/content/docs/reference/events.mdx new file mode 100644 index 00000000..59327762 --- /dev/null +++ b/docs/ai-python/content/docs/reference/events.mdx @@ -0,0 +1,98 @@ +--- +title: "ai.events" +description: Reference for event classes and event helpers. +type: reference +summary: Reference for ai.events. +--- + +Streams and agents yield event objects from `ai.events`. This is the public +event-model namespace, and events are Pydantic models. + +## Stream Events + +Model stream events inherit from `BaseEvent`. + +```python +event.message +event.usage +event.provider_metadata +``` + +Text events: + +- `StreamStart` +- `TextStart` +- `TextDelta` +- `TextEnd` +- `StreamEnd` + +Reasoning events: + +- `ReasoningStart` +- `ReasoningDelta` +- `ReasoningEnd` + +Tool events: + +- `ToolStart` +- `ToolDelta` +- `ToolEnd` +- `BuiltinToolStart` +- `BuiltinToolDelta` +- `BuiltinToolEnd` +- `BuiltinToolResult` + +File and hook events: + +- `FileEvent` +- `HookSuspension` +- `HookResolution` + +Stream event unions: + +- `Event` +- `DiscriminatedEvent` + +## Agent Events + +Agents can emit event values that are not raw provider stream events. + +- `ToolCallResult`: Carries the tool result message and result parts. +- `PartialToolCallResult`: Carries values yielded by streaming tools and + `yield_from`. +- `HookEvent`: Carries an internal hook message and `HookPart`. + +Agent event unions: + +- `AgentMessageEvent` +- `AgentEvent` +- `TerminalEvent` + +## Aggregator + +`Aggregator[Item, Result, ModelInput]` is the interface used by streaming tools +and `yield_from`. + +```python +class MyAggregator(ai.events.Aggregator[Item, Result, ModelInput]): + def feed(self, item: Item) -> None: ... + def snapshot(self) -> Result: ... + + @classmethod + def to_model_input(cls, snapshot: Result) -> ModelInput: ... +``` + +`snapshot()` is the rich value stored in tool results. `get_model_input()` is +the value sent back to the model. + +## replay_message_events + +`replay_message_events` synthesizes stream events from a complete `Message`. + +```python +async for event in ai.events.replay_message_events(message): + ... +``` + +Use it when cached, durable, or test messages need to flow through code that +expects stream events. diff --git a/docs/ai-python/content/docs/reference/mcp.mdx b/docs/ai-python/content/docs/reference/mcp.mdx new file mode 100644 index 00000000..4caa1b25 --- /dev/null +++ b/docs/ai-python/content/docs/reference/mcp.mdx @@ -0,0 +1,51 @@ +--- +title: "ai.mcp" +description: Reference for MCP tool loading APIs. +type: reference +summary: Reference for ai.mcp. +--- + +`ai.mcp` loads MCP server tools as `AgentTool` values. + +## get_stdio_tools + +`get_stdio_tools` starts an MCP server subprocess and returns `AgentTool` +values that can be passed to `ai.agent`. + +```python +tools = await ai.mcp.get_stdio_tools( + "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp" +) +``` + +Arguments: + +- `command`: Subprocess command. +- `*args`: Subprocess arguments. +- `env`: Optional environment variables. +- `cwd`: Optional working directory. +- `tool_prefix`: Optional prefix for tool names. + +## get_http_tools + +`get_http_tools` connects to an MCP HTTP server and returns `AgentTool` values +that can be passed to `ai.agent`. + +```python +tools = await ai.mcp.get_http_tools("https://example.com/mcp") +``` + +Arguments: + +- `url`: MCP server endpoint. +- `headers`: Optional HTTP headers. +- `tool_prefix`: Optional prefix for tool names. + +Use `tool_prefix` when multiple servers expose overlapping tool names. + +## close_connections + +`close_connections` closes pooled MCP connections for the active context. + +Agent runs clean up MCP connections automatically. Call this helper only when +you manage MCP tool lifetimes manually. diff --git a/docs/ai-python/content/docs/reference/messages.mdx b/docs/ai-python/content/docs/reference/messages.mdx new file mode 100644 index 00000000..9215659b --- /dev/null +++ b/docs/ai-python/content/docs/reference/messages.mdx @@ -0,0 +1,102 @@ +--- +title: "ai.messages" +description: Reference for message models and message parts. +type: reference +summary: Reference for ai.messages. +--- + +`ai.messages` is the public message-model namespace. Messages are Pydantic +models and durable state shared by model calls, agents, tools, UI adapters, +and resume flows. + +## Message + +`Message` carries one conversation item. + +```python +message.role +message.parts +message.id +message.turn_id +message.usage +message.provider_metadata +message.replay +``` + +Roles are `user`, `assistant`, `system`, `tool`, and `internal`. + +Convenience properties: + +```python +message.text +message.reasoning +message.tool_calls +message.tool_results +message.builtin_tool_calls +message.builtin_tool_returns +message.files +message.images +message.videos +message.get_output(output_type=None) +``` + +`get_output()` returns text by default. With a Pydantic model, it validates the +message text as JSON and returns that model. + +## Parts + +Message parts store typed content inside a `Message`. + +Common parts: + +- `TextPart`: Text content. +- `FilePart`: File, image, document, audio, or video content. +- `ReasoningPart`: Model reasoning text. + +Tool and runtime parts: + +- `ToolCallPart`: A host-executed tool call requested by the model. +- `ToolResultPart`: The result for a host-executed tool call. +- `BuiltinToolCallPart`: A provider-executed tool call. +- `BuiltinToolReturnPart`: A provider-executed tool result. +- `HookPart`: A hook suspension, resolution, or cancellation. + +`ToolResultPart.get_model_input()` returns the value sent back to the model. For +most tools this is the same as `result`. Aggregator-backed tools can store a +rich `result` while sending a simpler model-facing value. + +## Message Bundles + +Message bundle types are used when a tool or adapter needs to carry multiple +message-layer values as one result. + +- `MessageBundle`: A tuple of `Message` values. +- `ContentOutput`: A multipart tool result containing text and file parts. +- `ContentPart`: The text-or-file part union used by `ContentOutput`. +- `SpecialToolResult`: The special result union for multipart content and + message bundles. +- `ResultKind`: The coarse tag for a tool result shape: `error`, `json`, or + `special`. + +## Message IDs + +`generate_id` creates SDK-style IDs for messages and parts. + +```python +message_id = ai.messages.generate_id("msg") +``` + +Pass a prefix to control the ID family. If no prefix is supplied, the helper +returns an unprefixed generated ID. + +## Serialization + +Messages serialize through Pydantic. + +```python +encoded = [message.model_dump(mode="json") for message in messages] +restored = [ai.messages.Message.model_validate(item) for item in encoded] +``` + +Persist messages after completed or suspended runs. Recreate providers, hooks, +streams, and other live runtime objects on the next request. diff --git a/docs/ai-python/content/docs/reference/meta.json b/docs/ai-python/content/docs/reference/meta.json index 69f406e5..5ca76191 100644 --- a/docs/ai-python/content/docs/reference/meta.json +++ b/docs/ai-python/content/docs/reference/meta.json @@ -5,12 +5,12 @@ "ai", "ai.providers", "ai.agents", - "ai.tools", - "ai.messages", - "ai.events", - "ai.errors", - "ai.mcp", - "ai.types", - "ai.util" + "tools", + "messages", + "events", + "errors", + "mcp", + "types", + "util" ] } diff --git a/docs/ai-python/content/docs/reference/tools.mdx b/docs/ai-python/content/docs/reference/tools.mdx new file mode 100644 index 00000000..52bca91d --- /dev/null +++ b/docs/ai-python/content/docs/reference/tools.mdx @@ -0,0 +1,67 @@ +--- +title: "ai.tools" +description: Reference for schema tool types and approval payloads. +type: reference +summary: Reference for ai.tools. +--- + +`ai.tools` defines model-facing tool declarations and tool approval payloads. + +Schema-only tools and provider-executed tools are both represented as `ai.Tool` +values. Pass them to `ai.stream(..., tools=[...])` or to an agent when the +provider should receive the declaration. + +Provider-specific built-in tool factories live under provider namespaces such +as `ai.providers.openai.tools`, `ai.providers.anthropic.tools`, and +`ai.providers.ai_gateway.tools`. + +## Tool + +`Tool` is the model-facing declaration used by providers. + +Fields: + +- `kind`: `function` or `provider`. +- `name`: Tool name exposed to the model. +- `spec`: Function tool schema. +- `tool_config`: Provider-executed tool configuration. +- `require_approval`: Whether the tool call needs approval before execution. + +Function tools require `spec`. Provider tools require `tool_config.id` and do +not accept `spec`. + +## ToolSpec + +`ToolSpec` contains the provider-facing schema for a host-executed function +tool. + +Fields: + +- `description` +- `params` + +## ToolConfig + +`ToolConfig` stores provider-facing tool options. + +Fields: + +- `id`: Canonical provider tool id. +- `args`: Provider wire arguments as plain snake_case data. + +Use it with `ai.Tool` when a provider-executed tool needs provider-specific +configuration. + +## ToolApproval + +`ToolApproval` is a Pydantic model used with hooks and UI adapters when a tool +call needs external approval. + +```python +approval = await ai.hook("approve_tool", payload=ai.tools.ToolApproval) +``` + +Fields: + +- `granted` +- `reason` diff --git a/docs/ai-python/content/docs/reference/types.mdx b/docs/ai-python/content/docs/reference/types.mdx new file mode 100644 index 00000000..02e89d95 --- /dev/null +++ b/docs/ai-python/content/docs/reference/types.mdx @@ -0,0 +1,73 @@ +--- +title: "ai.types" +description: "Reference for lower-level public type helper modules." +type: reference +summary: "Reference for public type helpers that are not top-level imports." +--- + +Most message, event, and tool APIs are documented under the root aliases +`ai.messages`, `ai.events`, and `ai.tools`. Use `ai.types` for lower-level +helper modules that do not have a shorter public alias. + +## ai.types.media + +`ai.types.media` contains URL, data URL, media type inference, and magic-byte +detection helpers. + +URL helpers: + +- `is_url` +- `is_downloadable_url` +- `split_data_url` + +Encoding helpers: + +- `data_to_base64` +- `data_to_data_url` + +Media type helpers: + +- `infer_media_type` +- `detect_media_type` +- `detect_image_media_type` +- `detect_audio_media_type` + +## ai.types.integrity + +Before provider calls, the SDK prepares message history. It strips internal +messages, removes non-model parts, repairs invalid tool args to `{}`, and +inserts error results for missing tool calls when possible. + +```python +from ai.types import integrity + + +prepared = integrity.prepare_messages(messages) +``` + +Use strict validation when you want repairable issues to raise. + +```python +integrity.prepare_messages(messages, mode="strict") +``` + +APIs: + +- `prepare_messages` +- `IntegrityError` + +## ai.types.usage + +`Usage` is normalized token usage from a single model call. + +```python +usage.input_tokens +usage.output_tokens +usage.reasoning_tokens +usage.cache_read_tokens +usage.cache_write_tokens +usage.raw +usage.total_tokens +``` + +Use `usage_a + usage_b` to accumulate usage across calls. diff --git a/docs/ai-python/content/docs/reference/util.mdx b/docs/ai-python/content/docs/reference/util.mdx new file mode 100644 index 00000000..7fba1440 --- /dev/null +++ b/docs/ai-python/content/docs/reference/util.mdx @@ -0,0 +1,45 @@ +--- +title: "ai.util" +description: Reference for async utility helpers. +type: reference +summary: Reference for ai.util. +--- + +`ai.util` contains asynchronous utility primitives used by the SDK. + +## merge + +`merge` consumes multiple async iterables concurrently and yields items as they +become available. + +```python +async for event in ai.util.merge(stream, tool_runner.events()): + ... +``` + +## decouple + +`decouple` separates producer and consumer timing for an async iterable. + +Use it when a producer should continue running while another task consumes +items at a different pace. + +## Queues + +Queue primitives: + +- `AsyncIterableQueue` +- `MultiWaiter` + +`AsyncIterableQueue` is an async iterable queue that can be closed. `MultiWaiter` +waits for the first completed item across multiple async sources. + +## Lifecycle Helpers + +Lifecycle helpers: + +- `unwrap_generator_exit` +- `maybe_aclosing` + +Use these helpers when implementing custom async generators or safely closing +optional async resources. From 70e7d8dc900e909aa2a25146ad7a8f77a8f5b993 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 11:27:18 -0700 Subject: [PATCH 07/19] Glue together provider sections --- .../ai.providers/ai-gateway/index.mdx | 49 +++++++++++++++++++ .../ai.providers/ai-gateway/meta.json | 5 +- .../ai.providers/ai-gateway/params.mdx | 13 ----- .../ai.providers/ai-gateway/protocol.mdx | 9 ---- .../ai.providers/ai-gateway/provider.mdx | 10 ---- .../ai.providers/ai-gateway/tools.mdx | 2 +- .../ai.providers/anthropic/index.mdx | 36 ++++++++++++++ .../ai.providers/anthropic/meta.json | 4 +- .../ai.providers/anthropic/protocol.mdx | 9 ---- .../ai.providers/anthropic/provider.mdx | 17 ------- .../ai.providers/anthropic/tools.mdx | 2 +- .../reference/ai.providers/openai/index.mdx | 40 +++++++++++++++ .../reference/ai.providers/openai/meta.json | 4 +- .../ai.providers/openai/protocols.mdx | 14 ------ .../ai.providers/openai/provider.mdx | 16 ------ .../reference/ai.providers/openai/tools.mdx | 2 +- 16 files changed, 131 insertions(+), 101 deletions(-) delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx index 58bf643e..318b74b1 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx @@ -12,3 +12,52 @@ params, tools, and error mapping. model = ai.get_model("gateway:anthropic/claude-sonnet-4") ids = await ai.get_provider("vercel").list_models() ``` + +## GatewayProvider + +`GatewayProvider` implements `Provider` for Vercel AI Gateway. + +Default configuration uses `AI_GATEWAY_API_KEY`. + +```python +provider = ai.get_provider("vercel") +model = ai.Model("anthropic/claude-sonnet-4", provider=provider) +``` + +The provider uses the Gateway v3 protocol by default, owns the Gateway client, +and supports model listing, probing, streaming, and media generation. + +## GatewayV3Protocol + +`GatewayV3Protocol` translates SDK messages, tools, params, and generated files +to the AI Gateway v3 wire format. + +Use it directly only when you need a protocol override. Most code should let +`GatewayProvider` choose the default protocol. + +## GatewayParams + +AI Gateway params configure gateway-specific request behavior. + +Fields: + +- `quota_entity_id` +- `zero_data_retention` +- `hipaa_compliant` +- `disallow_prompt_training` +- `byok` +- `provider_timeouts` + +Pass `GatewayParams` through `InferenceRequestParams.provider_params`. + +## ProviderTimeoutsParams + +`ProviderTimeoutsParams` configures per-provider timeout behavior. + +Fields: + +- `byok`: Per-provider BYOK attempt timeouts in milliseconds. + +## Tools + +Provider-executed AI Gateway tools are documented on the child `tools` page. diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json index 3f10a8fb..302fee68 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/meta.json @@ -1,10 +1,7 @@ { - "title": "ai.providers.ai_gateway", + "title": "ai_gateway", "description": "Reference for AI Gateway provider APIs.", "pages": [ - "provider", - "protocol", - "params", "tools" ] } diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx deleted file mode 100644 index 2d8ba9cf..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/params.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "ai.providers.ai_gateway params" -description: Reference for AI Gateway provider params. -type: reference -summary: Reference for GatewayParams and ProviderTimeoutsParams. ---- - -AI Gateway params configure gateway-specific request behavior. - -## Types - -- `GatewayParams` -- `ProviderTimeoutsParams` diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx deleted file mode 100644 index ee8a8f91..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/protocol.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "ai.providers.ai_gateway.GatewayV3Protocol" -description: Reference for the AI Gateway v3 protocol. -type: reference -summary: Reference for ai.providers.ai_gateway.GatewayV3Protocol. ---- - -`GatewayV3Protocol` translates SDK messages, tools, params, and generated files -to the AI Gateway v3 wire format. diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx deleted file mode 100644 index 6a8f1db1..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/provider.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "ai.providers.ai_gateway.GatewayProvider" -description: Reference for the AI Gateway provider. -type: reference -summary: Reference for ai.providers.ai_gateway.GatewayProvider. ---- - -`GatewayProvider` implements `Provider` for Vercel AI Gateway. - -Default configuration uses `AI_GATEWAY_API_KEY`. diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx index cddb5b1c..9b0227a5 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/tools.mdx @@ -1,5 +1,5 @@ --- -title: "ai.providers.ai_gateway.tools" +title: "tools" description: Reference for AI Gateway provider-executed tools. type: reference summary: Reference for AI Gateway provider tool helpers. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx index ba5408ee..22337a95 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx @@ -15,3 +15,39 @@ model = ai.Model("claude-sonnet-4-6", provider=provider) The optional upstream Anthropic SDK loads lazily when the provider creates or uses an SDK client. + +## AnthropicCompatibleProvider + +`AnthropicCompatibleProvider` implements `Provider` for Anthropic-compatible +APIs. + +Default configuration for the `anthropic` provider uses: + +- `ANTHROPIC_API_KEY` +- `ANTHROPIC_BASE_URL` + +Pass `base_url`, `api_key`, or a custom client through `get_provider` when you +need explicit configuration. + +```python +provider = ai.get_provider( + "anthropic", + base_url="https://anthropic.example.com", +) +model = ai.Model("claude-sonnet-4-6", provider=provider) +``` + +The provider supports model listing, probing, streaming, provider-executed +tools, and custom Anthropic-compatible clients. + +## AnthropicMessagesProtocol + +`AnthropicMessagesProtocol` translates SDK messages and params to the +Anthropic Messages API wire format. + +The provider uses this protocol by default. Use it directly only when you need +a protocol override. + +## Tools + +Provider-executed Anthropic tools are documented on the child `tools` page. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json b/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json index b7728e41..f78384aa 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/meta.json @@ -1,9 +1,7 @@ { - "title": "ai.providers.anthropic", + "title": "anthropic", "description": "Reference for Anthropic-compatible provider APIs.", "pages": [ - "provider", - "protocol", "tools" ] } diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx deleted file mode 100644 index 8a959f83..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/anthropic/protocol.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "ai.providers.anthropic.AnthropicMessagesProtocol" -description: Reference for the Anthropic Messages protocol. -type: reference -summary: Reference for ai.providers.anthropic.AnthropicMessagesProtocol. ---- - -`AnthropicMessagesProtocol` translates SDK messages and params to the Anthropic -Messages API wire format. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx deleted file mode 100644 index f2b8205a..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/anthropic/provider.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: "ai.providers.anthropic.AnthropicCompatibleProvider" -description: Reference for the Anthropic-compatible provider. -type: reference -summary: Reference for ai.providers.anthropic.AnthropicCompatibleProvider. ---- - -`AnthropicCompatibleProvider` implements `Provider` for Anthropic-compatible -APIs. - -Default configuration uses: - -- `ANTHROPIC_API_KEY` -- `ANTHROPIC_BASE_URL` - -Pass `base_url`, `api_key`, or a custom client through `get_provider` when you -need explicit configuration. diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx index 232174ce..dc2fcd16 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/tools.mdx @@ -1,5 +1,5 @@ --- -title: "ai.providers.anthropic.tools" +title: "tools" description: Reference for Anthropic provider-executed tools. type: reference summary: Reference for Anthropic provider tool helpers. diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx index 51773b62..dcf08006 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx @@ -15,3 +15,43 @@ model = ai.Model("gpt-5", provider=provider) The optional upstream OpenAI SDK loads lazily when the provider creates or uses an SDK client. + +## OpenAICompatibleProvider + +`OpenAICompatibleProvider` implements `Provider` for OpenAI-compatible APIs. + +Default configuration for the `openai` provider uses: + +- `OPENAI_API_KEY` +- `OPENAI_BASE_URL` + +Pass `base_url`, `api_key`, or a custom client through `get_provider` when you +need explicit configuration. + +```python +provider = ai.get_provider( + "openai", + base_url="http://localhost:11434/v1", +) +model = ai.Model("llama3", provider=provider) +``` + +The provider supports model listing, probing, streaming, provider-executed +tools, and custom OpenAI-compatible clients. + +## Protocols + +OpenAI-compatible protocols translate SDK messages and params to OpenAI wire +formats. + +Types: + +- `OpenAIResponsesProtocol` +- `OpenAIChatCompletionsProtocol` + +The provider chooses a default protocol for the configured provider. Use these +classes directly only when you need a protocol override. + +## Tools + +Provider-executed OpenAI tools are documented on the child `tools` page. diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json b/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json index 044dd85f..45088200 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/meta.json @@ -1,9 +1,7 @@ { - "title": "ai.providers.openai", + "title": "openai", "description": "Reference for OpenAI-compatible provider APIs.", "pages": [ - "provider", - "protocols", "tools" ] } diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx deleted file mode 100644 index 9eb63ca1..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/openai/protocols.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "ai.providers.openai protocols" -description: Reference for OpenAI-compatible protocols. -type: reference -summary: Reference for OpenAIResponsesProtocol and OpenAIChatCompletionsProtocol. ---- - -OpenAI-compatible protocols translate SDK messages and params to OpenAI wire -formats. - -## Types - -- `OpenAIResponsesProtocol` -- `OpenAIChatCompletionsProtocol` diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx deleted file mode 100644 index 7e3fa1ea..00000000 --- a/docs/ai-python/content/docs/reference/ai.providers/openai/provider.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai.providers.openai.OpenAICompatibleProvider" -description: Reference for the OpenAI-compatible provider. -type: reference -summary: Reference for ai.providers.openai.OpenAICompatibleProvider. ---- - -`OpenAICompatibleProvider` implements `Provider` for OpenAI-compatible APIs. - -Default configuration uses: - -- `OPENAI_API_KEY` -- `OPENAI_BASE_URL` - -Pass `base_url`, `api_key`, or a custom client through `get_provider` when you -need explicit configuration. diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx index bf6380f6..182cca33 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/tools.mdx @@ -1,5 +1,5 @@ --- -title: "ai.providers.openai.tools" +title: "tools" description: Reference for OpenAI provider-executed tools. type: reference summary: Reference for OpenAI provider tool helpers. From ed80fa8514db2769332f331881f9b55bad225917 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 11:32:21 -0700 Subject: [PATCH 08/19] Prune unused files --- .../docs/reference/ai/agent-factory.mdx | 21 -------- .../content/docs/reference/ai/agent-tool.mdx | 19 ------- .../content/docs/reference/ai/context.mdx | 51 ------------------- .../content/docs/reference/ai/hooks.mdx | 47 ----------------- .../reference/ai/media-generation-params.mdx | 38 -------------- .../docs/reference/ai/message-builders.mdx | 15 ------ .../docs/reference/ai/model-params.mdx | 46 ----------------- .../content/docs/reference/ai/model.mdx | 30 ----------- .../docs/reference/ai/part-builders.mdx | 16 ------ .../content/docs/reference/ai/probe.mdx | 15 ------ .../docs/reference/ai/provider-protocol.mdx | 11 ---- .../content/docs/reference/ai/provider.mdx | 32 ------------ .../docs/reference/ai/routing-params.mdx | 19 ------- .../docs/reference/ai/streaming-tools.mdx | 17 ------- .../content/docs/reference/ai/tool-call.mdx | 24 --------- .../docs/reference/ai/tool-decorator.mdx | 33 ------------ .../docs/reference/ai/tool-results.mdx | 17 ------- .../content/docs/reference/ai/tool-runner.mdx | 24 --------- .../content/docs/reference/ai/yield-from.mdx | 16 ------ 19 files changed, 491 deletions(-) delete mode 100644 docs/ai-python/content/docs/reference/ai/agent-factory.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/agent-tool.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/context.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/hooks.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/media-generation-params.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/message-builders.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/model-params.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/model.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/part-builders.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/probe.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/provider-protocol.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/provider.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/routing-params.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/streaming-tools.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/tool-call.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/tool-decorator.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/tool-results.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/tool-runner.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai/yield-from.mdx diff --git a/docs/ai-python/content/docs/reference/ai/agent-factory.mdx b/docs/ai-python/content/docs/reference/ai/agent-factory.mdx deleted file mode 100644 index 01ee01da..00000000 --- a/docs/ai-python/content/docs/reference/ai/agent-factory.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "ai.agent" -description: Create an Agent with the default loop. -type: reference -summary: Reference for ai.agent. ---- - -`agent` creates an `Agent`. - -```python -agent = ai.agent(tools=[contact_mothership]) -``` - -## Arguments - -- `tools`: Optional `AgentTool` values from `@ai.tool` and schema-only `ai.Tool` - declarations for provider-executed tools. - -## Return value - -Returns `ai.Agent`. diff --git a/docs/ai-python/content/docs/reference/ai/agent-tool.mdx b/docs/ai-python/content/docs/reference/ai/agent-tool.mdx deleted file mode 100644 index b20c2ed7..00000000 --- a/docs/ai-python/content/docs/reference/ai/agent-tool.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "ai.AgentTool" -description: Reference for executable agent tools. -type: reference -summary: Reference for ai.AgentTool. ---- - -`AgentTool` binds a model-facing `Tool` declaration to an executable Python -function. - -```python -tool.name -tool.tool -tool.fn -tool.validator -tool.require_approval -``` - -Pass `AgentTool` values to `ai.agent(tools=[...])`. diff --git a/docs/ai-python/content/docs/reference/ai/context.mdx b/docs/ai-python/content/docs/reference/ai/context.mdx deleted file mode 100644 index fe1d7bf8..00000000 --- a/docs/ai-python/content/docs/reference/ai/context.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: "ai.Context" -description: Resolve and update agent context. -type: reference -summary: Reference for ai.Context. ---- - -Custom loops use `Context` to resolve model tool calls and `ToolRunner` to run -them. - -`Context` contains the state for one agent run. - -```python -context.model -context.messages -context.tools -context.output_type -context.params -``` - -## Context.keep_running - -```python -while context.keep_running(): - ... -``` - -`keep_running()` returns `True` while the last message still needs work. A final -assistant message stops the loop. A pending hook result also stops the loop -until the hook resolves. - -## Context.resolve - -```python -tool_call = context.resolve(event.tool_call) -tool_calls = context.resolve(message.tool_calls) -``` - -`resolve` converts `ToolCallPart` values into callable `ToolCall` objects. If -the registered tool has `require_approval=True`, the returned call is wrapped -with approval behavior. - -## Context.add - -```python -context.add(stream.message) -context.add(tool_runner.get_tool_message()) -``` - -`add` appends messages to history. Replay-marked assistant messages are skipped -to avoid duplicate history during resume flows. diff --git a/docs/ai-python/content/docs/reference/ai/hooks.mdx b/docs/ai-python/content/docs/reference/ai/hooks.mdx deleted file mode 100644 index 1b955cae..00000000 --- a/docs/ai-python/content/docs/reference/ai/hooks.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: "ai hooks" -description: "Suspend and resume agent workflows for external input." -type: reference -summary: "Reference for ai.hook, ai.resolve_hook, ai.abort_pending_hook, and ai.cancel_hook." ---- - -Hooks let an agent pause while another process or UI supplies a decision. - -## hook - -```python -approval = await ai.hook( - "approve_contact_mothership", - payload=ai.tools.ToolApproval, - metadata={"tool": "contact_mothership"}, -) -``` - -`hook` emits a pending hook event and waits for a matching resolution. The -return value is an instance of the `payload` model. - -## resolve_hook - -```python -ai.resolve_hook(label, data, payload=None) -``` - -`data` can be a dict, a Pydantic model, or an exception. If no live hook -exists, the resolution is stored and consumed by the next matching hook. - -## abort_pending_hook - -```python -ai.abort_pending_hook(hook_part) -``` - -Mark a serialized pending hook as aborted before replaying or continuing a -run. - -## cancel_hook - -```python -await ai.cancel_hook(label, reason="client disconnected") -``` - -Cancel a live hook by label. diff --git a/docs/ai-python/content/docs/reference/ai/media-generation-params.mdx b/docs/ai-python/content/docs/reference/ai/media-generation-params.mdx deleted file mode 100644 index 13f69d70..00000000 --- a/docs/ai-python/content/docs/reference/ai/media-generation-params.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: "ai media generation params" -description: Reference for media generation params. -type: reference -summary: Reference for ImageParams, VideoParams, and GenerateParams. ---- - -Media params configure non-streaming generation with `ai.generate`. - -## ImageParams - -```python -ai.ImageParams( - n=1, - size=None, - aspect_ratio=None, - seed=None, - provider_options={}, -) -``` - -## VideoParams - -```python -ai.VideoParams( - n=1, - aspect_ratio=None, - resolution=None, - duration=None, - fps=None, - seed=None, - provider_options={}, -) -``` - -## GenerateParams - -`GenerateParams` is the accepted media params union for `ai.generate`. diff --git a/docs/ai-python/content/docs/reference/ai/message-builders.mdx b/docs/ai-python/content/docs/reference/ai/message-builders.mdx deleted file mode 100644 index 88910dc4..00000000 --- a/docs/ai-python/content/docs/reference/ai/message-builders.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai message builders" -description: Reference for message builder helpers. -type: reference -summary: Reference for system_message, user_message, assistant_message, and tool_message. ---- - -Message builders create `Message` values. - -```python -ai.system_message("You are concise.") -ai.user_message("Hello", ai.file_part(data, media_type="image/png")) -ai.assistant_message("Hi") -ai.tool_message(tool_call_id="tc_1", result="done", tool_name="lookup") -``` diff --git a/docs/ai-python/content/docs/reference/ai/model-params.mdx b/docs/ai-python/content/docs/reference/ai/model-params.mdx deleted file mode 100644 index 3426a4b8..00000000 --- a/docs/ai-python/content/docs/reference/ai/model-params.mdx +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: "ai model params" -description: "Reference for model request parameter types." -type: reference -summary: "Reference for parameter objects passed to ai.stream, ai.generate, and Agent.run." ---- - -Model params are top-level `ai` types. - -Use `InferenceRequestParams` with `ai.stream` and `Agent.run`. Use -`ImageParams` and `VideoParams` with `ai.generate`. - -## Request params - -- `InferenceRequestParams` -- `ProviderServiceParams` -- `ReasoningParams` -- `OutputParams` -- `CacheParams` -- `ContextManagementParams` - -## Sampling params - -- `TemperatureSamplerParams` -- `TopKSamplerParams` -- `TopPSamplerParams` -- `MinPSamplerParams` -- `RepetitionPenaltyParams` -- `SeedSamplerParams` -- `RandomSeed` -- `RANDOM` -- `DEFAULT` -- `UNSET` - -## Tool calling params - -- `ToolCallingParams` -- `ToolChoiceMode` -- `ToolSelection` -- `ToolRef` - -```python -params = ai.InferenceRequestParams().with_temperature(0) -async with ai.stream(model, messages, params=params) as stream: - ... -``` diff --git a/docs/ai-python/content/docs/reference/ai/model.mdx b/docs/ai-python/content/docs/reference/ai/model.mdx deleted file mode 100644 index cf77c4cc..00000000 --- a/docs/ai-python/content/docs/reference/ai/model.mdx +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "ai.Model" -description: Reference for model references. -type: reference -summary: Reference for ai.Model. ---- - -`Model` identifies what to call. Providers own credentials, clients, endpoints, -model listing, and wire translation. - -```python -model = ai.Model("gpt-5", provider=provider) -model.id -model.provider -model.protocol -model.with_protocol(protocol) -``` - -`Model` is a lightweight reference. It does not own network state. - -## Fields - -- `id`: Provider model id. -- `provider`: Provider instance or provider id. -- `protocol`: Optional provider protocol override. - -## Methods - -- `with_protocol(protocol)`: Return a copy that uses a specific provider - protocol. diff --git a/docs/ai-python/content/docs/reference/ai/part-builders.mdx b/docs/ai-python/content/docs/reference/ai/part-builders.mdx deleted file mode 100644 index c7021c27..00000000 --- a/docs/ai-python/content/docs/reference/ai/part-builders.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai part builders" -description: Reference for message part builders. -type: reference -summary: Reference for text_part, file_part, thinking, content_output, and tool_result_part. ---- - -Part builders create message part values. - -```python -ai.text_part("hello") -ai.file_part(data, media_type="image/png", filename="image.png") -ai.thinking("reasoning text") -ai.content_output("caption", ai.file_part(png_bytes, media_type="image/png")) -ai.tool_result_part("tc_1", result={"ok": True}, tool_name="lookup") -``` diff --git a/docs/ai-python/content/docs/reference/ai/probe.mdx b/docs/ai-python/content/docs/reference/ai/probe.mdx deleted file mode 100644 index 25ac8518..00000000 --- a/docs/ai-python/content/docs/reference/ai/probe.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "ai.probe" -description: Check whether a provider can reach a model. -type: reference -summary: Reference for ai.probe. ---- - -`probe` asks the model provider to verify that a model exists and is reachable. - -```python -await ai.probe(model) -``` - -It raises a provider error unless the provider is configured, reachable, and -able to find the model. diff --git a/docs/ai-python/content/docs/reference/ai/provider-protocol.mdx b/docs/ai-python/content/docs/reference/ai/provider-protocol.mdx deleted file mode 100644 index 6d49c377..00000000 --- a/docs/ai-python/content/docs/reference/ai/provider-protocol.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "ai.ProviderProtocol" -description: Reference for provider wire protocols. -type: reference -summary: Reference for ai.ProviderProtocol. ---- - -Provider protocols translate messages, tools, params, and generated files to -provider wire formats. - -Provider instances use a protocol for `stream` and `generate` calls. diff --git a/docs/ai-python/content/docs/reference/ai/provider.mdx b/docs/ai-python/content/docs/reference/ai/provider.mdx deleted file mode 100644 index 843cbffa..00000000 --- a/docs/ai-python/content/docs/reference/ai/provider.mdx +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: "ai.Provider" -description: Reference for provider instances. -type: reference -summary: Reference for ai.Provider. ---- - -Provider instances own credentials, clients, endpoints, model listing, and wire -translation. - -```python -provider.name -provider.base_url -provider.default_base_url -provider.api_key -provider.api_key_env -provider.base_url_env -provider.headers -provider.client -provider.is_configured() -await provider.list_models() -await provider.probe(model) -await provider.aclose() -``` - -`provider.stream(...)` and `provider.generate(...)` are usually called through -`ai.stream` and `ai.generate`. - -## Custom providers - -Add a provider by subclassing `ai.Provider`, setting `handles`, and -implementing provider-specific behavior. diff --git a/docs/ai-python/content/docs/reference/ai/routing-params.mdx b/docs/ai-python/content/docs/reference/ai/routing-params.mdx deleted file mode 100644 index f67e2e02..00000000 --- a/docs/ai-python/content/docs/reference/ai/routing-params.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "ai routing params" -description: Reference for routing parameter types. -type: reference -summary: Reference for RoutingParams, routing targets, regions, and ranking strategies. ---- - -Routing params configure provider or gateway routing behavior. - -## Types - -- `RoutingParams` -- `RoutingTarget` -- `RoutingTargetChain` -- `GeoRegion` -- `CloudRegion` -- `ProviderRankingStrategy` - -Use `GLOBAL` for global routing when supported by the provider. diff --git a/docs/ai-python/content/docs/reference/ai/streaming-tools.mdx b/docs/ai-python/content/docs/reference/ai/streaming-tools.mdx deleted file mode 100644 index 7bf4d8fa..00000000 --- a/docs/ai-python/content/docs/reference/ai/streaming-tools.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: "ai streaming tools" -description: Reference for streaming tool return aliases. -type: reference -summary: Reference for StreamingTextTool, StreamingStatusTool, and SubAgentTool. ---- - -Async-generator tools can yield partial output while they run. The agent emits -`ai.events.PartialToolCallResult` events for yielded values. - -## Built-in aliases - -- `StreamingTextTool`: Concatenate yielded strings. -- `StreamingStatusTool[T]`: Treat intermediate yields as status updates and the - last yielded value as the final result. -- `SubAgentTool`: Forward nested agent events and use the nested final text as - model input. diff --git a/docs/ai-python/content/docs/reference/ai/tool-call.mdx b/docs/ai-python/content/docs/reference/ai/tool-call.mdx deleted file mode 100644 index 4b5c1fa1..00000000 --- a/docs/ai-python/content/docs/reference/ai/tool-call.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "ai.agents tool calls" -description: Reference for executable tool calls. -type: reference -summary: Reference for ToolCall, BoundToolCall, and GatedToolCall. ---- - -Tool calls are executable runtime objects produced by `Context.resolve`. - -## ToolCall - -```python -tool_call.id -tool_call.name -tool_call.fn -tool_call.kwargs -result = await tool_call() -``` - -## Implementations - -- `BoundToolCall`: Default executable call. -- `GatedToolCall`: Wraps another call with an approval hook. -- `ToolCallCallable`: Protocol for values a `ToolRunner` can schedule. diff --git a/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx b/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx deleted file mode 100644 index b2c1c48e..00000000 --- a/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: "ai.tool" -description: Define executable tools from Python functions. -type: reference -summary: Reference for ai.tool. ---- - -`@ai.tool` turns an async Python function into an executable `AgentTool` plus a -model-facing `ai.Tool` declaration. - -```python -@ai.tool -async def contact_mothership(query: str) -> str: - """Contact the mothership.""" - return "Soon." -``` - -## Forms - -```python -@ai.tool -async def name(...) -> Result: ... - -@ai.tool(require_approval=True) -async def name(...) -> Result: ... - -@ai.tool(aggregator=...) -async def name(...) -> AsyncGenerator[Item]: ... -``` - -The function name becomes the tool name. The docstring becomes the tool -description. The function signature becomes a Pydantic validator and JSON -schema. diff --git a/docs/ai-python/content/docs/reference/ai/tool-results.mdx b/docs/ai-python/content/docs/reference/ai/tool-results.mdx deleted file mode 100644 index b1c58919..00000000 --- a/docs/ai-python/content/docs/reference/ai/tool-results.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: "ai.agents tool result helpers" -description: Create tool result events and pending tool results. -type: reference -summary: Reference for tool_result and pending_tool_result. ---- - -Tool result helpers create event-layer values used by custom loops and -resumable tool approval flows. - -```python -ai.tool_result(tool_call_id="tc_1", tool_name="lookup", result={"ok": True}) -ai.pending_tool_result(hook_part, tool_call_id="tc_1", tool_name="lookup") -``` - -Use message builders such as `ai.tool_message` and `ai.tool_result_part` for -message-layer values. diff --git a/docs/ai-python/content/docs/reference/ai/tool-runner.mdx b/docs/ai-python/content/docs/reference/ai/tool-runner.mdx deleted file mode 100644 index 669fc07b..00000000 --- a/docs/ai-python/content/docs/reference/ai/tool-runner.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "ai.ToolRunner" -description: Schedule and collect tool calls in custom loops. -type: reference -summary: Reference for ai.ToolRunner. ---- - -Custom loops use `Context` to resolve model tool calls and `ToolRunner` to run -them. - -```python -async with ai.ToolRunner() as runner: - runner.schedule(tool_call) - async for result in runner.events(): - ... - message = runner.get_tool_message() -``` - -`schedule` starts the call in the runner's task group. `events()` yields -`ToolCallResult` values as calls finish. `get_tool_message()` merges collected -results into one `role="tool"` message. - -Use `add_result(result)` when a custom loop executes a tool itself but still -wants the runner to aggregate the result message. diff --git a/docs/ai-python/content/docs/reference/ai/yield-from.mdx b/docs/ai-python/content/docs/reference/ai/yield-from.mdx deleted file mode 100644 index 270f86cc..00000000 --- a/docs/ai-python/content/docs/reference/ai/yield-from.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "ai.yield_from" -description: "Forward events from nested async generators." -type: reference -summary: "Reference for ai.yield_from." ---- - -`yield_from` forwards events from a nested async generator and returns the -nested generator result. - -It is useful in custom agent loops and streaming tools that compose another -async generator. - -```python -result = await ai.yield_from(generator) -``` From 4b598215be152371c35e2afd96d32adda87ba446 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 13:07:35 -0700 Subject: [PATCH 09/19] Dedupe and compress the docs more --- .../docs/reference/ai.agents/aggregators.mdx | 20 ------ .../reference/ai.agents/gated-tool-call.mdx | 12 ---- .../docs/reference/ai.agents/index.mdx | 29 +++++++- .../docs/reference/ai.agents/meta.json | 2 - .../content/docs/reference/ai/index.mdx | 71 +------------------ .../content/docs/reference/ai/meta.json | 2 +- .../ai/{tool.mdx => tool-decorator.mdx} | 10 +-- 7 files changed, 37 insertions(+), 109 deletions(-) delete mode 100644 docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx delete mode 100644 docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx rename docs/ai-python/content/docs/reference/ai/{tool.mdx => tool-decorator.mdx} (78%) diff --git a/docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx b/docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx deleted file mode 100644 index 1b011b19..00000000 --- a/docs/ai-python/content/docs/reference/ai.agents/aggregators.mdx +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "ai.agents aggregators" -description: Reference for streaming tool aggregation helpers. -type: reference -summary: Reference for Aggregate, yield_from, and built-in aggregators. ---- - -Aggregators collect yielded values from streaming tools and decide what value is -stored and what value is sent back to the model. - -## APIs - -- `Aggregate` -- `yield_from` -- `SimpleAggregator` -- `ConcatAggregator` -- `LastAggregator` -- `MessageAggregator` - -Custom aggregators implement `ai.events.Aggregator`. diff --git a/docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx b/docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx deleted file mode 100644 index 3f9d4260..00000000 --- a/docs/ai-python/content/docs/reference/ai.agents/gated-tool-call.mdx +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "ai.agents.GatedToolCall" -description: "Gate a tool call before execution." -type: reference -summary: "Reference for ai.agents.GatedToolCall." ---- - -`GatedToolCall` wraps a tool call that requires approval or another gate -before execution. - -Use it in custom agent loops when you need to delay or externally approve a -scheduled tool call. diff --git a/docs/ai-python/content/docs/reference/ai.agents/index.mdx b/docs/ai-python/content/docs/reference/ai.agents/index.mdx index a35948bb..87c083d5 100644 --- a/docs/ai-python/content/docs/reference/ai.agents/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.agents/index.mdx @@ -9,13 +9,38 @@ Most agent APIs are documented as top-level `ai` exports. Use `ai.agents` for advanced agent namespace APIs and types that are not promoted to the top-level namespace. -Public advanced APIs: +## Aggregators + +Aggregators collect yielded values from streaming tools and decide what value is +stored and what value is sent back to the model. + +APIs: - `Aggregate` +- `yield_from` - `SimpleAggregator` - `ConcatAggregator` - `LastAggregator` - `MessageAggregator` + +Custom aggregators implement `ai.events.Aggregator`. + +`yield_from` forwards events from a nested async generator and returns the +nested generator result. + +```python +result = await ai.agents.yield_from(generator) +``` + +## Tool Calls + - `BoundToolCall` -- `GatedToolCall` - `ToolCallCallable` + +## GatedToolCall + +`GatedToolCall` wraps a tool call that requires approval or another gate before +execution. + +Use it in custom agent loops when you need to delay or externally approve a +scheduled tool call. diff --git a/docs/ai-python/content/docs/reference/ai.agents/meta.json b/docs/ai-python/content/docs/reference/ai.agents/meta.json index 64546d58..af9cfc48 100644 --- a/docs/ai-python/content/docs/reference/ai.agents/meta.json +++ b/docs/ai-python/content/docs/reference/ai.agents/meta.json @@ -2,8 +2,6 @@ "title": "ai.agents", "description": "Reference for advanced agent namespace APIs.", "pages": [ - "aggregators", - "gated-tool-call", "ui" ] } diff --git a/docs/ai-python/content/docs/reference/ai/index.mdx b/docs/ai-python/content/docs/reference/ai/index.mdx index b3e87d76..b83c063d 100644 --- a/docs/ai-python/content/docs/reference/ai/index.mdx +++ b/docs/ai-python/content/docs/reference/ai/index.mdx @@ -27,8 +27,8 @@ These top-level exports have their own pages under `ai`. `Model`. - [`get_provider`](/docs/reference/ai/get-provider): Resolve and configure a provider. -- [`tool`](/docs/reference/ai/tool): Define executable tools from Python - functions. +- [`@ai.tool`](/docs/reference/ai/tool-decorator): Define executable tools from + Python functions. - [`Agent`](/docs/reference/ai/agent): Run the default agent loop. ## Module aliases @@ -229,25 +229,6 @@ Part builder exports: ## Tools and Agents -### Tool - -`Tool` is the model-facing tool declaration used by providers. - -```python -tool = ai.Tool( - kind="function", - name="lookup", - spec=ai.tools.ToolSpec( - description="Look up a value.", - params={"type": "object", "properties": {}}, - ), -) -``` - -Pass `Tool` values to `stream(..., tools=[...])` or to an agent when the -provider should receive the declaration directly. For Python callables, use -`tool` instead. - ### agent `agent` creates an `Agent`. @@ -366,52 +347,6 @@ Hook exports: - `abort_pending_hook`: Mark a serialized pending hook as aborted. - `cancel_hook`: Cancel a live hook by label. -### yield_from - -`yield_from` forwards events from a nested async generator and returns the -nested generator result. - -```python -result = await ai.yield_from(generator) -``` - ## Errors -Top-level error exports are re-exported from [`ai.errors`](/docs/reference/errors). - -Base errors: - -- `AIError` -- `ConfigurationError` -- `InstallationError` -- `UnsupportedProviderError` - -HTTP context: - -- `HTTPErrorContext` - -Provider errors: - -- `ProviderError` -- `ProviderNotConfiguredError` -- `ProviderAPIError` -- `ProviderConnectionError` -- `ProviderTimeoutError` -- `ProviderResponseError` - -Provider status errors: - -- `ProviderStatusError` -- `ProviderBadRequestError` -- `ProviderAuthenticationError` -- `ProviderPermissionDeniedError` -- `ProviderNotFoundError` -- `ProviderModelNotFoundError` -- `ProviderConflictError` -- `ProviderRequestTooLargeError` -- `ProviderUnprocessableEntityError` -- `ProviderRateLimitError` -- `ProviderInternalServerError` -- `ProviderServiceUnavailableError` -- `ProviderDeadlineExceededError` -- `ProviderOverloadedError` +Top-level error exports are documented in [`ai.errors`](/docs/reference/errors). diff --git a/docs/ai-python/content/docs/reference/ai/meta.json b/docs/ai-python/content/docs/reference/ai/meta.json index 0cb23b0a..56627c36 100644 --- a/docs/ai-python/content/docs/reference/ai/meta.json +++ b/docs/ai-python/content/docs/reference/ai/meta.json @@ -6,7 +6,7 @@ "generate", "get-model", "get-provider", - "tool", + "tool-decorator", "agent" ] } diff --git a/docs/ai-python/content/docs/reference/ai/tool.mdx b/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx similarity index 78% rename from docs/ai-python/content/docs/reference/ai/tool.mdx rename to docs/ai-python/content/docs/reference/ai/tool-decorator.mdx index 519ee9d6..b1062c6b 100644 --- a/docs/ai-python/content/docs/reference/ai/tool.mdx +++ b/docs/ai-python/content/docs/reference/ai/tool-decorator.mdx @@ -1,12 +1,11 @@ --- -title: "tool" +title: "@ai.tool" description: Define executable tools from Python functions. type: reference -summary: Reference for ai.tool. +summary: Reference for the ai.tool decorator. --- -`@ai.tool` turns an async Python function into an executable `AgentTool` plus a -model-facing `ai.Tool` declaration. +`@ai.tool` turns an async Python function into an executable `AgentTool`. ```python @ai.tool @@ -31,3 +30,6 @@ async def name(...) -> AsyncGenerator[Item]: ... The function name becomes the tool name. The docstring becomes the tool description. The function signature becomes a Pydantic validator and JSON schema. + +For model-facing tool declarations and provider-executed tools, use +[`ai.tools`](/docs/reference/tools). From b9dad3df60fedad6c87abe1fc6b33eead0af4766 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 14:11:05 -0700 Subject: [PATCH 10/19] Rename all skills and add framework version in metadata --- .../SKILL.md | 6 ++++-- skills/{ai => ai-python-basics}/SKILL.md | 13 ++++++++----- .../{custom_loop => ai-python-custom-loop}/SKILL.md | 10 ++++++---- .../SKILL.md | 6 ++++-- .../SKILL.md | 6 ++++-- .../SKILL.md | 6 ++++-- .../SKILL.md | 6 ++++-- skills/{subagents => ai-python-subagents}/SKILL.md | 8 +++++--- 8 files changed, 39 insertions(+), 22 deletions(-) rename skills/{ai_sdk_ui_adapter => ai-python-ai-sdk-ui-adapter}/SKILL.md (94%) rename skills/{ai => ai-python-basics}/SKILL.md (80%) rename skills/{custom_loop => ai-python-custom-loop}/SKILL.md (90%) rename skills/{custom_provider => ai-python-custom-provider}/SKILL.md (96%) rename skills/{durable_execution => ai-python-durable-execution}/SKILL.md (93%) rename skills/{serverless_execution => ai-python-serverless-execution}/SKILL.md (92%) rename skills/{streaming_tools => ai-python-streaming-tools}/SKILL.md (93%) rename skills/{subagents => ai-python-subagents}/SKILL.md (90%) diff --git a/skills/ai_sdk_ui_adapter/SKILL.md b/skills/ai-python-ai-sdk-ui-adapter/SKILL.md similarity index 94% rename from skills/ai_sdk_ui_adapter/SKILL.md rename to skills/ai-python-ai-sdk-ui-adapter/SKILL.md index 14052629..3e241e15 100644 --- a/skills/ai_sdk_ui_adapter/SKILL.md +++ b/skills/ai-python-ai-sdk-ui-adapter/SKILL.md @@ -1,9 +1,11 @@ --- -name: ai_sdk_ui_adapter +name: ai-python-ai-sdk-ui-adapter description: Use when connecting Python ai SDK agents to AI SDK UI useChat clients, UIMessage history, streamed responses, and approvals. +metadata: + sdk-version: "0.2.1" --- -# ai_sdk_ui_adapter +# ai-python-ai-sdk-ui-adapter Frontend: diff --git a/skills/ai/SKILL.md b/skills/ai-python-basics/SKILL.md similarity index 80% rename from skills/ai/SKILL.md rename to skills/ai-python-basics/SKILL.md index 46a277d7..18b2c6d9 100644 --- a/skills/ai/SKILL.md +++ b/skills/ai-python-basics/SKILL.md @@ -1,9 +1,11 @@ --- -name: ai +name: ai-python-basics description: Use for Python ai SDK basics: models, messages, streaming, tools, agents, and the minimal happy path. +metadata: + sdk-version: "0.2.1" --- -# ai +# ai-python Install with `uv add ai`. @@ -62,6 +64,7 @@ answer = run.output history = run.messages ``` -Use `custom_loop`, `subagents`, `streaming_tools`, `serverless_execution`, -`durable_execution`, `ai_sdk_ui_adapter`, and `custom_provider` for advanced -patterns. +Use `ai-python-custom-loop`, `ai-python-subagents`, +`ai-python-streaming-tools`, `ai-python-serverless-execution`, +`ai-python-durable-execution`, `ai-python-ai-sdk-ui-adapter`, and +`ai-python-custom-provider` for advanced patterns. diff --git a/skills/custom_loop/SKILL.md b/skills/ai-python-custom-loop/SKILL.md similarity index 90% rename from skills/custom_loop/SKILL.md rename to skills/ai-python-custom-loop/SKILL.md index 6857db7f..af07f5fb 100644 --- a/skills/custom_loop/SKILL.md +++ b/skills/ai-python-custom-loop/SKILL.md @@ -1,9 +1,11 @@ --- -name: custom_loop +name: ai-python-custom-loop description: Use when changing a Python ai SDK agent loop for custom tool order, routing, logging, hooks, replay, or scheduling. +metadata: + sdk-version: "0.2.1" --- -# custom_loop +# ai-python-custom-loop Keep the default shape unless you must change control flow: @@ -37,5 +39,5 @@ Rules: - If you make a result yourself, use `runner.add_result(ai.tool_result(...))`. - Add `stream.message`, then `runner.get_tool_message()`. `context.add(...)` skips replay messages. - Every tool call must get one tool result. -- For hooks, let `context.resolve(...)` build the gated call. Use `serverless_execution` for request boundaries. -- For durable calls, keep this shape and wrap only model or tool I/O. Use `durable_execution`. +- For hooks, let `context.resolve(...)` build the gated call. Use `ai-python-serverless-execution` for request boundaries. +- For durable calls, keep this shape and wrap only model or tool I/O. Use `ai-python-durable-execution`. diff --git a/skills/custom_provider/SKILL.md b/skills/ai-python-custom-provider/SKILL.md similarity index 96% rename from skills/custom_provider/SKILL.md rename to skills/ai-python-custom-provider/SKILL.md index 63c57506..efbc946d 100644 --- a/skills/custom_provider/SKILL.md +++ b/skills/ai-python-custom-provider/SKILL.md @@ -1,9 +1,11 @@ --- -name: custom_provider +name: ai-python-custom-provider description: Use for writing custom Python ai SDK providers and protocols. +metadata: + sdk-version: "0.2.1" --- -# custom_provider +# ai-python-custom-provider Providers emit model events. They do not run Python tools. `ai.stream` collects events into a `Message`. `ai.Agent` adds tool execution, hooks, and replay. diff --git a/skills/durable_execution/SKILL.md b/skills/ai-python-durable-execution/SKILL.md similarity index 93% rename from skills/durable_execution/SKILL.md rename to skills/ai-python-durable-execution/SKILL.md index 251cdfde..505113e8 100644 --- a/skills/durable_execution/SKILL.md +++ b/skills/ai-python-durable-execution/SKILL.md @@ -1,9 +1,11 @@ --- -name: durable_execution +name: ai-python-durable-execution description: Use for Python ai SDK durable execution, serialization boundaries, replay, and workflow engines such as Temporal. +metadata: + sdk-version: "0.2.1" --- -# durable_execution +# ai-python-durable-execution Durability belongs at I/O boundaries. Keep the framework pieces when possible: `Agent`, `Context`, messages, `ai.stream`, `ToolRunner`, and `@ai.tool`. diff --git a/skills/serverless_execution/SKILL.md b/skills/ai-python-serverless-execution/SKILL.md similarity index 92% rename from skills/serverless_execution/SKILL.md rename to skills/ai-python-serverless-execution/SKILL.md index b2e34920..76432dbd 100644 --- a/skills/serverless_execution/SKILL.md +++ b/skills/ai-python-serverless-execution/SKILL.md @@ -1,9 +1,11 @@ --- -name: serverless_execution +name: ai-python-serverless-execution description: Use for Python ai SDK hook interruptions, approvals, replay, and resume across stateless requests. +metadata: + sdk-version: "0.2.1" --- -# serverless_execution +# ai-python-serverless-execution Use hooks to stop a run, save messages, then replay from the same assistant turn. diff --git a/skills/streaming_tools/SKILL.md b/skills/ai-python-streaming-tools/SKILL.md similarity index 93% rename from skills/streaming_tools/SKILL.md rename to skills/ai-python-streaming-tools/SKILL.md index 964571fd..04315d13 100644 --- a/skills/streaming_tools/SKILL.md +++ b/skills/ai-python-streaming-tools/SKILL.md @@ -1,9 +1,11 @@ --- -name: streaming_tools +name: ai-python-streaming-tools description: Use for Python ai SDK tools that stream partial output, nested agent events, MessageBundle values, or preliminary UI output. +metadata: + sdk-version: "0.2.1" --- -# streaming_tools +# ai-python-streaming-tools Make a streaming tool an async generator. diff --git a/skills/subagents/SKILL.md b/skills/ai-python-subagents/SKILL.md similarity index 90% rename from skills/subagents/SKILL.md rename to skills/ai-python-subagents/SKILL.md index 1475b467..c39ad416 100644 --- a/skills/subagents/SKILL.md +++ b/skills/ai-python-subagents/SKILL.md @@ -1,9 +1,11 @@ --- -name: subagents +name: ai-python-subagents description: Use for the subagent-as-a-tool pattern and other Python ai SDK multi-agent handoffs. +metadata: + sdk-version: "0.2.1" --- -# subagents +# ai-python-subagents Use a subagent tool when the parent model should choose when to call another agent. @@ -37,4 +39,4 @@ Do not append child messages to the parent history yourself. The tool result stores the child transcript as a `MessageBundle`. For `MessageBundle`, preliminary output, and streaming tool details, use -`streaming_tools`. +`ai-python-streaming-tools`. From c40c8454ea1cf89b7ae830d2c2f54ef7229657b3 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 14:30:48 -0700 Subject: [PATCH 11/19] Shorten skills descriptions --- skills/ai-python-basics/SKILL.md | 4 ++-- skills/ai-python-custom-loop/SKILL.md | 2 +- skills/ai-python-custom-provider/SKILL.md | 2 +- skills/ai-python-durable-execution/SKILL.md | 2 +- skills/ai-python-serverless-execution/SKILL.md | 2 +- skills/ai-python-streaming-tools/SKILL.md | 2 +- skills/ai-python-subagents/SKILL.md | 2 +- .../SKILL.md | 6 +++--- 8 files changed, 11 insertions(+), 11 deletions(-) rename skills/{ai-python-ai-sdk-ui-adapter => ai-python-ui-adapter}/SKILL.md (88%) diff --git a/skills/ai-python-basics/SKILL.md b/skills/ai-python-basics/SKILL.md index 18b2c6d9..094e704a 100644 --- a/skills/ai-python-basics/SKILL.md +++ b/skills/ai-python-basics/SKILL.md @@ -1,11 +1,11 @@ --- name: ai-python-basics -description: Use for Python ai SDK basics: models, messages, streaming, tools, agents, and the minimal happy path. +description: Use for AI SDK for Python basics. Configure a model, make messages, stream, declare tools, build a basic agent. metadata: sdk-version: "0.2.1" --- -# ai-python +# ai-python-basics Install with `uv add ai`. diff --git a/skills/ai-python-custom-loop/SKILL.md b/skills/ai-python-custom-loop/SKILL.md index af07f5fb..373258cb 100644 --- a/skills/ai-python-custom-loop/SKILL.md +++ b/skills/ai-python-custom-loop/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-python-custom-loop -description: Use when changing a Python ai SDK agent loop for custom tool order, routing, logging, hooks, replay, or scheduling. +description: Use when building custom agent loops. Modify tool dispatch, history management, hooks, control flow. metadata: sdk-version: "0.2.1" --- diff --git a/skills/ai-python-custom-provider/SKILL.md b/skills/ai-python-custom-provider/SKILL.md index efbc946d..72de40b4 100644 --- a/skills/ai-python-custom-provider/SKILL.md +++ b/skills/ai-python-custom-provider/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-python-custom-provider -description: Use for writing custom Python ai SDK providers and protocols. +description: Use for implementing custom providers in AI SDK for Python. metadata: sdk-version: "0.2.1" --- diff --git a/skills/ai-python-durable-execution/SKILL.md b/skills/ai-python-durable-execution/SKILL.md index 505113e8..703373ea 100644 --- a/skills/ai-python-durable-execution/SKILL.md +++ b/skills/ai-python-durable-execution/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-python-durable-execution -description: Use for Python ai SDK durable execution, serialization boundaries, replay, and workflow engines such as Temporal. +description: Use when adding durable execution to AI SDK for Python or serializing messages. metadata: sdk-version: "0.2.1" --- diff --git a/skills/ai-python-serverless-execution/SKILL.md b/skills/ai-python-serverless-execution/SKILL.md index 76432dbd..f3d23032 100644 --- a/skills/ai-python-serverless-execution/SKILL.md +++ b/skills/ai-python-serverless-execution/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-python-serverless-execution -description: Use for Python ai SDK hook interruptions, approvals, replay, and resume across stateless requests. +description: Use when building with AI SDK for Python in serverless. Correctly do tool approvals, utilize built-in replay and resume. metadata: sdk-version: "0.2.1" --- diff --git a/skills/ai-python-streaming-tools/SKILL.md b/skills/ai-python-streaming-tools/SKILL.md index 04315d13..ce6a76b1 100644 --- a/skills/ai-python-streaming-tools/SKILL.md +++ b/skills/ai-python-streaming-tools/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-python-streaming-tools -description: Use for Python ai SDK tools that stream partial output, nested agent events, MessageBundle values, or preliminary UI output. +description: Use for AI SDK for Python tools that stream output, or contain subagents. Handle interleaved streaming and nested events. metadata: sdk-version: "0.2.1" --- diff --git a/skills/ai-python-subagents/SKILL.md b/skills/ai-python-subagents/SKILL.md index c39ad416..7359c00f 100644 --- a/skills/ai-python-subagents/SKILL.md +++ b/skills/ai-python-subagents/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-python-subagents -description: Use for the subagent-as-a-tool pattern and other Python ai SDK multi-agent handoffs. +description: Use for the subagent-as-a-tool pattern. metadata: sdk-version: "0.2.1" --- diff --git a/skills/ai-python-ai-sdk-ui-adapter/SKILL.md b/skills/ai-python-ui-adapter/SKILL.md similarity index 88% rename from skills/ai-python-ai-sdk-ui-adapter/SKILL.md rename to skills/ai-python-ui-adapter/SKILL.md index 3e241e15..4a0b5df3 100644 --- a/skills/ai-python-ai-sdk-ui-adapter/SKILL.md +++ b/skills/ai-python-ui-adapter/SKILL.md @@ -1,11 +1,11 @@ --- -name: ai-python-ai-sdk-ui-adapter -description: Use when connecting Python ai SDK agents to AI SDK UI useChat clients, UIMessage history, streamed responses, and approvals. +name: ai-python-ui-adapter +description: Use when connecting AI SDK for Python streams to AI SDK UI useChat clients. metadata: sdk-version: "0.2.1" --- -# ai-python-ai-sdk-ui-adapter +# ai-python-ui-adapter Frontend: From 2a5912393731109b44580852c06413529d8c1ca2 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Tue, 23 Jun 2026 14:56:12 -0700 Subject: [PATCH 12/19] Update the basics skill --- skills/ai-python-basics/SKILL.md | 56 +++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/skills/ai-python-basics/SKILL.md b/skills/ai-python-basics/SKILL.md index 094e704a..999f937b 100644 --- a/skills/ai-python-basics/SKILL.md +++ b/skills/ai-python-basics/SKILL.md @@ -11,6 +11,14 @@ Install with `uv add ai`. Use `import ai`. +Core pieces: + +- `Model` selects the provider and model. +- Messages are typed Python objects. +- `ai.stream` makes one model call and returns one assistant message. +- `ai.Agent` wraps `ai.stream` in a loop that executes Python tools and manages + history. + Use gateway model IDs unless you need a direct provider: ```python @@ -33,38 +41,54 @@ messages = [ ] ``` -For one model call, use `ai.stream`: +Minimal agent happy path: ```python -async with ai.stream(model, messages) as stream: - async for event in stream: - if isinstance(event, ai.events.TextDelta): - print(event.chunk, end="", flush=True) +import asyncio -answer = stream.output -messages.append(stream.message) -``` +import ai -For Python tools, use an agent: -```python @ai.tool async def get_weather(city: str) -> str: """Get the weather for a city.""" return "Sunny" -agent = ai.agent(tools=[get_weather]) -async with agent.run(model, messages) as run: - async for event in run: +async def main() -> None: + model = ai.get_model("anthropic/claude-sonnet-4") + agent = ai.agent(tools=[get_weather]) + messages = [ + ai.system_message("Use tools when useful."), + ai.user_message("What is the weather in San Francisco?"), + ] + + async with agent.run(model, messages) as run: + async for event in run: + if isinstance(event, ai.events.TextDelta): + print(event.chunk, end="", flush=True) + + answer = run.output + history = run.messages + + +if __name__ == "__main__": + asyncio.run(main()) +``` + +For one model call without Python tool execution, use `ai.stream`: + +```python +async with ai.stream(model, messages) as stream: + async for event in stream: if isinstance(event, ai.events.TextDelta): print(event.chunk, end="", flush=True) -answer = run.output -history = run.messages +answer = stream.output +messages.append(stream.message) ``` Use `ai-python-custom-loop`, `ai-python-subagents`, `ai-python-streaming-tools`, `ai-python-serverless-execution`, -`ai-python-durable-execution`, `ai-python-ai-sdk-ui-adapter`, and +`ai-python-durable-execution`, `ai-python-ui-adapter`, and `ai-python-custom-provider` for advanced patterns. From 72bf732e7baef512b929f003d948a05214dd15ac Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Wed, 24 Jun 2026 19:52:00 -0700 Subject: [PATCH 13/19] Update and restructure everything in basics --- docs/ai-python/content/docs/basics/agents.mdx | 51 ++------- .../content/docs/basics/ai-sdk-ui.mdx | 88 +++++++------- .../content/docs/basics/custom-loops.mdx | 107 +++++------------- .../content/docs/basics/human-in-the-loop.mdx | 94 +++++++-------- .../docs/basics/messages-and-events.mdx | 77 +++++++------ .../content/docs/basics/providers.mdx | 24 ++-- .../content/docs/basics/streaming.mdx | 54 ++++----- .../docs/basics/subagents-and-multi-agent.mdx | 44 ++----- docs/ai-python/content/docs/basics/tools.mdx | 59 ++++------ docs/ai-python/content/docs/index.mdx | 2 +- 10 files changed, 219 insertions(+), 381 deletions(-) diff --git a/docs/ai-python/content/docs/basics/agents.mdx b/docs/ai-python/content/docs/basics/agents.mdx index 904851d7..85ef7b9d 100644 --- a/docs/ai-python/content/docs/basics/agents.mdx +++ b/docs/ai-python/content/docs/basics/agents.mdx @@ -6,8 +6,7 @@ summary: Create agents, run the default loop, inspect results, and understand mu --- Use an agent when the model needs to call tools and continue with the tool -results. The default agent loop is built from the same primitives you can use -directly: `ai.stream`, `ToolRunner`, messages, and events. +results. ## Create an agent @@ -15,21 +14,8 @@ An agent wraps `ai.stream` in a loop. It streams model output, executes requeste tools, appends tool results to history, and repeats until the model returns a final assistant message. -```python -agent = ai.agent(tools=[contact_mothership]) - -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) -``` - -Use `ai.agent` for the default loop. Subclass `ai.Agent` and override -`async def loop()` when you need to change control flow. - -## Run the default loop - -Create an agent with tools, then call `agent.run`: +Subclass `ai.Agent` and override `async def loop()` when you need to change +control flow. ```python title="agent_loop.py" import asyncio @@ -64,17 +50,19 @@ if __name__ == "__main__": asyncio.run(main()) ``` -## Inspect the run result - The stream yields model events and agent events. After the run finishes, `stream.messages` contains the updated history, and `stream.output` contains the final assistant output. +Unline `ai.stream`, every `agent.run` can produce multiple messages alternating +between `"user"`/`"tool"` and `"assistant"`, representing turns in the LLM request +and response cycle. + ## Understand multi-turn behavior -Each loop turn streams one assistant message. If the message contains tool -calls, the agent executes them, appends one tool-result message, and starts the -next model turn. +Each loop turn has one `ai.stream` that produces one assistant message. If the +message contains tool calls, the agent executes them, appends one tool-result +message, and starts the next model turn. ```python async with agent.run(model, messages) as stream: @@ -118,22 +106,3 @@ async with agent.run( forecast = stream.output print(forecast.eta) ``` - -## Choose agents or direct streaming - -Use `ai.stream` when you want one model response and you will handle any tool -calls yourself. Use an agent when the SDK should execute Python tools, append -tool results, and keep looping until the assistant returns a final answer. - -```python -# Direct stream: inspect tool calls yourself. -async with ai.stream(model, messages, tools=[get_weather.tool]) as stream: - async for event in stream: - ... - -# Agent: execute registered tools. -agent = ai.agent(tools=[get_weather]) -async with agent.run(model, messages) as stream: - async for event in stream: - ... -``` diff --git a/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx b/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx index 25b195f2..ef9843b2 100644 --- a/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx +++ b/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx @@ -5,42 +5,18 @@ type: guide summary: Parse UI messages, apply approvals, stream SSE responses, set headers, and rebuild UI history. --- -The AI SDK UI adapter converts between AI SDK UI messages and the Python -runtime message/event types. +This adapter provides integration with the UI part of the sister AI SDK +in TypeScript. -## Parse UI messages +AI SDK UI provides `useChat`, which handles streaming complexity on the +client side, such as collecting message chunks and optimistically updating +the UI when the user submits a new message. -Accept `UIMessage` values from an AI SDK UI client, then convert them to -runtime messages: +The AI SDK UI's data model is significantly different from the AI SDK for +Python's, which is why you need to convert events and messages back and forth +using the adapter. -```python -class ChatRequest(pydantic.BaseModel): - messages: list[ai.agents.ui.ai_sdk.UIMessage] - - -@app.post("/chat") -async def chat(request: ChatRequest): - messages, approvals = ai.agents.ui.ai_sdk.to_messages(request.messages) -``` - -`to_messages` also extracts approval responses from tool parts. - -## Apply approval responses - -Register extracted approvals before resuming the agent: - -```python -messages, approvals = ai.agents.ui.ai_sdk.to_messages(request.messages) -ai.agents.ui.ai_sdk.apply_approvals(approvals) - -async with chat_agent.run(model, messages) as stream: - ... -``` - -The hook registry stores each approval until the matching tool-approval hook -runs. - -## Stream SSE responses +## Outbound streaming and message history Use `to_sse` to convert agent events to AI SDK UI stream chunks: @@ -61,18 +37,6 @@ async def chat(request: ChatRequest) -> fastapi.responses.StreamingResponse: ) ``` -## Set response headers - -Return the adapter headers on every streamed response: - -```python -headers = ai.agents.ui.ai_sdk.UI_MESSAGE_STREAM_HEADERS -``` - -These headers identify the response as an AI SDK UI message stream. - -## Rebuild UI history - Convert stored runtime messages back to AI SDK UI messages for history endpoints: @@ -86,8 +50,6 @@ async def get_chat(session_id: str): The adapter groups assistant, tool, and internal hook messages into one assistant UI message. -## Support streaming tool output - Generator tools and subagents emit `PartialToolCallResult` events. The UI adapter folds those partial values into the corresponding tool output: @@ -102,3 +64,35 @@ async def draft_mothership_reply(topic: str) -> ai.StreamingTextTool: For subagents, `ai.SubAgentTool` streams nested events and stores the nested assistant message as the tool output. + +## Inbound message updates + +Accept `UIMessage` values from an AI SDK UI client, then convert them to +runtime messages: + +```python +class ChatRequest(pydantic.BaseModel): + messages: list[ai.agents.ui.ai_sdk.UIMessage] + + +@app.post("/chat") +async def chat(request: ChatRequest): + messages, approvals = ai.agents.ui.ai_sdk.to_messages(request.messages) +``` + +`to_messages` also extracts approval responses from tool parts. + +## Tool approvals + +Register extracted approvals before resuming the agent: + +```python +messages, approvals = ai.agents.ui.ai_sdk.to_messages(request.messages) +ai.agents.ui.ai_sdk.apply_approvals(approvals) + +async with chat_agent.run(model, messages) as stream: + ... +``` + +The hook registry stores each approval until the matching tool-approval hook +runs. diff --git a/docs/ai-python/content/docs/basics/custom-loops.mdx b/docs/ai-python/content/docs/basics/custom-loops.mdx index 4ad8ac65..235a26af 100644 --- a/docs/ai-python/content/docs/basics/custom-loops.mdx +++ b/docs/ai-python/content/docs/basics/custom-loops.mdx @@ -5,104 +5,51 @@ type: guide summary: Override the agent loop to customize scheduling, routing, history updates, logging, and tool execution. --- -Custom loops use the same primitives as the default loop. Override `Agent.loop` -when you need to change scheduling, logging, routing, or persistence. +Override `loop` when you need custom tool dispatch, logging, durability, or +branching. While the SDK is doing it's best to define the loop as a Python +async generator, it's still using *some* special components. Be sure to reuse +those to retain certain framework-controlled behavior. -## When to customize the loop +## Explore the standard loop shape -Override `loop` when you need custom scheduling, logging, durability, or -branching. Keep the same pattern when you still want SDK-managed history and -tool resolution. - -## Use the standard loop shape - -The default loop keeps running while the last message needs more work. On each +The default loop keeps running while there is more work to do. On each turn, it streams the model response and schedules tool calls: ```python class CustomAgent(ai.Agent): - async def loop(self, context: ai.Context): + # ai.Context keeps track of message history, run inputs, and other per-run data + async def loop(self, context: ai.Context) -> AsyncGenerator[ai.Event]: while context.keep_running(): + # call ai.stream with whatever model, tools, and messages the user has + # passed to agent.run async with ( ai.stream(context=context) as stream, - ai.ToolRunner() as tool_runner, + # ai.ToolRunner is responsible for concurrent tool scheduling and + # streaming, as well as graceful handling of hook interruptions + ai.ToolRunner() as tool_runner, + ): + # ai.util.merge interleaves two streams together, so the agent + # can fire off tools as they arrive in the stream rather than + # waiting for the model to stop streaming; and also start streaming + # the streaming tools. async for event in ai.util.merge(stream, tool_runner.events()): yield event if isinstance(event, ai.events.ToolEnd): + # context.resolve looks up the Python function for the + # tool name in the model's tool call tool_call = context.resolve(event.tool_call) + # schedule the tool for concurrent execution + # using the tool runner tool_runner.schedule(tool_call) + # add new messages to message history stored in the context. + # this works with internal replay machinery to enable serverless + # execution. context.add(stream.message) context.add(tool_runner.get_tool_message()) ``` -## Resolve and schedule tool calls - -`ToolEnd` means the model finished emitting a tool call. Resolve it through the -context, then schedule it with `ToolRunner`: - -```python -if isinstance(event, ai.events.ToolEnd): - tool_call = context.resolve(event.tool_call) - tool_runner.schedule(tool_call) -``` - -`context.resolve` validates that the agent has an executable tool registered -for the model's `tool_name`. - -## Add messages to history - -After a stream turn finishes, add the assistant message and any tool-result -message: - -```python -context.add(stream.message) -context.add(tool_runner.get_tool_message()) -``` - -`context.add` skips replayed assistant messages, so resume flows can call it -without duplicating history. - -## Run tools sequentially - -`ToolRunner.schedule` runs active tools concurrently. To run tools one at a -time, collect the calls during the model stream, then execute them in order: - -```python -pending: list[ai.ToolCall] = [] - -async for event in stream: - yield event - if isinstance(event, ai.events.ToolEnd): - pending.append(context.resolve(event.tool_call)) - -for tool_call in pending: - result = await tool_call() - yield result - tool_runner.add_result(result) -``` - -This keeps the same tool-message aggregation path while preserving execution -order. - -## Add logging or routing - -Custom loops can inspect events before yielding or scheduling: - -```python -if isinstance(event, ai.events.ToolEnd): - call = event.tool_call - print(f"tool: {call.tool_name}({call.tool_args})") - tool_runner.schedule(context.resolve(call)) -``` - -You can also route specific tools through custom wrappers: - -```python -if tool_call.name == "contact_mothership": - tool_runner.schedule(ai.agents.GatedToolCall(tool_call)) -else: - tool_runner.schedule(tool_call) -``` +You can modify most of the loop and extend `CustomAgent` to fit your application's needs, +and the SDK will keep working as long as the loop is still an async generator of events. diff --git a/docs/ai-python/content/docs/basics/human-in-the-loop.mdx b/docs/ai-python/content/docs/basics/human-in-the-loop.mdx index 85fe158c..58a549f8 100644 --- a/docs/ai-python/content/docs/basics/human-in-the-loop.mdx +++ b/docs/ai-python/content/docs/basics/human-in-the-loop.mdx @@ -5,8 +5,9 @@ type: guide summary: Use tool approvals, manual hooks, cancellation, denial, and serverless resume flows. --- -Hooks let an agent suspend while your application waits for a decision. Tool -approvals are the built-in hook workflow. +Tool approval in the SDK is a high-level API built on top of hooks. Hooks +suspend the loop until your application resolves them externally with some +payload. ## Require tool approval @@ -22,18 +23,6 @@ async def notify_mothership(message: str) -> str: When the model calls the tool, the agent emits a hook event. Resolve it with `ai.resolve_hook`: -```python -ai.resolve_hook( - "approve_tool_call_id_here", - ai.tools.ToolApproval(granted=True, reason="approved"), -) -``` - -## Resolve approvals in a live app - -Listen for pending hook events and resolve the matching hook from another task, -request handler, or UI callback: - ```python async with agent.run(model, messages) as stream: async for event in stream: @@ -50,68 +39,67 @@ ai.resolve_hook( ) ``` -## Build manual hooks - -Hooks let an agent suspend while your application waits for external input, -such as a human approval: +Return a denial by resolving the hook with `granted=False`: ```python -approval = await ai.hook( - "approve_contact_mothership", - payload=ai.tools.ToolApproval, - metadata={"tool": "contact_mothership"}, +ai.resolve_hook( + "approve_tool_call_id_here", + ai.tools.ToolApproval(granted=False, reason="not allowed"), ) ``` -Resolve the hook from another part of your application: +Cancel a live hook when the waiting workflow should stop: ```python -ai.resolve_hook( - "approve_contact_mothership", - {"granted": True, "reason": "approved"}, -) +await ai.cancel_hook("approve_tool_call_id_here", reason="client disconnected") ``` -Use hooks when a tool or workflow needs a decision that cannot happen inside the -model call. +## Build custom hooks -## Deny or cancel work - -Return a denial by resolving the hook with `granted=False`: +Use `ai.hook` to define your own custom hooks to suspend execution +and deliver external information into the loop: ```python -ai.resolve_hook( - "approve_tool_call_id_here", - ai.tools.ToolApproval(granted=False, reason="not allowed"), +class CustomPayload(pydantic.BaseModel): + foo: int + +approval = await ai.hook( + "some_hook", + payload=CustomPayload, + metadata={"kek": "pek"}, ) ``` -Cancel a live hook when the waiting workflow should stop: +Resolve the hook from another part of your application: ```python -await ai.cancel_hook("approve_tool_call_id_here", reason="client disconnected") +ai.resolve_hook( + "some_hook", + {"foo": 999}, +) ``` ## Resume in serverless flows -For serverless or resumable flows, keep the pending hook part from the emitted -event, call `ai.abort_pending_hook(hook_part)` to end the current run, persist -`stream.messages`, and call `ai.resolve_hook` before replaying the agent. +Serverless setups can't suspend on `await` in the same way as long-running +servers. For that reason, the SDK providers an alternative way for handling +hook resolutions. -## Persist approval state +Using the serverless flow only requires you to update the `agent.run` callsite +(e.g. your serverless endpoint code). -Persist `stream.messages` when a run stops on a pending hook. When the user -responds, restore those messages, register the resolution, and run the same -agent again: +> provide example of abort_pending_hook -```python -messages, approvals = ai.agents.ui.ai_sdk.to_messages(ui_messages) -ai.agents.ui.ai_sdk.apply_approvals(approvals) +When handling the hook event, call `abort_pending_hook` to interrupt the loop +and surface your tool approvals (or custom hook-related work) to the client. -async with agent.run(model, messages) as stream: - async for event in stream: - ... -``` +The `ToolRunner` will handle multiple concurrent aborts by waiting for all +scheduled tasks to complete or get aborted. That way you can run approval-gated +tools on serverless concurrently. -The agent marks interrupted assistant turns for replay, so the resumed run can -dispatch the original tool call without asking the model to emit it again. +Once the client has gathered payloads for all hooks, it will re-enter via the +same endpoint, which will then pre-register hook resolutions *before* calling +`agent.run` again. The loop will replay results of LLM calls and tool results +from the first run without redoing non-deterministic and duplicating side-effects. +When it hits the hook for which it has a pre-registered resolution, it will +continue through without suspending. diff --git a/docs/ai-python/content/docs/basics/messages-and-events.mdx b/docs/ai-python/content/docs/basics/messages-and-events.mdx index be203dde..565321c9 100644 --- a/docs/ai-python/content/docs/basics/messages-and-events.mdx +++ b/docs/ai-python/content/docs/basics/messages-and-events.mdx @@ -5,13 +5,22 @@ type: guide summary: Construct messages, add files, read outputs, serialize history, handle events, and track usage. --- -Messages are Pydantic models. Events are also Pydantic models, so you can -pattern-match, serialize, and persist them when your app needs that. +Messages and events make up AI SDK for Python's data model. Events are used +to communicate transient streaming state, while messages are used to accumulate, +store, and pass around non-streaming state. + +Both are Pydantic models, so you can pattern-match, serialize, and persist them +when your app needs that. ## Build messages -Messages are the conversation history you send to the model. Use message -builders for the common roles: +Messages store the conversation history you send to the model. Each message +represents a turn in the conversation and is made up of `Part`'s: + +> insert flowchart of what the message is made out of + +Use builtin factory functions to quickly construct frequently used shapes of +messages: ```python messages = [ @@ -20,10 +29,17 @@ messages = [ ] ``` +Messages round-trip through Pydantic: + +```python +encoded = [message.model_dump(mode="json") for message in stream.messages] +restored = [ai.messages.Message.model_validate(item) for item in encoded] +``` + ## Add files and multimodal input -Each message contains parts. Strings become text parts. File parts let you send -images, audio, or documents when the provider supports them. +File parts let you send images, audio, or documents when the provider supports +them. ```python message = ai.user_message( @@ -32,7 +48,7 @@ message = ai.user_message( ) ``` -## Read message output +## Handle message output Assistant messages expose common part collections: @@ -45,42 +61,17 @@ print(message.tool_calls) print(message.files) ``` -Use `get_output` for a final assistant message. With no type, it returns text. -With a Pydantic model, it validates the text as JSON: +When working with structured outputs, use `get_output` to get the final assistant +message wrapped into the provided Pydantic model. ```python -answer = message.get_output() forecast = message.get_output(Forecast) ``` -## Serialize and restore messages - -Messages round-trip through Pydantic JSON: - -```python -encoded = [message.model_dump(mode="json") for message in stream.messages] -restored = [ai.messages.Message.model_validate(item) for item in encoded] -``` - -Persist `stream.messages` after an agent run when you want to continue the -conversation later. - -Before provider calls, the SDK prepares message history by stripping internal -messages, removing non-model parts, repairing invalid tool args to `{}`, and -inserting error results for missing tool calls when possible. Use strict -validation in tests or import pipelines: - -```python -from ai.types import integrity - - -integrity.prepare_messages(messages, mode="strict") -``` - ## Handle stream events -Streams and agents both yield event objects from `ai.events`. Most applications -start by handling `TextDelta`: +Streams and agents both yield event objects from `ai.events`. Applications can handle +each kind of event as they see fit: ```python if isinstance(event, ai.events.TextDelta): @@ -119,3 +110,17 @@ async with ai.stream(model, messages) as stream: print(stream.usage) print(stream.message.usage) ``` + +## Validate message history + +Before provider calls, the SDK prepares message history by stripping internal +messages, removing non-model parts, repairing invalid tool args to `{}`, and +inserting error results for missing tool calls when possible. Use strict +validation in tests or import pipelines: + +```python +from ai.types import integrity + + +integrity.prepare_messages(messages, mode="strict") +``` diff --git a/docs/ai-python/content/docs/basics/providers.mdx b/docs/ai-python/content/docs/basics/providers.mdx index ee432784..7ee4898b 100644 --- a/docs/ai-python/content/docs/basics/providers.mdx +++ b/docs/ai-python/content/docs/basics/providers.mdx @@ -10,9 +10,8 @@ Models are lightweight references that point at a provider. ## Create a model -A model is a lightweight reference to a provider model. Create one with -`ai.get_model`. If you omit the provider prefix, the model routes through AI -Gateway: +Use `ai.get_model` to create a model. If you omit the provider prefix, the model +will use AI Gateway as a provider: ```python model = ai.get_model("anthropic/claude-sonnet-4") @@ -36,22 +35,18 @@ model = ai.get_model("openai:gpt-5") ## Configure credentials -The default gateway route reads `AI_GATEWAY_API_KEY`: +Providers read their provider-specific keys: ```bash title="Terminal" export AI_GATEWAY_API_KEY="your_access_token_here" -``` - -Direct providers read their provider-specific keys: - -```bash title="Terminal" export OPENAI_API_KEY="your_access_token_here" export ANTHROPIC_API_KEY="your_access_token_here" ``` -## Override base URLs +## Use an explicit provider -Pass `base_url` when you create an explicit provider: +If your application requires a provider with custom configuration, +use `get_provider` to get a `Provider` instance: ```python provider = ai.get_provider( @@ -63,12 +58,7 @@ provider = ai.get_provider( model = ai.Model("local-model", provider=provider) ``` -OpenAI and Anthropic direct providers also read `OPENAI_BASE_URL` and -`ANTHROPIC_BASE_URL`. - -## Use an explicit client - -Pass an upstream client when your app owns transport configuration: +You can pass an upstream client to the provider: ```python import httpx diff --git a/docs/ai-python/content/docs/basics/streaming.mdx b/docs/ai-python/content/docs/basics/streaming.mdx index e49da74f..6a3a7c77 100644 --- a/docs/ai-python/content/docs/basics/streaming.mdx +++ b/docs/ai-python/content/docs/basics/streaming.mdx @@ -29,13 +29,15 @@ async def main() -> None: async for event in stream: if isinstance(event, ai.events.TextDelta): print(event.chunk, end="", flush=True) - print() if __name__ == "__main__": asyncio.run(main()) ``` +One call to `ai.stream` produces one `ai.Message`. + + ## Read the final message The stream aggregates events into a final assistant message: @@ -43,17 +45,13 @@ The stream aggregates events into a final assistant message: ```python async with ai.stream(model, messages) as stream: async for event in stream: - if isinstance(event, ai.events.TextDelta): - print(event.chunk, end="", flush=True) + pass message = stream.message # Final message text = stream.text # Unwrapped text from the final message usage = stream.usage ``` -Use `stream.message` when you need to append the assistant turn to your own -history. Use `stream.text` when you only need the final text. - If a provider stream ends before its finish event, iteration raises `ai.errors.ProviderIncompleteResponseError`. The partial message is still available on `stream.message`. @@ -65,8 +63,7 @@ message. ## Use structured output -Pass a Pydantic model as `output_type` when you want the final text parsed as -JSON: +Pass a Pydantic model as `output_type` when you want to use structured outputs: ```python title="structured_output.py" import asyncio @@ -102,34 +99,27 @@ if __name__ == "__main__": `stream.output` returns text by default. When you pass `output_type`, it returns an instance of that Pydantic model after the stream finishes. -## Pass tool schemas without an agent +## Pass tools -`ai.stream` does not execute function tools. Use it when you want to inspect -tool calls and manage execution yourself. Use an agent when you want the SDK to +`ai.stream` accepts a list of `ai.Tool`, however, it does not have any +framework-side tool execution machinery. Use an agent when you want the SDK to execute requested tools and continue the loop. -## Use provider-executed tools - -Provider-executed tools run inside the provider or gateway. They appear in the +Provider-executed tools run on provider's side. They appear in the stream as built-in tool events and do not need a Python function: ```python -tools = [ai.providers.anthropic.tools.web_search(max_uses=3)] +tools = [ai.providers.ai_gateway.tools.perplexity_search(max_results=5)] async with ai.stream(model, messages, tools=tools) as stream: async for event in stream: - if isinstance(event, ai.events.BuiltinToolEnd): - print(event.tool_call.tool_name) - elif isinstance(event, ai.events.BuiltinToolResult): - print(event.result.result) - elif isinstance(event, ai.events.TextDelta): - print(event.chunk, end="", flush=True) -``` - -When you route through AI Gateway, you can also pass gateway tools: - -```python -tools = [ai.providers.ai_gateway.tools.perplexity_search(max_results=5)] + match event: + case ai.events.BuiltinToolEnd(tool_call): + print(tool_call.tool_name) + case ai.events.BuiltinToolResult(result): + print(result.result) + case ai.events.TextDelta(chunk): + print(chunk, end="", flush=True) ``` ## Handle files from a stream @@ -143,8 +133,8 @@ async with ai.stream(model, messages) as stream: if isinstance(event, ai.events.FileEvent): print(event.media_type, event.filename) -for file in stream.message.files: - print(file.media_type) +for f in stream.message.files: + print(f.media_type) ``` Use `ai.generate` for dedicated image and video models: @@ -158,9 +148,3 @@ result = await ai.generate( image = result.images[0] ``` - -## Replay an existing assistant turn - -When the last message has `replay=True`, `ai.stream` does not call the -provider. It emits replay events from the existing assistant message so resume -flows can dispatch the same tool calls again. diff --git a/docs/ai-python/content/docs/basics/subagents-and-multi-agent.mdx b/docs/ai-python/content/docs/basics/subagents-and-multi-agent.mdx index 854bf535..fff4b685 100644 --- a/docs/ai-python/content/docs/basics/subagents-and-multi-agent.mdx +++ b/docs/ai-python/content/docs/basics/subagents-and-multi-agent.mdx @@ -1,8 +1,8 @@ --- -title: Subagents and Multi-Agent +title: Subagents description: Compose agents and stream nested agent output. type: guide -summary: Run subagents as tools, stream nested output, run agents in parallel, route labels, and fan in results. +summary: Run subagents as tools, stream nested output. --- Subagents are regular agents used inside tools or custom loops. Their events @@ -10,7 +10,8 @@ can stream through the parent run while their final text becomes model input. ## Run a subagent as a tool -Use `ai.SubAgentTool` when a tool should stream events from another agent: +In order for the SDK to correctly handle subagent's outputs, you need to +annotate the tool's output type with `ai.SubAgentTool`: ```python mothership_model = ai.get_model("anthropic/claude-sonnet-4") @@ -30,10 +31,9 @@ async def ask_mothership(topic: str) -> ai.SubAgentTool: yield event ``` -The parent stream receives the sub-agent events. The parent model sees the final -assistant text from the sub-agent as the tool result. - -## Stream subagent output +This allows the framework to stream partial outputs, keep nested chat history +in `ai.MessageBundle` (which is a marker type for `list[ai.Message]`), and +pass the final output to the parent agent. `ai.SubAgentTool` declares the aggregator for nested agent events. The parent consumer receives each nested event as `PartialToolCallResult.value`: @@ -48,7 +48,7 @@ async with orchestrator.run(model, messages) as stream: print(event.chunk, end="", flush=True) ``` -## Run agents in parallel +## Run streams in parallel Use `ai.yield_from` inside a custom loop to run branches concurrently and forward their events: @@ -72,10 +72,8 @@ async with ( ) ``` -## Route labeled output - -`yield_from` wraps forwarded events in `PartialToolCallResult` with the label -you pass: +`yield_from` wraps events in `PartialToolCallResult` with the label +you pass, and forwards them outside via the internal runtime queue: ```python if isinstance(event, ai.events.PartialToolCallResult): @@ -84,25 +82,3 @@ if isinstance(event, ai.events.PartialToolCallResult): elif event.label == "data_centers": route_to_data_center_panel(event.value) ``` - -## Fan in results - -After parallel branches finish, send their returned text into a final summary -turn: - -```python -combined = ( - f"Mothership: {mothership_text}\n" - f"Data centers: {data_center_text}" -) - -async with summary_agent.run( - model, - [ - ai.system_message("Summarize the branch reports."), - ai.user_message(combined), - ], -) as summary: - async for event in summary: - yield event -``` diff --git a/docs/ai-python/content/docs/basics/tools.mdx b/docs/ai-python/content/docs/basics/tools.mdx index 1eccf96d..5a734a98 100644 --- a/docs/ai-python/content/docs/basics/tools.mdx +++ b/docs/ai-python/content/docs/basics/tools.mdx @@ -5,10 +5,10 @@ type: guide summary: Define function tools, design schemas, handle tool errors, use schema-only tools, provider tools, and MCP tools. --- -Tools can be schema-only declarations for direct streaming, executable Python -functions for agents, or provider-executed tools that run outside your process. +AI SDK for Python supports multiple types of tools, inlcuding function tools +defined in code using `@ai.tool`, as well as built-in provider-side tools. -## Define function tools +## Declare function tools Decorate an async function with `@ai.tool`: @@ -25,35 +25,9 @@ async def contact_mothership(query: str) -> str: The tool name comes from the function name. The model receives the function parameters as a JSON schema and the docstring as the tool description. -## Design tool schemas - -The function signature becomes the tool schema. The docstring becomes the tool -description the model sees. - -```python -@ai.tool -async def scan_sector(sector: str, depth: int = 1) -> str: - """Scan a mothership sector at the requested depth.""" - return f"{sector}: clear at depth {depth}" -``` - -The model receives `sector` as a required string and `depth` as an optional -integer with a default. - -## Validate arguments - -Tool arguments validate through the generated Pydantic model before your -function runs: - -```python -@ai.tool -async def set_alert_level(level: int) -> str: - """Set the mothership alert level.""" - return f"Alert level set to {level}" -``` - -If the model sends `{"level": "high"}`, validation fails and the agent returns -an error tool result instead of calling the function. +Function tools will only be automatically executed by the SDK when used +in the context of the agent. Provider-side tools will always get executed +by the provider, even when passed to `ai.stream`. ## Handle tool errors @@ -71,11 +45,16 @@ async with agent.run(model, messages) as stream: The original exception is available on `event.exception` for logging. -## Stream tool output +## Declare tools that stream output + +AI SDK for Python supports tools that are async-generators. You might want to +use those when your tools need to return partial output, e.g. when wrapping +subagents. -Async-generator tools can yield partial output while they run. The agent emits -`PartialToolCallResult` events for those values, then sends the aggregated -result back to the model on the next turn. +Streaming tools require a special return type in order to get correctly +handled by the SDK, since partial outputs need to be accumulated, passed though, +and the LLM needs to receive an accumulated result. That return type must be +a subtype of `ai.Aggregator`. Use `ai.StreamingTextTool` when yielded strings should concatenate into the tool result: @@ -92,7 +71,13 @@ async def draft_reply(topic: str) -> ai.StreamingTextTool: Use `ai.StreamingStatusTool[T]` when intermediate yields are progress updates and the last yielded value is the final result. -## Use schema-only tools +The agent emits `PartialToolCallResult` events for those values, then sends +the aggregated result back to the model on the next turn. + +## Understand tool anatomy + +> provide a diagram of ai.Tool, AgentTool, provider tools, etc. +> mention that tools contain spec and params, and which tools have which Pass `ai.Tool` objects directly to `ai.stream` when you want the model to emit tool calls but you do not want the SDK to execute them: diff --git a/docs/ai-python/content/docs/index.mdx b/docs/ai-python/content/docs/index.mdx index dbadf7c7..68717fd4 100644 --- a/docs/ai-python/content/docs/index.mdx +++ b/docs/ai-python/content/docs/index.mdx @@ -44,7 +44,7 @@ async def contact_mothership(query: str) -> str: async def main() -> None: model = ai.get_model("anthropic/claude-sonnet-4") - agent = ai.agent(tools=[contact_mothership]) + agent = ai.Agent(tools=[contact_mothership]) messages = [ ai.system_message( From b51190ab50ea475bee4253db819ca0969f7d7fa5 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Thu, 25 Jun 2026 10:31:57 -0700 Subject: [PATCH 14/19] Outline a durable execution section --- .../content/docs/basics/durable-execution.mdx | 39 +++++++++++++++++++ docs/ai-python/content/docs/basics/meta.json | 1 + 2 files changed, 40 insertions(+) create mode 100644 docs/ai-python/content/docs/basics/durable-execution.mdx diff --git a/docs/ai-python/content/docs/basics/durable-execution.mdx b/docs/ai-python/content/docs/basics/durable-execution.mdx new file mode 100644 index 00000000..1367a689 --- /dev/null +++ b/docs/ai-python/content/docs/basics/durable-execution.mdx @@ -0,0 +1,39 @@ +--- +title: Durable Execution +description: Run agent loops inside durable workflow systems. +type: guide +summary: Build custom loops with durable model calls, serialized messages, tool dispatch, and external resume points. +--- + +Use durable execution when a run must survive process restarts, worker moves, or +long waits. + +The SDK currently does not provide a built-in durability solution, so you will +have to create a custom loop (or copy one from the example). This section will +use terminology and the general shape of Vercel Workflows for simplicity; same +approach can be applied to other durable execution frameworks (e.g. Temporal). + +## Why durability is different + +The core idea of durable execution is to make your code deterministic and +replayable by isolating side-effects and non-deterministic work inside *steps* +(or *activities*), i.e. functions that accept JSON inputs and produce JSON +outputs. Every successful step gets recorded in the event log. The rest of the +code turns into a deterministic orchestration *workflow*, that can replay +results of completed steps from the event log as many times as necessary. + +When applied to the agent, this idea turns it into a *workflow*, with `ai.stream` +and tool calls wrapped in *steps*. The SDK exposes all the necessary primitives +and ensures that their inputs and outputs can roundtrip through JSON. + +Another important caveat to durabile execution is that it normally does not +support async generators. Depending on the framework, additional work may be +required for your streaming setup. + +## Example: Vercel Workflows + +> insert a breakdown of a simplified seal-like loop here + +> explain that ai.stream is wrapped, tools are wrapped, ai.merge is not necessary, +> and the hook shape is serverless because that allows the workflow to not take +> up resources while the approval is being acquired outside of the workflow. diff --git a/docs/ai-python/content/docs/basics/meta.json b/docs/ai-python/content/docs/basics/meta.json index 0dd6f54d..494f0fb1 100644 --- a/docs/ai-python/content/docs/basics/meta.json +++ b/docs/ai-python/content/docs/basics/meta.json @@ -8,6 +8,7 @@ "tools", "agents", "custom-loops", + "durable-execution", "subagents-and-multi-agent", "human-in-the-loop", "ai-sdk-ui" From 378dfa0cc423eae513a46a7a954f6442dd9cf771 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Thu, 25 Jun 2026 11:18:49 -0700 Subject: [PATCH 15/19] Insert code examples for serverless hooks and durability --- .../content/docs/basics/durable-execution.mdx | 89 ++++++++++++++++--- .../content/docs/basics/human-in-the-loop.mdx | 28 ++++-- 2 files changed, 102 insertions(+), 15 deletions(-) diff --git a/docs/ai-python/content/docs/basics/durable-execution.mdx b/docs/ai-python/content/docs/basics/durable-execution.mdx index 1367a689..2897a6ff 100644 --- a/docs/ai-python/content/docs/basics/durable-execution.mdx +++ b/docs/ai-python/content/docs/basics/durable-execution.mdx @@ -6,7 +6,7 @@ summary: Build custom loops with durable model calls, serialized messages, tool --- Use durable execution when a run must survive process restarts, worker moves, or -long waits. +long waits. The SDK currently does not provide a built-in durability solution, so you will have to create a custom loop (or copy one from the example). This section will @@ -15,25 +15,94 @@ approach can be applied to other durable execution frameworks (e.g. Temporal). ## Why durability is different -The core idea of durable execution is to make your code deterministic and +The core idea of durable execution is to make your code deterministic and replayable by isolating side-effects and non-deterministic work inside *steps* (or *activities*), i.e. functions that accept JSON inputs and produce JSON -outputs. Every successful step gets recorded in the event log. The rest of the +outputs. Every successful step gets recorded in the event log. The rest of the code turns into a deterministic orchestration *workflow*, that can replay results of completed steps from the event log as many times as necessary. When applied to the agent, this idea turns it into a *workflow*, with `ai.stream` -and tool calls wrapped in *steps*. The SDK exposes all the necessary primitives -and ensures that their inputs and outputs can roundtrip through JSON. +and tool calls wrapped in *steps*. The SDK exposes all the necessary primitives +and ensures that their inputs and outputs can round-trip through JSON. -Another important caveat to durabile execution is that it normally does not +Another important caveat to durable execution is that it normally does not support async generators. Depending on the framework, additional work may be required for your streaming setup. ## Example: Vercel Workflows -> insert a breakdown of a simplified seal-like loop here +Wrap the model call in a step that returns the final assistant `Message`, +and wrap tools in steps before decorating them with `@ai.tool`. -> explain that ai.stream is wrapped, tools are wrapped, ai.merge is not necessary, -> and the hook shape is serverless because that allows the workflow to not take -> up resources while the approval is being acquired outside of the workflow. +```python +@workflow.step +async def llm_step( + model_data: dict[str, object], + messages_data: list[dict[str, object]], + tools_data: list[dict[str, object]], +) -> dict[str, object]: + model = ai.Model.model_validate(model_data) + messages = [ + ai.messages.Message.model_validate(message) + for message in messages_data + ] + tools = [ai.Tool.model_validate(tool) for tool in tools_data] + + async with ai.stream(model, messages, tools=tools) as stream: + async for _event in stream: + pass + + return stream.message.model_dump(mode="json") + + +@ai.tool +@workflow.step +async def ask_mothership(question: str) -> str: + """Ask the mothership for a status update.""" + response = await mothership_client.ask(question) + return response.summary +``` + +Then use a custom loop that calls the model step, schedules tool work, and +stores the resulting messages: + +```python +class DurableAgent(ai.Agent): + async def loop(self, context: ai.Context): + while context.keep_running(): + result = await llm_step( + context.model.model_dump(mode="json"), + [ + message.model_dump(mode="json") + for message in context.messages + ], + [ + tool.model_dump(mode="json") + for tool in context.tools + ], + ) + + assistant_message = ai.messages.Message.model_validate(result) + context.add(assistant_message) + + async with ai.ToolRunner() as runner: + for tool_call in assistant_message.tool_calls: + runner.schedule(context.resolve(tool_call)) + + async for event in runner.events(): + yield event + + context.add(runner.get_tool_message()) +``` + +This loop does not need `ai.util.merge`, because `llm_step` returns a complete +assistant message before tools are scheduled. In a streaming loop, `merge` +interleaves model events and tool results while the model is still producing +output. + +Consider using the serverless hook flow for approvals. When a pending `HookEvent` +appears, call `ai.abort_pending_hook(event.hook)`, persist `stream.messages`, +and return the approval request to the client. On the next workflow turn, call +`ai.resolve_hook(...)` before `agent.run(...)`. The SDK replays the interrupted +assistant turn and continues when the hook reads the pre-registered resolution. diff --git a/docs/ai-python/content/docs/basics/human-in-the-loop.mdx b/docs/ai-python/content/docs/basics/human-in-the-loop.mdx index 58a549f8..8db7af0e 100644 --- a/docs/ai-python/content/docs/basics/human-in-the-loop.mdx +++ b/docs/ai-python/content/docs/basics/human-in-the-loop.mdx @@ -5,8 +5,8 @@ type: guide summary: Use tool approvals, manual hooks, cancellation, denial, and serverless resume flows. --- -Tool approval in the SDK is a high-level API built on top of hooks. Hooks -suspend the loop until your application resolves them externally with some +Tool approval in the SDK is a high-level API built on top of hooks. Hooks +suspend the loop until your application resolves them externally with some payload. ## Require tool approval @@ -82,13 +82,31 @@ ai.resolve_hook( ## Resume in serverless flows Serverless setups can't suspend on `await` in the same way as long-running -servers. For that reason, the SDK providers an alternative way for handling +servers. For that reason, the SDK provides an alternative way for handling hook resolutions. Using the serverless flow only requires you to update the `agent.run` callsite (e.g. your serverless endpoint code). -> provide example of abort_pending_hook +```python +# pre-register tool approvals +for approval in approvals: + ai.resolve_hook( + approval.hook_id, + ai.tools.ToolApproval.model_validate(approval.data) + ) + +# start (or replay pre-hook part of) a run +async with agent.run(model, messages) as stream: + async for event in stream: + if ( + isinstance(event, ai.events.HookEvent) + and event.hook.status == "pending" + ): + # interrupt the loop + ai.abort_pending_hook(event.hook) + +``` When handling the hook event, call `abort_pending_hook` to interrupt the loop and surface your tool approvals (or custom hook-related work) to the client. @@ -99,7 +117,7 @@ tools on serverless concurrently. Once the client has gathered payloads for all hooks, it will re-enter via the same endpoint, which will then pre-register hook resolutions *before* calling -`agent.run` again. The loop will replay results of LLM calls and tool results +`agent.run` again. The loop will replay results of LLM calls and tool results from the first run without redoing non-deterministic and duplicating side-effects. When it hits the hook for which it has a pre-registered resolution, it will continue through without suspending. From 7335f3b50b5ad20e81f17fdcb25b168cb2f26cd3 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Thu, 25 Jun 2026 12:02:07 -0700 Subject: [PATCH 16/19] Update messages and tools sections --- .../docs/basics/messages-and-events.mdx | 78 ++++++++++++++++--- docs/ai-python/content/docs/basics/tools.mdx | 17 ++-- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/docs/ai-python/content/docs/basics/messages-and-events.mdx b/docs/ai-python/content/docs/basics/messages-and-events.mdx index 565321c9..eabf2ad6 100644 --- a/docs/ai-python/content/docs/basics/messages-and-events.mdx +++ b/docs/ai-python/content/docs/basics/messages-and-events.mdx @@ -6,20 +6,38 @@ summary: Construct messages, add files, read outputs, serialize history, handle --- Messages and events make up AI SDK for Python's data model. Events are used -to communicate transient streaming state, while messages are used to accumulate, +to communicate transient streaming state, while messages are used to accumulate, store, and pass around non-streaming state. -Both are Pydantic models, so you can pattern-match, serialize, and persist them +Both are Pydantic models, so you can pattern-match, serialize, and persist them when your app needs that. ## Build messages Messages store the conversation history you send to the model. Each message -represents a turn in the conversation and is made up of `Part`'s: +represents a turn in the conversation and is made up of `Part` values: -> insert flowchart of what the message is made out of +```python +class Message: + role: "system" | "user" | "assistant" | "tool" | "internal" + parts: list[Part] + ... + + +Part = ( + TextPart + | ReasoningPart + | ToolCallPart + | ToolResultPart + | BuiltinToolCallPart + | BuiltinToolReturnPart + | FilePart + | HookPart +) + +``` -Use builtin factory functions to quickly construct frequently used shapes of +Use built-in factory functions to quickly construct frequently used shapes of messages: ```python @@ -38,7 +56,7 @@ restored = [ai.messages.Message.model_validate(item) for item in encoded] ## Add files and multimodal input -File parts let you send images, audio, or documents when the provider supports +File parts let you send images, audio, or documents when the provider supports them. ```python @@ -61,8 +79,8 @@ print(message.tool_calls) print(message.files) ``` -When working with structured outputs, use `get_output` to get the final assistant -message wrapped into the provided Pydantic model. +When working with structured outputs, use `get_output` to get the final +assistant message wrapped into the provided Pydantic model. ```python forecast = message.get_output(Forecast) @@ -70,8 +88,8 @@ forecast = message.get_output(Forecast) ## Handle stream events -Streams and agents both yield event objects from `ai.events`. Applications can handle -each kind of event as they see fit: +Streams and agents both yield event objects from `ai.events`. Applications can +handle each kind of event as they see fit: ```python if isinstance(event, ai.events.TextDelta): @@ -83,6 +101,43 @@ arrive through `ToolStart`, `ToolDelta`, and `ToolEnd` events. Provider-executed tools use the `BuiltinToolStart`, `BuiltinToolDelta`, `BuiltinToolEnd`, and `BuiltinToolResult` events. +```text +StreamStart + + # text output + TextStart + TextDelta ... + TextEnd + + # reasoning output + ReasoningStart + ReasoningDelta ... + ReasoningEnd + + # host-executed tool call + ToolStart + ToolDelta ... + ToolEnd + + # provider-executed tool call + BuiltinToolStart + BuiltinToolDelta ... + BuiltinToolEnd + BuiltinToolResult + + # generated file + FileEvent + +StreamEnd +``` + +```text +# Agent runs can also interleave: +ToolCallResult # emitted after a Python tool finishes +PartialToolCallResult # emitted while a streaming tool or subagent yields +HookEvent # emitted when a hook is pending, resolved, or cancelled +``` + ```python async with ai.stream(model, messages, tools=tools) as stream: async for event in stream: @@ -96,6 +151,9 @@ Agents can also emit tool results, hook events, and partial tool output. You can ignore events you do not need, or route them into your application UI, observability pipeline, or durable workflow. +Every event also carries a reference to a `ai.Message` that has partial content +accumulated from the stream *so far*. + ## Track usage Providers attach usage to events when they report it. The latest value is also diff --git a/docs/ai-python/content/docs/basics/tools.mdx b/docs/ai-python/content/docs/basics/tools.mdx index 5a734a98..fb283af0 100644 --- a/docs/ai-python/content/docs/basics/tools.mdx +++ b/docs/ai-python/content/docs/basics/tools.mdx @@ -5,7 +5,7 @@ type: guide summary: Define function tools, design schemas, handle tool errors, use schema-only tools, provider tools, and MCP tools. --- -AI SDK for Python supports multiple types of tools, inlcuding function tools +AI SDK for Python supports multiple types of tools, including function tools defined in code using `@ai.tool`, as well as built-in provider-side tools. ## Declare function tools @@ -52,7 +52,7 @@ use those when your tools need to return partial output, e.g. when wrapping subagents. Streaming tools require a special return type in order to get correctly -handled by the SDK, since partial outputs need to be accumulated, passed though, +handled by the SDK, since partial outputs need to be accumulated, passed through, and the LLM needs to receive an accumulated result. That return type must be a subtype of `ai.Aggregator`. @@ -71,13 +71,20 @@ async def draft_reply(topic: str) -> ai.StreamingTextTool: Use `ai.StreamingStatusTool[T]` when intermediate yields are progress updates and the last yielded value is the final result. -The agent emits `PartialToolCallResult` events for those values, then sends +The agent emits `PartialToolCallResult` events for those values, then sends the aggregated result back to the model on the next turn. ## Understand tool anatomy -> provide a diagram of ai.Tool, AgentTool, provider tools, etc. -> mention that tools contain spec and params, and which tools have which +`ai.Tool` represents tools of all kinds in the SDK. + +Each tool carries an optional `spec`, which is a description consumed by the +model, as well as a `tool_config` that contains tool-specific execution config +(e.g. retry policy). + +`AgentTool` wraps `ai.Tool` together with its corresponding Python function, +which allows `agent.run` to find and call that function when the model requests +to do so. Pass `ai.Tool` objects directly to `ai.stream` when you want the model to emit tool calls but you do not want the SDK to execute them: From 36a81ba347f1bccbf98fb0e5428dba6b38ae168e Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Fri, 26 Jun 2026 08:26:38 -0700 Subject: [PATCH 17/19] Clarify aggregators --- docs/ai-python/content/docs/basics/tools.mdx | 22 ++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/ai-python/content/docs/basics/tools.mdx b/docs/ai-python/content/docs/basics/tools.mdx index fb283af0..054ccf12 100644 --- a/docs/ai-python/content/docs/basics/tools.mdx +++ b/docs/ai-python/content/docs/basics/tools.mdx @@ -51,10 +51,21 @@ AI SDK for Python supports tools that are async-generators. You might want to use those when your tools need to return partial output, e.g. when wrapping subagents. -Streaming tools require a special return type in order to get correctly -handled by the SDK, since partial outputs need to be accumulated, passed through, -and the LLM needs to receive an accumulated result. That return type must be -a subtype of `ai.Aggregator`. +Streaming tools use aggregators. An aggregator solves two problems: the tool can +yield many values over time, but the agent still needs one final tool result; +and your app may want a rich stored result while the model needs a simpler value +on the next turn. + +The core interface is: + +```python +class Aggregator[Item, Result, ModelInput]: + def feed(self, item: Item) -> None: ... + def snapshot(self) -> Result: ... + + @classmethod + def to_model_input(cls, snapshot: Result) -> ModelInput: ... +``` Use `ai.StreamingTextTool` when yielded strings should concatenate into the tool result: @@ -71,6 +82,9 @@ async def draft_reply(topic: str) -> ai.StreamingTextTool: Use `ai.StreamingStatusTool[T]` when intermediate yields are progress updates and the last yielded value is the final result. +Use `ai.SubAgentTool` when a tool streams events from a nested agent. The stored +result is a message bundle, and the model sees the final assistant text. + The agent emits `PartialToolCallResult` events for those values, then sends the aggregated result back to the model on the next turn. From 8c97b5547880194e4c66e7a047ede65a7cd0c352 Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Fri, 26 Jun 2026 09:11:43 -0700 Subject: [PATCH 18/19] Fix outdated APIs across the docs --- README.md | 2 +- docs/ai-python/content/docs/basics/agents.mdx | 2 +- .../content/docs/basics/ai-sdk-ui.mdx | 3 ++- .../content/docs/basics/custom-loops.mdx | 12 ++++----- .../content/docs/basics/providers.mdx | 16 ++++++----- docs/ai-python/content/docs/basics/tools.mdx | 4 +++ docs/ai-python/content/docs/index.mdx | 7 +++++ .../ai.providers/ai-gateway/index.mdx | 2 +- .../ai.providers/anthropic/index.mdx | 4 +-- .../reference/ai.providers/openai/index.mdx | 4 +-- .../content/docs/reference/ai/index.mdx | 15 ++++++++--- docs/ai-python/content/docs/reference/mcp.mdx | 6 +++++ skills/ai-python-basics/SKILL.md | 4 ++- skills/ai-python-custom-provider/SKILL.md | 27 ++++++++++++------- 14 files changed, 73 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 4b2ff58a..0233febe 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ async def contact_mothership(query: str) -> str: async def main() -> None: - model = ai.get_model("gateway:anthropic/claude-sonnet-4") + model = ai.get_model("anthropic/claude-sonnet-4") agent = ai.agent(tools=[contact_mothership]) messages = [ diff --git a/docs/ai-python/content/docs/basics/agents.mdx b/docs/ai-python/content/docs/basics/agents.mdx index 85ef7b9d..594ff64e 100644 --- a/docs/ai-python/content/docs/basics/agents.mdx +++ b/docs/ai-python/content/docs/basics/agents.mdx @@ -97,7 +97,7 @@ async with agent.run( model, [ai.user_message("Return a JSON mothership forecast.")], output_type=Forecast, - params={"temperature": 0}, + params=ai.InferenceRequestParams().with_temperature(0), ) as stream: async for event in stream: if isinstance(event, ai.events.TextDelta): diff --git a/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx b/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx index ef9843b2..49393763 100644 --- a/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx +++ b/docs/ai-python/content/docs/basics/ai-sdk-ui.mdx @@ -63,7 +63,8 @@ async def draft_mothership_reply(topic: str) -> ai.StreamingTextTool: ``` For subagents, `ai.SubAgentTool` streams nested events and stores the nested -assistant message as the tool output. +transcript as a `MessageBundle`. The model sees the nested agent's final +assistant text. ## Inbound message updates diff --git a/docs/ai-python/content/docs/basics/custom-loops.mdx b/docs/ai-python/content/docs/basics/custom-loops.mdx index 235a26af..de5d2af9 100644 --- a/docs/ai-python/content/docs/basics/custom-loops.mdx +++ b/docs/ai-python/content/docs/basics/custom-loops.mdx @@ -6,9 +6,9 @@ summary: Override the agent loop to customize scheduling, routing, history updat --- Override `loop` when you need custom tool dispatch, logging, durability, or -branching. While the SDK is doing it's best to define the loop as a Python -async generator, it's still using *some* special components. Be sure to reuse -those to retain certain framework-controlled behavior. +branching. While the SDK defines the loop as a Python async generator, it still +uses a few framework components. Reuse those to retain framework-controlled +behavior. ## Explore the standard loop shape @@ -18,7 +18,7 @@ turn, it streams the model response and schedules tool calls: ```python class CustomAgent(ai.Agent): # ai.Context keeps track of message history, run inputs, and other per-run data - async def loop(self, context: ai.Context) -> AsyncGenerator[ai.Event]: + async def loop(self, context: ai.Context) -> AsyncGenerator[ai.events.AgentEvent]: while context.keep_running(): # call ai.stream with whatever model, tools, and messages the user has # passed to agent.run @@ -26,8 +26,8 @@ class CustomAgent(ai.Agent): ai.stream(context=context) as stream, # ai.ToolRunner is responsible for concurrent tool scheduling and # streaming, as well as graceful handling of hook interruptions - ai.ToolRunner() as tool_runner, - + ai.ToolRunner() as tool_runner, + ): # ai.util.merge interleaves two streams together, so the agent # can fire off tools as they arrive in the stream rather than diff --git a/docs/ai-python/content/docs/basics/providers.mdx b/docs/ai-python/content/docs/basics/providers.mdx index 7ee4898b..8fe5b172 100644 --- a/docs/ai-python/content/docs/basics/providers.mdx +++ b/docs/ai-python/content/docs/basics/providers.mdx @@ -55,7 +55,7 @@ provider = ai.get_provider( api_key="your_access_token_here", ) -model = ai.Model("local-model", provider=provider) +model = ai.Model(id="local-model", provider=provider) ``` You can pass an upstream client to the provider: @@ -72,7 +72,7 @@ provider = ai.get_provider( api_key="your_access_token_here", client=client, ) -model = ai.Model("local-model", provider=provider) +model = ai.Model(id="local-model", provider=provider) ``` Close explicit providers when your app shuts down: @@ -110,12 +110,14 @@ except ai.ProviderError as exc: Pass request-scoped provider options with `params`: ```python -params = { - "providerOptions": { - "gateway": {"sort": "cost"}, - "anthropic": {"speed": "fast"}, +params = ai.InferenceRequestParams( + extra_body={ + "providerOptions": { + "gateway": {"sort": "cost"}, + "anthropic": {"speed": "fast"}, + } } -} +) async with ai.stream(model, messages, params=params) as stream: async for event in stream: diff --git a/docs/ai-python/content/docs/basics/tools.mdx b/docs/ai-python/content/docs/basics/tools.mdx index 054ccf12..f890204f 100644 --- a/docs/ai-python/content/docs/basics/tools.mdx +++ b/docs/ai-python/content/docs/basics/tools.mdx @@ -157,6 +157,10 @@ tools = [ The Model Context Protocol (MCP) adapter converts server tools into agent tools: +```bash +uv add "ai[mcp]" +``` + ```python tools = await ai.mcp.get_http_tools( "http://localhost:3000/mcp", diff --git a/docs/ai-python/content/docs/index.mdx b/docs/ai-python/content/docs/index.mdx index 68717fd4..55deabe9 100644 --- a/docs/ai-python/content/docs/index.mdx +++ b/docs/ai-python/content/docs/index.mdx @@ -21,6 +21,13 @@ async Python. uv add ai ``` +AI Gateway is the default route for unprefixed model IDs. Configure the gateway +key before running the examples: + +```bash title="Terminal" +export AI_GATEWAY_API_KEY="your_access_token_here" +``` + Then import the package in Python: ```python diff --git a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx index 318b74b1..09161bfb 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/ai-gateway/index.mdx @@ -21,7 +21,7 @@ Default configuration uses `AI_GATEWAY_API_KEY`. ```python provider = ai.get_provider("vercel") -model = ai.Model("anthropic/claude-sonnet-4", provider=provider) +model = ai.Model(id="anthropic/claude-sonnet-4", provider=provider) ``` The provider uses the Gateway v3 protocol by default, owns the Gateway client, diff --git a/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx index 22337a95..345a1ab9 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/anthropic/index.mdx @@ -10,7 +10,7 @@ and provider-executed tools. ```python provider = ai.get_provider("anthropic") -model = ai.Model("claude-sonnet-4-6", provider=provider) +model = ai.Model(id="claude-sonnet-4-6", provider=provider) ``` The optional upstream Anthropic SDK loads lazily when the provider creates or @@ -34,7 +34,7 @@ provider = ai.get_provider( "anthropic", base_url="https://anthropic.example.com", ) -model = ai.Model("claude-sonnet-4-6", provider=provider) +model = ai.Model(id="claude-sonnet-4-6", provider=provider) ``` The provider supports model listing, probing, streaming, provider-executed diff --git a/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx b/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx index dcf08006..f825b50b 100644 --- a/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx +++ b/docs/ai-python/content/docs/reference/ai.providers/openai/index.mdx @@ -10,7 +10,7 @@ provider-executed tools. ```python provider = ai.get_provider("openai") -model = ai.Model("gpt-5", provider=provider) +model = ai.Model(id="gpt-5", provider=provider) ``` The optional upstream OpenAI SDK loads lazily when the provider creates or uses @@ -33,7 +33,7 @@ provider = ai.get_provider( "openai", base_url="http://localhost:11434/v1", ) -model = ai.Model("llama3", provider=provider) +model = ai.Model(id="llama3", provider=provider) ``` The provider supports model listing, probing, streaming, provider-executed diff --git a/docs/ai-python/content/docs/reference/ai/index.mdx b/docs/ai-python/content/docs/reference/ai/index.mdx index b83c063d..d72ad32f 100644 --- a/docs/ai-python/content/docs/reference/ai/index.mdx +++ b/docs/ai-python/content/docs/reference/ai/index.mdx @@ -53,7 +53,7 @@ These module aliases are also re-exported from `ai`. endpoints, model listing, and wire translation. ```python -model = ai.Model("gpt-5", provider=provider) +model = ai.Model(id="gpt-5", provider=provider) model.id model.provider model.protocol @@ -65,7 +65,7 @@ model.with_protocol(protocol) Fields: - `id`: Provider model id. -- `provider`: Provider instance or provider id. +- `provider`: Provider instance. - `protocol`: Optional provider protocol override. Methods: @@ -109,8 +109,15 @@ provider wire formats. Provider instances use a protocol for `stream` and `generate` calls. ```python -protocol.stream(client, model, messages, tools=tools, params=params) -await protocol.generate(client, model, messages, params) +protocol.stream( + client, + model, + messages, + tools=tools, + params=params, + provider=provider.name, +) +await protocol.generate(client, model, messages, params, provider=provider.name) ``` ## Request Params diff --git a/docs/ai-python/content/docs/reference/mcp.mdx b/docs/ai-python/content/docs/reference/mcp.mdx index 4caa1b25..bffee0b3 100644 --- a/docs/ai-python/content/docs/reference/mcp.mdx +++ b/docs/ai-python/content/docs/reference/mcp.mdx @@ -7,6 +7,12 @@ summary: Reference for ai.mcp. `ai.mcp` loads MCP server tools as `AgentTool` values. +Install the MCP extra before using these helpers: + +```bash +uv add "ai[mcp]" +``` + ## get_stdio_tools `get_stdio_tools` starts an MCP server subprocess and returns `AgentTool` diff --git a/skills/ai-python-basics/SKILL.md b/skills/ai-python-basics/SKILL.md index 999f937b..fe62c06e 100644 --- a/skills/ai-python-basics/SKILL.md +++ b/skills/ai-python-basics/SKILL.md @@ -7,10 +7,12 @@ metadata: # ai-python-basics -Install with `uv add ai`. +Requires Python 3.12 or later. Install with `uv add ai`. Use `import ai`. +For gateway-routed model IDs, set `AI_GATEWAY_API_KEY`. + Core pieces: - `Model` selects the provider and model. diff --git a/skills/ai-python-custom-provider/SKILL.md b/skills/ai-python-custom-provider/SKILL.md index 72de40b4..ce8d3f0d 100644 --- a/skills/ai-python-custom-provider/SKILL.md +++ b/skills/ai-python-custom-provider/SKILL.md @@ -14,13 +14,15 @@ Minimal shape: ```python from collections.abc import AsyncGenerator, Sequence -from typing import Any +from typing import Any, Literal import pydantic import ai class MyProtocol(ai.ProviderProtocol[Any]): + protocol_class_id: Literal["my_protocol"] = "my_protocol" + def stream( self, client: Any, @@ -50,13 +52,16 @@ class MyProtocol(ai.ProviderProtocol[Any]): class MyProvider(ai.Provider[Any]): - def __init__(self, client: Any) -> None: - super().__init__( - name="my", - base_url="", - protocol=MyProtocol(), - client=client, - ) + provider_class_id: Literal["my_provider"] = "my_provider" + name: str = "my" + default_base_url: str = "https://example.invalid" + + def __init__(self, *, client: Any) -> None: + super().__init__() + self._set_client(client) + + def default_protocol(self) -> ai.ProviderProtocol[Any]: + return MyProtocol() async def list_models(self) -> list[str]: return ["my-model"] @@ -65,7 +70,7 @@ class MyProvider(ai.Provider[Any]): return None -model = ai.Model("my-model", provider=MyProvider(client)) +model = ai.Model(id="my-model", provider=MyProvider(client=client)) ``` For Python tool calls, emit `ToolStart`, `ToolDelta`, and `ToolEnd`: @@ -84,3 +89,7 @@ Then `Agent` resolves and runs the tool. If the provider runs its own built-in tool, emit `BuiltinToolStart`, `BuiltinToolDelta`, `BuiltinToolEnd`, and `BuiltinToolResult` instead. + +Do not implement a custom provider for normal app configuration. Prefer +`ai.get_provider(...)`, `ai.get_model(...)`, or a protocol override unless you +are adding a new upstream API adapter. From 2a60028b98d23a436203509726862a09be8a01ad Mon Sep 17 00:00:00 2001 From: Andrey Buzin Date: Fri, 26 Jun 2026 10:03:40 -0700 Subject: [PATCH 19/19] Align skills with the updated documentation --- skills/ai-python-durable-execution/SKILL.md | 119 +++++++++++++----- .../ai-python-serverless-execution/SKILL.md | 77 +++++++++--- skills/ai-python-streaming-tools/SKILL.md | 98 ++++++++++++--- 3 files changed, 229 insertions(+), 65 deletions(-) diff --git a/skills/ai-python-durable-execution/SKILL.md b/skills/ai-python-durable-execution/SKILL.md index 703373ea..d16c5cfc 100644 --- a/skills/ai-python-durable-execution/SKILL.md +++ b/skills/ai-python-durable-execution/SKILL.md @@ -1,46 +1,107 @@ --- name: ai-python-durable-execution -description: Use when adding durable execution to AI SDK for Python or serializing messages. +description: Use when adding durable execution to AI SDK for Python, building durable agent loops, or serializing messages across workflow steps. metadata: sdk-version: "0.2.1" --- # ai-python-durable-execution -Durability belongs at I/O boundaries. Keep the framework pieces when possible: -`Agent`, `Context`, messages, `ai.stream`, `ToolRunner`, and `@ai.tool`. +Use durable execution when an agent run must survive restarts, worker moves, or +long waits. -Serialize only data: +The SDK does not provide durability by itself. Build a custom `Agent.loop`, and +put side effects inside durable steps: -- Messages with `message.model_dump(mode="json")`. -- Restore with `ai.messages.Message.model_validate(...)`. -- Model IDs, tool schemas, params, and plain tool arguments. +- model calls +- tool I/O +- approval or resume boundaries -Do not serialize live clients, provider instances with open clients, streams, -tasks, or sockets. Recreate those inside activities or other durable I/O calls. +Keep the workflow replayable. Durable steps should take JSON inputs and return +JSON outputs. -For a durable model call, run the real model call in the durability API and -return a complete assistant `Message`. Feed it back through the normal stream -machinery: +Serialize messages like this: ```python -message = ai.messages.Message.model_validate(saved_message) - -async with ( - ai.Stream(ai.events.replay_message_events(message)) as stream, - ai.ToolRunner() as runner, -): - async for event in ai.util.merge(stream, runner.events()): - yield event - if isinstance(event, ai.events.ToolEnd): - runner.schedule(context.resolve(event.tool_call)) - - context.add(stream.message) - context.add(runner.get_tool_message()) +data = message.model_dump(mode="json") +message = ai.messages.Message.model_validate(data) ``` -For durable tools, pass `ToolRunner.schedule(...)` a zero-arg async callable -that calls the durability API and returns `ai.tool_result(...)`. +## Model Step -You do not need to rewrite the whole loop. Usually only the model call and tool -body need durable wrappers. +A durable model step should drain `ai.stream(...)` inside the step and return one +complete assistant `Message`. + +```python +@workflow.step +async def llm_step( + model_data: dict[str, object], + messages_data: list[dict[str, object]], + tools_data: list[dict[str, object]], +) -> dict[str, object]: + model = ai.Model.model_validate(model_data) + messages = [ + ai.messages.Message.model_validate(message) + for message in messages_data + ] + tools = [ai.Tool.model_validate(tool) for tool in tools_data] + + async with ai.stream(model, messages, tools=tools) as stream: + async for _event in stream: + pass + + if stream.message is None: + raise RuntimeError("LLM stream ended without a message") + + return stream.message.model_dump(mode="json") +``` + +## Durable Tools + +Prefer wrapping the tool body in the durable step: + +```python +@ai.tool +@workflow.step +async def ask_mothership(question: str) -> str: + response = await mothership_client.ask(question) + return response.summary +``` + +If the workflow system needs separate activity dispatch, schedule a zero-arg +callable that returns `ai.tool_result(...)`. Do not call `tool.fn` directly. + +## Agent Loop + +Use the model step result as a complete message. Do not wrap it in `ai.Stream`, +`ai.events.replay_message_events`, or `ai.util.merge`, those utilities are +used for fluent dispatch in non-durable applications, which is impossible +in a workflow setting since streams are considered side-effects. + +```python +class DurableAgent(ai.Agent): + async def loop(self, context: ai.Context): + while context.keep_running(): + result = await llm_step( + context.model.model_dump(mode="json"), + [m.model_dump(mode="json") for m in context.messages], + [t.model_dump(mode="json") for t in context.tools], + ) + + assistant_message = ai.messages.Message.model_validate(result) + context.add(assistant_message) + + async with ai.ToolRunner() as runner: + for tool_call in assistant_message.tool_calls: + runner.schedule(context.resolve(tool_call)) + + async for event in runner.events(): + yield event + + context.add(runner.get_tool_message()) +``` + +This pattern does not stream model tokens to the caller. That is usually the +right tradeoff for durable workflows, because many durable systems do not support +async generators. You can build a queue-based side channel for streaming; however, +that kind of stream can't be used to dispatch tools and affect control flow directly. diff --git a/skills/ai-python-serverless-execution/SKILL.md b/skills/ai-python-serverless-execution/SKILL.md index f3d23032..3753266d 100644 --- a/skills/ai-python-serverless-execution/SKILL.md +++ b/skills/ai-python-serverless-execution/SKILL.md @@ -1,16 +1,22 @@ --- name: ai-python-serverless-execution -description: Use when building with AI SDK for Python in serverless. Correctly do tool approvals, utilize built-in replay and resume. +description: Use when building serverless AI SDK for Python endpoints, handling hook approvals, aborting pending hooks, or resuming runs across requests. metadata: sdk-version: "0.2.1" --- # ai-python-serverless-execution -Use hooks to stop a run, save messages, then replay from the same assistant -turn. +Use this when working in a serverless setup, e.g. Vercel Fluid Compute. -For tool approval, mark the tool: +The only major difference in serverless is processing tool approvals +and other hooks. Since you can't keep the hook future alive, you need +to stop the run, save messages, then start a later request with the +hook resolution pre-registered. + +## Tool Approval + +Mark approval-gated tools with `require_approval=True`: ```python @ai.tool(require_approval=True) @@ -18,42 +24,77 @@ async def delete_file(path: str) -> str: return f"Deleted {path}" ``` -First request: +## First Request + +When a pending hook appears, send it to the client and call +`ai.abort_pending_hook(...)`. + +Keep draining the stream. Do not break after the first hook. This lets sibling +tools finish or get marked pending, and makes `stream.messages` complete. ```python +pending_hooks = [] + async with agent.run(model, messages) as stream: async for event in stream: if ( isinstance(event, ai.events.HookEvent) and event.hook.status == "pending" ): - save_hook_id(event.hook.hook_id) + pending_hooks.append(event.hook) ai.abort_pending_hook(event.hook) + yield event -saved_messages = stream.messages +saved_messages = [ + message.model_dump(mode="json") + for message in stream.messages +] +save_messages(saved_messages) +save_pending_hook_ids([hook.hook_id for hook in pending_hooks]) ``` -Next request: +## Resume Request + +Load the saved messages, pre-register hook resolutions, then call `agent.run`. ```python messages = [ - ai.messages.Message.model_validate(m) - for m in load_messages_json() + ai.messages.Message.model_validate(message) + for message in load_messages() ] -ai.resolve_hook( - hook_id, - ai.tools.ToolApproval(granted=True, reason="approved"), -) +for approval in approvals: + ai.resolve_hook( + approval.hook_id, + ai.tools.ToolApproval( + granted=approval.granted, + reason=approval.reason, + ), + ) async with agent.run(model, messages) as stream: async for event in stream: yield event + +save_messages([ + message.model_dump(mode="json") + for message in stream.messages +]) ``` -Do not ask the model to make the tool call again. `Agent.run` prepares replay: -it marks the interrupted assistant turn with `replay=True` and keeps completed -sibling tool results on `cached_result`. +Call `ai.resolve_hook(...)` before `agent.run(...)`. Do not ask the model to +make the tool call again. + +`Agent.run` prepares saved interrupted messages for replay. Completed sibling +tool results are reused, pending hooks receive the pre-registered resolution, +and replay-only events are hidden from the caller. + +## Rules -Persist messages, not the hook registry. +- Use normal `agent.run(...)`; serverless resume usually does not need a custom loop. +- If you do write a custom loop, use `context.resolve(...)`, `ToolRunner`, and + `context.add(...)` so approvals and replay keep working. +- For custom hooks, pre-register with `ai.resolve_hook(hook_id, data, payload=PayloadType)`. +- For AI SDK UI clients, use `ai-python-ui-adapter` for message conversion, + approval responses, and SSE. diff --git a/skills/ai-python-streaming-tools/SKILL.md b/skills/ai-python-streaming-tools/SKILL.md index ce6a76b1..b305fb12 100644 --- a/skills/ai-python-streaming-tools/SKILL.md +++ b/skills/ai-python-streaming-tools/SKILL.md @@ -1,55 +1,117 @@ --- name: ai-python-streaming-tools -description: Use for AI SDK for Python tools that stream output, or contain subagents. Handle interleaved streaming and nested events. +description: Use for AI SDK for Python async-generator tools, streaming tool output, subagent tools, PartialToolCallResult events, and custom tool aggregation. metadata: sdk-version: "0.2.1" --- # ai-python-streaming-tools -Make a streaming tool an async generator. +Use async-generator tools when a tool should show progress while it runs. -Use `StreamingTextTool` when yielded strings join into the result: +A streaming tool yields many values, but the agent still needs one final tool +result for the next model turn. The return type tells the SDK how to combine +those yields. + +## Text Chunks + +Use `ai.StreamingTextTool` when yielded strings should concatenate into the +final tool result. ```python @ai.tool -async def draft(topic: str) -> ai.StreamingTextTool: - yield "Drafting " +async def draft_reply(topic: str) -> ai.StreamingTextTool: + yield "Checking records for " yield topic ``` -Use `StreamingStatusTool[T]` when only the last yield is the result: +The caller sees each yield as `ai.events.PartialToolCallResult`. The model later +sees one string: `"Checking records for {topic}"`. + +## Progress Then Result + +Use `ai.StreamingStatusTool[T]` when the last yielded value is the tool result. ```python @ai.tool -async def fetch(url: str) -> ai.StreamingStatusTool[str]: +async def ask_mothership(question: str) -> ai.StreamingStatusTool[str]: yield "connecting" - yield "downloading" - yield body + yield "transmitting" + yield f"The mothership says: {question} is under review." ``` -Use `SubAgentTool` for nested agent events: +The progress values stream to the caller. The model sees only the final yielded +value. + +## Subagents + +Use `ai.SubAgentTool` when a tool runs another agent and streams its events. ```python @ai.tool async def research(topic: str) -> ai.SubAgentTool: - async with child.run(model, [ai.user_message(topic)]) as stream: + researcher = ai.agent() + + messages = [ + ai.system_message("Research briefly."), + ai.user_message(topic), + ] + + async with researcher.run(model, messages) as stream: async for event in stream: yield event ``` -Live values arrive as `ai.events.PartialToolCallResult`. +The parent caller receives nested events as `PartialToolCallResult.value`. + +```python +async with agent.run(model, messages) as stream: + async for event in stream: + if isinstance(event, ai.events.PartialToolCallResult): + if isinstance(event.value, ai.events.TextDelta): + yield event.value.chunk +``` + +`SubAgentTool` stores a typed `MessageBundle` as the tool result. The parent +model sees the nested agent's final assistant text, not the raw bundle. -`SubAgentTool` stores a `MessageBundle` as the tool result. The model sees the -last child assistant text, not the raw bundle. Keep the bundle typed when you -save history: +When saving history, keep the typed message data: ```python data = message.model_dump(mode="json") message = ai.messages.Message.model_validate(data) ``` -Do not stringify `MessageBundle` or drop `result_kind`. The UI adapter uses it -to round-trip subagent output. +Do not stringify `MessageBundle` or drop `result_kind`. + +## Custom Aggregation + +Prefer the aliases above. If you need custom aggregation, use either +`@ai.tool(aggregator=...)` or an `Annotated` return type. Do not use both. + +```python +from collections.abc import AsyncGenerator +from typing import Annotated + +JoinedLines = Annotated[ + AsyncGenerator[str], + ai.agents.Aggregate(ai.agents.ConcatAggregator, delim="\n"), +] + + +@ai.tool +async def outline(topic: str) -> JoinedLines: + yield f"# {topic}" + yield "- first point" +``` + +Custom aggregators implement `ai.events.Aggregator`. + +## Rules -For custom aggregation, use `ai.agents.Aggregate` on the return type. +- Streaming tools must be async generators. +- Every streaming tool needs an aggregator, usually from the return type alias. +- Consume live output from `ai.events.PartialToolCallResult`. +- The final aggregated value is sent back to the model as a normal tool result. +- In custom agent loops, keep `ToolRunner` events flowing; otherwise partial + tool output will not reach the caller.