Skip to main content

pydantic-ai-stream

Production runtime for pydantic-ai agents. Provides structured event streaming via Redis Streams, session persistence, and cancellation support.

img

Install

pip install pydantic-ai-stream

Quick Start

from dataclasses import dataclass
from redis.asyncio import Redis
from pydantic_ai import Agent

from pydantic_ai_stream import Deps, Session, run

# 1. Define your deps (includes Redis client)
@dataclass
class MyDeps(Deps):
    def get_scope_id(self) -> int:
        return 1

# 2. Implement session persistence
@dataclass
class MySession(Session):
    session_id: str

    async def load(self) -> None:
        pass  # Load from your storage

    async def save(self) -> None:
        pass  # Save to your storage

# 3. Create agent and run
agent = Agent("openai:gpt-4o-mini", deps_type=MyDeps)
redis = Redis.from_url("redis://localhost:6379")

async def main():
    deps = MyDeps(redis=redis, user_id=1, session_id="session-1")
    await run(
        MySession(session_id="session-1"),
        agent,
        "Hello, world!",
        deps=deps,
    )

# 4. Stream events (in another coroutine/process)
async def consume():
    deps = MyDeps(redis=redis, user_id=1, session_id="session-1")
    async for event in deps.listen():
        print(event)

Protocol Reference

Stream Format

Events are stored in Redis Streams with three fields:

Field Type Description
type string Event type
origin string Event source
body JSON Event payload

Event Types

type origin Usage
begin pydantic-ai-stream Session start
event pydantic-ai LLM interaction events
error developer / custom Error during execution
info developer / custom Informational
end pydantic-ai-stream Session complete

Event Body Schema (type=event)

Field Type When
idx int Always — node index
event str llm-begin, llm-end, part_start, part_delta, answer
event_idx int Part events — part index
part_kind str text, thinking, tool-call, tool-return
content str Start events — full content
content_delta str Delta events — incremental
tool_name str Tool call/return
tool_call_id str Tool correlation
args dict Tool call — emitted at part end

Configuration

Configure the Redis key prefix via settings:

from pydantic_ai_stream import settings

settings.set_redis_prefix("myapp")  # default: "pyaix"

Key Patterns

{prefix}:{scope_id}:{user_id}:{session_id}       # stream
{prefix}:{scope_id}:{user_id}:{session_id}:live  # live flag

API Reference

Core

async def run(session, agent, user_prompt, deps, **kwargs) -> None

Execute agent with streaming. Wraps Agent.iter(), emits events, handles cancellation.

class AgxCanceledError(Exception)

Raised when execution is cancelled via deps.cancel().

Session

class Session(ABC):
    msgs: list[ModelMessage]

    async def load(self) -> None: ...       # Load from storage
    async def save(self) -> None: ...       # Save to storage
    def msgs_to_json(self) -> bytes         # Serialize messages
    def msgs_from_json(self, data: bytes)   # Deserialize messages
    def get_user_prompt(self) -> str        # Extract initial prompt
    @staticmethod
    def nodes_from_msgs(msgs) -> list       # Reconstruct node structure

Deps

@dataclass
class Deps(ABC):
    redis: AsyncRedis
    user_id: int
    session_id: str

    @abstractmethod
    def get_scope_id(self) -> int: ...

    # Stream operations
    async def start(self) -> None
    async def stop(self, grace_period: int = 5) -> None
    async def is_live(self) -> bool
    async def listen(self, *, wait=3, timeout=60, serialize=True) -> AsyncGenerator
    async def cancel(self) -> bool

    # Event emission
    async def add(self, *, type: str, origin: str, body: dict | None = None) -> None
    async def add_error(self, body: dict, origin: str = "developer") -> None
    async def add_info(self, body: dict, origin: str = "developer") -> None

    # Node tracking (called by run())
    async def add_node_begin(self, node) -> None
    async def add_node_end(self) -> None
    async def add_node_event(self, event) -> None

Query Active Sessions

async def q(redis, scope_id, user_id) -> AsyncGenerator[tuple[int, int, str], None]

Scan for active sessions (those with live flag set).

Example: FastAPI SSE

See examples/fastapi_sse.py for a complete example with:

  • SSE streaming endpoint
  • Cancellation support
  • Tool usage
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic_ai_stream import Deps, Session, run

@app.post("/chat")
async def chat(prompt: str, session_id: str):
    deps = MyDeps(redis=redis, user_id=1, session_id=session_id)

    # Start agent in background
    asyncio.create_task(run(MySession(...), agent, prompt, deps=deps))

    # Stream events via SSE
    async def stream():
        async for event in deps.listen():
            yield f"data: {event}\n\n"

    return StreamingResponse(stream(), media_type="text/event-stream")

@app.post("/chat/{session_id}/cancel")
async def cancel_chat(session_id: str):
    deps = MyDeps(redis=redis, user_id=1, session_id=session_id)
    return {"cancelled": await deps.cancel()}

License

MIT

Metadata

Release files for pydantic-ai-stream 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydantic-ai-stream 0.1.1
File Size Uploaded Provenance
pydantic_ai_stream-0.1.1.tar.gz 113.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pydantic-ai-stream 0.1.1
File Interpreter ABI Platform
pydantic_ai_stream-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 121.4 kB

Release files / pydantic_ai_stream-0.1.1.tar.gz

Download URL pydantic_ai_stream-0.1.1.tar.gz
Size 113.7 kB
Tags Source
SHA-256 checksum
How to use checksums
9e4f54ac6781485386c08fc9f07e3d3837a6801e42c9bd3e1115a4d114db2a36
BLAKE2b-256 checksum
How to use checksums
b8fc638cd25f74c8b81bce78b9af79fc8bdaefb747178813fc33ea20a3e88b0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.18

Release files / pydantic_ai_stream-0.1.1-py3-none-any.whl

Download URL pydantic_ai_stream-0.1.1-py3-none-any.whl
Size 7.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a48e53eee81456f5c36984f3888620f3c0c787a078a7725748464aec24991b26
BLAKE2b-256 checksum
How to use checksums
6fb40039e43cb8433487a02ff5ca97d991dd9f591e55de02cc1bbaf657112833
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.18

Security for pydantic-ai-stream 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page