Skip to main content

Tessera × Pydantic AI

tessera-pydantic-ai is a thin adapter that routes every Pydantic AI agent.run_sync() / agent.run()call through Tessera's substrate proxy. Two patterns: provider wrapper (one function call returns a ready-to-use Pydantic AI Provider) or config kwargs (you keep direct control of the underlying AsyncOpenAI / AsyncAnthropic client and just spread our config into its constructor).

v0.1 ships OpenAI + Anthropic.Mistral / Groq / Cohere are queued for v0.2 — those Provider classes have a similar custom-client pattern but the exact signature has not been end-to-end verified yet, so we'd rather ship two honest providers than five unverified ones. For verified Mistral / Groq / Cohere, use tessera-langchain or tessera-llamaindex.

Install

pip install tessera-pydantic-ai pydantic-ai openai anthropic

Get a free Tessera API key at tesseraai.io/dev — 60M tokens/month, no card up front.

Quickstart — OpenAI

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from tessera_pydantic_ai import tessera_openai_provider

provider = tessera_openai_provider(
    openai_api_key="sk-...",        # your OpenAI key
    tessera_api_key="tk_...",      # free from tesseraai.io/dev
)

agent = Agent(OpenAIChatModel("gpt-4o", provider=provider))
result = agent.run_sync("Summarize this customer support ticket in 2 sentences.")

Scenario 1 — Anthropic — same shape, different model class

The provider-wrapper pattern mirrors OpenAI. Use tessera_anthropic_provider in place of tessera_openai_provider and pass the result into AnthropicModel(...).

from pydantic_ai import Agent
from pydantic_ai.models.anthropic import AnthropicModel
from tessera_pydantic_ai import tessera_anthropic_provider

provider = tessera_anthropic_provider(
    anthropic_api_key="sk-ant-...",
    tessera_api_key="tk_...",
)
agent = Agent(AnthropicModel("claude-sonnet-4-6", provider=provider))
result = agent.run_sync("Classify the intent of: ...")

Scenario 2 — Type-safe structured output

Pydantic AI's killer feature is the type-safe output_type — the agent produces a Pydantic model instance instead of a raw string. Auto-route often promotes structured-output workloads from gpt-4o down to gpt-4o-mini because schema-constrained tasks tolerate the swap on the canary eval.

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic import BaseModel
from tessera_pydantic_ai import tessera_openai_provider

class TicketTriage(BaseModel):
    intent: str   # bug / feature / billing / other
    severity: str # low / medium / high / critical
    summary: str

agent = Agent(
    OpenAIChatModel("gpt-4o-mini", provider=tessera_openai_provider(
        openai_api_key="sk-...",
        tessera_api_key="tk_...",
    )),
    output_type=TicketTriage,
)

result = agent.run_sync("Customer says their March invoice shows $0 but card was charged.")
# result.output is a TicketTriage instance — fully typed.

Scenario 3 — Fine-grained AsyncOpenAI client control

When you need to set an organization id, custom http_client, retry config, or compose other constructor kwargs that the wrapper hides, use the pass-through config function and build the AsyncOpenAI client yourself.

# When you need fine-grained control over the AsyncOpenAI client itself
# (organization id, custom http_client, retry config), use the pass-through
# config function instead of the wrapper.

from openai import AsyncOpenAI
from pydantic_ai.providers.openai import OpenAIProvider
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai import Agent
from tessera_pydantic_ai import tessera_openai_config

client = AsyncOpenAI(
    api_key="sk-...",
    organization="org-mine",
    **tessera_openai_config(api_key="tk_..."),
)
provider = OpenAIProvider(openai_client=client)
agent = Agent(OpenAIChatModel("gpt-4o", provider=provider))

Worked savings example

Customer-support agent on gpt-4o with structured output, 5B tokens/month, OpenAI list prices.

StageCost / moSaved
Baseline — OpenAI direct via Pydantic AI$24,000
+ Tessera (route, cache, prompt-cache, compress, M9 ceiling, batch)$9,400$14,600
Tessera fee (20% × measured savings)$2,920
You net pay$12,320$11,680 / mo saved

Quality canary held 0.96 across the full mechanic stack (floor 0.95). Auto-route from gpt-4o to gpt-4o-mini on schema-constrained sub-tasks contributed roughly half of the savings.

Architecture and quality contract

Pydantic AI + the underlying SDK clients (openai, anthropic) are NOT declared as dependencies of this package — install whichever providers you actually use. The Tessera factories import them lazily at call time so the package itself never blows up over missing optional deps.

Composition cap (max 2 content-mutators per request), per-stack 0.95 quality floor, audit-immutable measurement — all enforced on the proxy. Browse the verified-savings ledger at ledger.tesseraai.io.

FAQ

Why only OpenAI and Anthropic in v0.1?
Honesty over feature breadth. The Pydantic AI Provider class for each LLM accepts a custom underlying-SDK client (e.g. OpenAIProvider(openai_client=...)) — we have end-to-end verified that pattern against OpenAI and Anthropic. Mistral / Groq / Cohere Provider classes exist in Pydantic AI but their custom-client shape has not been tested in our CI. Per our public-claim discipline, the unverified providers stay queued for v0.2.
Does this break tools / structured outputs / streaming?
No. The Pydantic AI Provider object that wraps the underlying SDK client is unchanged in shape — agent.run_sync(), agent.run(), tool calls, structured outputs (output_type=...), and streaming all work unchanged. Auto-route gates on tool-calling capability.
What if I already use multiple providers in one app?
Same Tessera key powers both. Construct one Pydantic AI Agent per provider, route each through its matching Tessera helper. Per-workload auto-route + quality canary fire independently. Billing rolls up to the same monthly reading.

Where to go next