Skip to content
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
1cfa48e
add Agent.to_web() method and web chat UI module #3295
dsfaccini Nov 17, 2025
d83caa5
add "web" group
dsfaccini Nov 17, 2025
bfffd4b
try import create_chat_app
dsfaccini Nov 17, 2025
055e120
fix tests to run on CI
dsfaccini Nov 17, 2025
6bc8b16
fix example to use tool_plain
dsfaccini Nov 17, 2025
32f7e1d
add clai web - tested with uv run clai web
dsfaccini Nov 18, 2025
cf0e177
wip: remove agent discovery and fix tests
dsfaccini Nov 20, 2025
e7f44eb
rename command
dsfaccini Nov 20, 2025
c4ffde3
rename function
dsfaccini Nov 20, 2025
0595c27
- define builtin tool ids
dsfaccini Nov 21, 2025
0d24941
fix tests
dsfaccini Nov 21, 2025
e5b30c2
- update CLI commands and improve agent loading mechanism
dsfaccini Nov 21, 2025
f2dd19a
Merge branch 'main' into clai-chat
dsfaccini Nov 21, 2025
8ca7a27
import sorting
dsfaccini Nov 21, 2025
fa3bb5f
more import sorting
dsfaccini Nov 21, 2025
e45c93f
covergae?
dsfaccini Nov 22, 2025
f90b570
Merge upstream/main into clai-chat
dsfaccini Nov 22, 2025
da8032c
Merge upstream/main into clai-chat
dsfaccini Nov 26, 2025
0ab07b6
- remove agent_options - add supported_builtin_tools - swap fastapi f…
dsfaccini Nov 26, 2025
191897f
refactor from --web to web, adjust flags, add tests, update docs
dsfaccini Nov 26, 2025
1faae3f
remove clai import on test
dsfaccini Nov 26, 2025
8423e89
coverage
dsfaccini Nov 26, 2025
a32c15a
- consolidate web docs in own doc
dsfaccini Nov 27, 2025
91f9533
remove memory cache and swap prints for consoles
dsfaccini Nov 27, 2025
441d6a0
use snapshots where it makes sense
dsfaccini Nov 27, 2025
558985f
Merge branch 'main' into clai-chat
dsfaccini Nov 27, 2025
85f63bc
make _web a private module
dsfaccini Nov 28, 2025
cd91e81
move supported_builtin_tools to abstract tool set type
dsfaccini Nov 28, 2025
a132f26
warning about memory tool
dsfaccini Nov 29, 2025
943c7a8
move name formatting to model method
dsfaccini Nov 29, 2025
831bdf3
move to toolsets
dsfaccini Nov 29, 2025
125c059
update docstring
dsfaccini Nov 29, 2025
025f1b5
take agent's own model into account
dsfaccini Nov 29, 2025
0701b22
bit of docs
dsfaccini Nov 29, 2025
40b5c78
move builtin tool support to profile and move check to base model class
dsfaccini Nov 29, 2025
0673277
fix test profile classes to avoid ci api key error
dsfaccini Nov 29, 2025
974bac2
Merge branch 'main' into clai-chat
dsfaccini Nov 29, 2025
4b58307
coverage
dsfaccini Nov 29, 2025
74f09e9
add anthropic prefix
dsfaccini Dec 1, 2025
897e4e4
fix naming
dsfaccini Dec 1, 2025
10d32fe
remove get agent utility and make supported builtin tools a classmethod
dsfaccini Dec 1, 2025
1c93cf0
remove test
dsfaccini Dec 1, 2025
b60f2ff
Add screenshot link for web chat UI
dsfaccini Dec 3, 2025
ee21cfb
- remove builtin_tools suport check for specific models, base model t…
dsfaccini Dec 3, 2025
cf1da90
support double instructions
dsfaccini Dec 3, 2025
372db8b
remove program check, tie tool arg options to constant and set up aut…
dsfaccini Dec 4, 2025
32cc5c5
merge
dsfaccini Dec 4, 2025
48094d2
add support for model instances, deps and settings
dsfaccini Dec 4, 2025
cd1e683
fix tests after cli adjustments
dsfaccini Dec 4, 2025
c1ba780
separate chat command
dsfaccini Dec 4, 2025
6984dfd
Merge branch 'main' into clai-chat
dsfaccini Dec 4, 2025
cf54985
Merge branch 'main' into clai-chat
dsfaccini Dec 4, 2025
106c8b9
- remove mcp support for now
dsfaccini Dec 4, 2025
f491e57
Merge branch 'main' into clai-chat
dsfaccini Dec 4, 2025
16e36dc
narrow types
dsfaccini Dec 4, 2025
48bd838
Merge branch 'main' into clai-chat
dsfaccini Dec 5, 2025
b45156c
Update clai/README.md
dsfaccini Dec 9, 2025
3733a56
Merge branch 'main' into clai-chat
dsfaccini Dec 9, 2025
b57fb38
Update clai/README.md
dsfaccini Dec 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion clai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,73 @@ Either way, running `clai` will start an interactive session where you can chat
- `/multiline`: Toggle multiline input mode (use Ctrl+D to submit)
- `/cp`: Copy the last response to clipboard

## Web Chat UI

Launch a web-based chat interface for your agent:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's first have an example without an agent, to show that it will work that way as well


```bash
clai web --agent module:agent_variable
```

For example, if you have an agent defined in `my_agent.py`:

```python
from pydantic_ai import Agent

my_agent = Agent('openai:gpt-5', system_prompt='You are a helpful assistant.')
```

Launch the web UI with:

```bash
clai web --agent my_agent:my_agent
```

This will start a web server (default: http://127.0.0.1:7932) with a chat interface for your agent.

### Web Command Options

- `--agent`, `-a`: Agent to serve in `module:variable` format
- `--models`, `-m`: Comma-separated models to make available (e.g., `gpt-5,sonnet-4-5`)
- `--tools`, `-t`: Comma-separated builtin tool IDs to enable (e.g., `web_search,code_execution`)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to builtin tools docs please. We may also need to list all the IDs as I don't think they're documented anywhere

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is "to enable" correct? Are they all enabled by default or just available as options?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most correctest would probably be offer or put at the disposal I guess, but enable seems good enough enable for the user

- `--instructions`, `-i`: System instructions for generic agent (when `--agent` not specified)
- `--host`: Host to bind the server to (default: 127.0.0.1)
- `--port`: Port to bind the server to (default: 7932)

### Using with Models and Tools

You can specify which models and builtin tools are available in the UI via CLI flags:

```bash
# Generic agent with specific models and tools
clai web -m gpt-5,sonnet-4-5 -t web_search,code_execution

# Custom agent with additional models
clai web --agent my_agent:my_agent -m gpt-5,gemini-2.5-pro

# Generic agent with system instructions
clai web -m gpt-5 -i 'You are a helpful coding assistant'
```

You can also launch the web UI directly from an `Agent` instance using `Agent.to_web()`:

```python
from pydantic_ai import Agent
from pydantic_ai.builtin_tools import WebSearchTool

agent = Agent('openai:gpt-5')

# Use defaults
app = agent.to_web()

# Or customize models and tools
app = agent.to_web(builtin_tools=[WebSearchTool()])
```

## Help

```
usage: clai [-h] [-m [MODEL]] [-a AGENT] [-l] [-t [CODE_THEME]] [--no-stream] [--version] [prompt]
usage: clai [-h] [-m [MODEL]] [-a AGENT] [-l] [-t [CODE_THEME]] [--no-stream] [--version] [prompt] {web} ...

Pydantic AI CLI v...

Expand All @@ -66,6 +129,8 @@ Special prompts:

positional arguments:
prompt AI Prompt, if omitted fall into interactive mode
{web} Available commands
web Launch web chat UI for an agent

options:
-h, --help show this help message and exit
Expand Down
26 changes: 26 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ Either way, running `clai` will start an interactive session where you can chat
- `/multiline`: Toggle multiline input mode (use Ctrl+D to submit)
- `/cp`: Copy the last response to clipboard

### Web Chat UI
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of duplication here with clai/README.md. Maybe that readme should just link to this page?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I wasn't sure about it as well, I thought there maybe be people who look more at the repo than the docs, I know I sometimes do, so I left it in both places, but I can just link to the docs from the readme.


Launch a web-based chat interface for your agent:

```bash
clai web --agent module:agent_variable
```

For example, if you have an agent defined in `my_agent.py`:

```python
from pydantic_ai import Agent

my_agent = Agent('openai:gpt-5', instructions='You are a helpful assistant.')
```

Launch the web UI with:

```bash
clai web --agent my_agent:my_agent
```

This will start a web server (default: http://127.0.0.1:7932) with a chat interface for your agent.

For more details on web UI options, MCP server configuration, and programmatic usage with `Agent.to_web()`, see the [Web Chat UI documentation](ui/web.md).

### Help

To get help on the CLI, use the `--help` flag:
Expand Down
150 changes: 150 additions & 0 deletions docs/ui/web.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Web Chat UI

Pydantic AI includes a built-in web chat interface that you can use to interact with your agents through a browser.

<!-- TODO: Add screenshot of the web chat UI here -->

## Installation

Install the `web` extra to get the required dependencies:

```bash
pip/uv-add 'pydantic-ai-slim[web]'
```

## Usage

There are two ways to launch the web chat UI:

### 1. Using the CLI (`clai web`)

The simplest way to start the web UI is using the `clai web` command:

```bash
# With a custom agent
clai web --agent my_module:my_agent

# With specific models
clai web -m openai:gpt-5 -m anthropic:claude-sonnet-4-5

# With builtin tools
clai web -m openai:gpt-5 -t web_search -t code_execution

# Generic agent with system instructions
clai web -m openai:gpt-5 -i 'You are a helpful coding assistant'
```

#### CLI Options

| Option | Description |
|--------|-------------|
| `--agent`, `-a` | Agent to serve in `module:variable` format |
| `--model`, `-m` | Model to make available (repeatable) |
| `--tool`, `-t` | Builtin tool to enable (repeatable) |
| `--instructions`, `-i` | System instructions (when `--agent` not specified) |
| `--host` | Host to bind server (default: 127.0.0.1) |
| `--port` | Port to bind server (default: 7932) |
| `--mcp` | Path to MCP server config JSON file |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is missing from the CLI docs


Model names without a provider prefix are automatically inferred:

- `gpt-*`, `o1`, `o3` → OpenAI
- `claude-*`, `sonnet`, `opus`, `haiku` → Anthropic
- `gemini-*` → Google

### 2. Using `Agent.to_web()` Programmatically
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these docs, I would present the to_web approach first, and then link to the CLI docs for the second approach


For more control, you can create a web app from an agent instance:

```python
from pydantic_ai import Agent
from pydantic_ai.builtin_tools import WebSearchTool

agent = Agent('openai:gpt-5')

@agent.tool_plain
def get_weather(city: str) -> str:
return f'The weather in {city} is sunny'

# Create app with model names (their display names are auto-generated)
app = agent.to_web(
models=['openai:gpt-5', 'anthropic:claude-sonnet-4-5'],
builtin_tools=[WebSearchTool()],
)

# Or with custom display labels
app = agent.to_web(
models={'GPT 5': 'openai:gpt-5', 'Claude': 'anthropic:claude-sonnet-4-5'},
builtin_tools=[WebSearchTool()],
)
```

The returned Starlette app can be run with any ASGI server:

```bash
uvicorn my_module:app --host 0.0.0.0 --port 8080
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the same port the CLI uses

```

!!! note "Reserved Routes"
The web UI app uses the following routes which should not be overwritten:

- `/` and `/{id}` - Serves the chat UI
- `/api/chat` - Chat endpoint (POST, OPTIONS)
- `/api/configure` - Frontend configuration (GET)
- `/api/health` - Health check (GET)

The app cannot currently be mounted at a subpath (e.g., `/chat`) because the UI expects these routes at the root. You can add additional routes to the app, but avoid conflicts with these reserved paths.

## MCP Server Configuration

You can enable [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) servers using a JSON configuration file:

```bash
clai web --agent my_agent:my_agent --mcp mcp-servers.json
```

Example JSON configuration:

```json
{
"mcpServers": {
"deepwiki": {
"url": "https://mcp.deepwiki.com/mcp"
},
"github": {
"url": "https://api.githubcopilot.com/mcp",
"authorizationToken": "${GITHUB_TOKEN}"
}
}
}
```

Environment variables can be referenced using `${VAR_NAME}` syntax, with optional defaults: `${VAR_NAME:-default_value}`.

Each server entry supports:

| Field | Description |
|-------|-------------|
| `url` (required) | The MCP server URL |
| `authorizationToken` | Authorization token for the server |
| `description` | Description shown in the UI |
| `allowedTools` | List of allowed tool names |
| `headers` | Additional HTTP headers |

## Builtin Tool Support
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list of options should be much further up, or we should link to it from there.

Also this should be int he CLI docs, no? When using to_web, the user will pass in the instances as normal

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optimally, we would've separated the bash cli and python to_web() inits o the to_web would take all its arguments directly from the agent, but since both are using the same api now the user can call the to_web with the strings as well. I'll link to each Tool's API docs to make clear these are actual tool classes.

as to much further up, the doc will probably be a lot shorter when I push, but let me know if you'd still want to move these up after that


When using the new models API, builtin tool support is automatically determined from each model's profile. The UI will only show tools that the selected model supports.

Available builtin tools:

- `web_search` - Web search capability
- `code_execution` - Code execution in a sandbox
- `image_generation` - Image generation
- `web_fetch` - Fetch content from URLs
- `memory` - Persistent memory across conversations

!!! note "Memory Tool Requirements"
The `memory` tool requires the agent to have memory configured via the
`memory` parameter when creating the agent. It cannot be enabled via
the CLI `-t memory` flag alone - an agent with memory must be provided
via `--agent`.
Loading