Skip to main content

uv ty Ask DeepWiki

OpenBB Pydantic AI Adapter

openbb-pydantic-ai lets any Pydantic AI agent run behind OpenBB Workspace by translating QueryRequest payloads into a Pydantic AI run, exposing Workspace widgets as deferred tools, and streaming native OpenBB SSE events back to the UI.

  • Stateless by design: each QueryRequest carries the full conversation history, widgets, context, and URLs so requests are processed independently.
  • First-class widget tools: every widget becomes a deferred Pydantic AI tool; when the model calls one, the adapter emits copilotFunctionCall events and waits for the Workspace to return data before resuming.
  • Rich event stream: reasoning steps, thinking traces, tables, charts, HTML artifacts, and citations are streamed as native OpenBB SSE payloads.
  • PDF context: install the [pdf] extra and the agent can extract and query PDF widgets on the active dashboard, with citations linked to specific pages.
  • Output helpers included: structured outputs (dicts/lists) are auto-detected and converted to tables or charts; chart parameters are normalized for consistent rendering.

See the OpenBB Custom Agent SDK and Pydantic AI UI adapter docs for the underlying types.

Installation

pip install openbb-pydantic-ai
# or with uv
uv add openbb-pydantic-ai

For PDF context support (requires docling):

uv add "openbb-pydantic-ai[pdf]"
# GPU variant (CUDA 12.8)
uv add "openbb-pydantic-ai[pdf-cu128]"

Quick Start (FastAPI)

from anyio import BrokenResourceError
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from pydantic_ai import Agent

from openbb_pydantic_ai import OpenBBAIAdapter, OpenBBDeps

agent = Agent(
    "openrouter:minimax/minimax-m2.5",
    instructions="Be concise and helpful. Only use widget tools for data lookups.",
    deps_type=OpenBBDeps,
)

app = FastAPI()
AGENT_BASE_URL = "http://localhost:8003"


@app.get("/agents.json")
async def agents_json():
    return JSONResponse(
        content={
            "<agent-id>": {
                "name": "My Custom Agent",
                "description": "This is my custom agent",
                "image": f"{AGENT_BASE_URL}/my-custom-agent/logo.png",
                "endpoints": {"query": f"{AGENT_BASE_URL}/query"},
                "features": {
                    "streaming": True,
                    "widget-dashboard-select": True,  # primary & secondary widgets
                    "widget-dashboard-search": True,  # extra widgets
                    "mcp-tools": True,
                },
            }
        }
    )


@app.post("/query")
async def query(request: Request):
    try:
        return await OpenBBAIAdapter.dispatch_request(request, agent=agent)
    except BrokenResourceError:
        pass  # client disconnected


app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://pro.openbb.co"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

How It Works

1. Request Handling

  • OpenBB Workspace POST's a QueryRequest to /query
  • OpenBBAIAdapter validates it, builds the Pydantic AI message stack, and injects workspace context and URLs as system prompts

2. Widget Tool Conversion

  • Widgets in the request become deferred Pydantic AI tools
  • Each call emits a copilotFunctionCall event (via get_widget_data)
  • The adapter pauses until Workspace responds with data, then resumes the run

3. Event Streaming

Pydantic AI event OpenBB SSE event
Text chunk copilotMessageChunk
Reasoning / thinking block Collapsed under "Step-by-step reasoning" dropdown
Table / chart / HTML artifact copilotMessageArtifact
Widget citations copilotCitationCollection (batched at end of run)

Features

Widget Toolsets

Widgets are grouped by priority (primary, secondary, extra) and exposed through dedicated toolsets. Tool names follow the openbb_widget_<identifier> convention with any redundant openbb_ prefix trimmed (e.g. openbb_widget_financial_statements).

Control access via the agents.json feature flags:

"features": {
    "widget-dashboard-select": true,
    "widget-dashboard-search": true
}

Visualization: Charts, Tables & HTML

Three built-in tools handle structured output. The model can call any of them directly; the adapter handles serialization and streaming.

openbb_create_chart

Creates chart artifacts inline in the response. Supported types: line, bar, scatter, pie, donut.

Insert {{place_chart_here}} in the model's text where the chart should appear — the adapter swaps the placeholder with the rendered artifact while streaming:

Here is the revenue breakdown: {{place_chart_here}}

Required axes:

  • line / bar / scatter: x_key + y_keys
  • pie / donut: angle_key + callout_label_key

Different field spellings (y_keys, yKeys, etc.) are accepted and normalized before emitting.

openbb_create_table

Creates a table artifact from structured data with explicit column ordering and metadata. Use this when you want predictable output over auto-detection.

openbb_create_html

Renders a self-contained HTML artifact, useful for custom layouts, formatted reports, or SVG-based plots when Markdown isn't enough.

Constraint: limited to HTML + CSS + inline SVG. No JavaScript. This is an OpenBB Workspace restriction on non-Enterprise plans.

Auto-detection: dict/list outputs shaped like {"type": "table", "data": [...]} or a plain list of dicts are automatically converted to table artifacts without calling any tool explicitly.

Markdown tables are also supported: stream tabular data as Markdown and Workspace renders it as an interactive table users can promote to a widget.

MCP Tools

Tools listed in QueryRequest.tools are exposed as an external MCP toolset. The model sees the same tool names the Workspace UI presents. Deferred execute_agent_tool results replay on the next request just like widget results.

Enable in agents.json:

"features": { "mcp-tools": true }

PDF Context

Install the [pdf] extra to enable PDF support. When a PDF widget is on the active dashboard, the agent can extract and query it with citations linked to specific pages.

uv add "openbb-pydantic-ai[pdf]"

Performance: GPU extraction is significantly faster. CPU works, but expect slowdowns on documents over ~50 pages.

Deferred Results & Citations

  • Pending widget responses in the request are replayed before the run starts, keeping multi-turn workflows seamless.
  • Every widget call records a citation via openbb_ai.helpers.cite, emitted as a copilotCitationCollection at the end of the run.

Progressive Tool Discovery (Default)

Instead of dumping every tool schema into the context upfront, the adapter wraps toolsets with four meta-tools:

Meta-tool Purpose
list_tools List available tools by group
search_tools Keyword search across tool descriptions
get_tool_schema Fetch the full schema for a specific tool
call_tools Invoke a tool by name

The model fetches schemas only when it needs them, keeping the initial context window small. Deferred flows (widget data, MCP) continue to emit get_widget_data and execute_agent_tool events as before.

To disable and expose all schemas upfront:

adapter = OpenBBAIAdapter(
    agent=agent,
    run_input=run_input,
    enable_progressive_tool_discovery=False,
)

Adding Custom Toolsets

Pass custom or third-party toolsets to the adapter at request time rather than mounting them on Agent. They are merged into the progressive discovery wrapper automatically.

Important: do not also pass these toolsets to Agent(toolsets=[...]) when using the OpenBB adapter — they would appear as both direct and progressive tools.

Tag a toolset with add_to_progressive(...):

from pydantic_ai.toolsets import FunctionToolset
from pydantic_ai.tools import RunContext

from openbb_pydantic_ai import OpenBBDeps
from openbb_pydantic_ai.tool_discovery import add_to_progressive

custom_tools = FunctionToolset[OpenBBDeps](id="custom_agent_tools")


@custom_tools.tool
def earnings_note(ctx: RunContext[OpenBBDeps], symbol: str) -> str:
    _ = ctx
    return f"Custom note for {symbol}"


add_to_progressive(
    custom_tools,
    group="custom_agent_tools",
    description="Custom user tools",
)

# Pass at request time
return await OpenBBAIAdapter.dispatch_request(request, agent=agent, toolsets=[custom_tools])

Or use the @progressive(...) decorator directly on the tool function:

from openbb_pydantic_ai.tool_discovery import progressive


@progressive(toolset=custom_tools, group="custom_agent_tools", description="Custom user tools")
@custom_tools.tool
def earnings_note(ctx: RunContext[OpenBBDeps], symbol: str) -> str:
    _ = ctx
    return f"Custom note for {symbol}"

Untagged toolsets passed at request time are forwarded as standalone toolsets without being merged into the progressive wrapper.

Advanced Usage

Instantiate the adapter manually for full control:

from openbb_pydantic_ai import OpenBBAIAdapter

run_input = OpenBBAIAdapter.build_run_input(body_bytes)
adapter = OpenBBAIAdapter(agent=agent, run_input=run_input)

async for event in adapter.run_stream():
    yield event  # already encoded as OpenBB SSE payloads

message_history, deferred_tool_results, and on_complete callbacks are forwarded directly to Agent.run_stream_events().

Runtime deps & prompts: OpenBBDeps bundles widgets (by priority group), context rows, relevant URLs, workspace state, timezone, and a state dict you can pass to toolsets or output validators. The adapter merges dashboard context and current widget parameter values into the runtime instructions automatically — append your own instructions without re-supplying that context.

Local Development

uv sync --dev
uv run pytest
uv run pre-commit run --all-files  # lint + format

Metadata

Release files for openbb-pydantic-ai 0.1.9

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

Source distribution (sdist)

Source distribution for openbb-pydantic-ai 0.1.9
File Size Uploaded Provenance Actions
openbb_pydantic_ai-0.1.9.tar.gz 61.3 kB Without provenance Details for openbb_pydantic_ai-0.1.9.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for openbb-pydantic-ai 0.1.9
File Interpreter ABI Platform Actions
openbb_pydantic_ai-0.1.9-py3-none-any.whl Python 3 none any Details for openbb_pydantic_ai-0.1.9-py3-none-any.whl

Total release size: 137.0 kB

Release files / openbb_pydantic_ai-0.1.9.tar.gz

Download URL openbb_pydantic_ai-0.1.9.tar.gz
Size 61.3 kB
Tags Source
SHA-256 checksum
How to use checksums
72c4d29d36bf46fa57ef120635809d98f641a3045d5225cbcec75b903757f6d9
BLAKE2b-256 checksum
How to use checksums
1608d7e8fe9368fbcd8230afde95f09e17a17d62a99dd2dc88382a4dfbab34a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / openbb_pydantic_ai-0.1.9-py3-none-any.whl

Download URL openbb_pydantic_ai-0.1.9-py3-none-any.whl
Size 75.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
68a003551ee563763fb6a4e6acf871e7b564f211e15ed39ebd50c221b6ab2309
BLAKE2b-256 checksum
How to use checksums
db63040d30b68b2e2edf834de7cae52e6a80d3a65ad88a2992e72178817b5c9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for openbb-pydantic-ai 0.1.9

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