mu-agent 0.1.7 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +34 -29
- package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
- package/dist/bundle/chunks/anthropic.js +2 -2
- package/dist/bundle/chunks/azure-openai-responses-Y4BBWQ3N.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +12 -9
- package/dist/bundle/chunks/{chunk-TRDNDS6A.js → chunk-3V45WARH.js} +6 -3
- package/dist/bundle/chunks/{chunk-XDUWOHPL.js → chunk-5AGIVGSV.js} +3 -3
- package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
- package/dist/bundle/chunks/chunk-7CBJINYJ.js +20 -0
- package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-7DDKXS2Q.js} +1 -1
- package/dist/bundle/chunks/chunk-BSS6T6KQ.js +2 -0
- package/dist/bundle/chunks/chunk-CF5GWZHW.js +31 -0
- package/dist/bundle/chunks/chunk-DNNHZBQR.js +4 -0
- package/dist/bundle/chunks/chunk-FN6OEZYR.js +2 -0
- package/dist/bundle/chunks/chunk-FTJT2X6E.js +2 -0
- package/dist/bundle/chunks/chunk-HZNN636Z.js +130 -0
- package/dist/bundle/chunks/{chunk-4L3WN2XY.js → chunk-JXWJOIH4.js} +1 -1
- package/dist/bundle/chunks/{chunk-4O2SCVYF.js → chunk-KIDDRTZP.js} +4 -4
- package/dist/bundle/chunks/chunk-LMNWTX2L.js +11 -0
- package/dist/bundle/chunks/chunk-LPXNMA2W.js +2 -0
- package/dist/bundle/chunks/{chunk-6CYCI3EJ.js → chunk-LVVZS2NO.js} +1 -1
- package/dist/bundle/chunks/chunk-NN4BEPYX.js +2 -0
- package/dist/bundle/chunks/chunk-O7IPTASE.js +1221 -0
- package/dist/bundle/chunks/chunk-PMRZO46Y.js +2 -0
- package/dist/bundle/chunks/chunk-QOEEJKS4.js +9 -0
- package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
- package/dist/bundle/chunks/chunk-RAQ6TU76.js +2 -0
- package/dist/bundle/chunks/chunk-RDZVAGPR.js +2 -0
- package/dist/bundle/chunks/chunk-SGOTYFMT.js +91 -0
- package/dist/bundle/chunks/chunk-TMTOQ7H7.js +2 -0
- package/dist/bundle/chunks/chunk-UKVNB6C4.js +2 -0
- package/dist/bundle/chunks/chunk-VJLOQZKR.js +9 -0
- package/dist/bundle/chunks/chunk-WCGU75WO.js +11 -0
- package/dist/bundle/chunks/chunk-X234222Q.js +64 -0
- package/dist/bundle/chunks/cli-722OL3K5.js +51 -0
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
- package/dist/bundle/chunks/codemode-worker.js +478 -0
- package/dist/bundle/chunks/easter-egg-3d-6H34EDGX.js +2 -0
- package/dist/bundle/chunks/execute-KVSEIDWL.js +499 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-C44KRRZ4.js → google-generative-ai-D2VJQBTK.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-25DUXPTJ.js → google-vertex-SQG2BO6C.js} +1 -1
- package/dist/bundle/chunks/https-proxy-agent-LVOO5TPL.js +13 -0
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{jiti-loader-C3NU2SDH.js → jiti-loader-GL4HJFAD.js} +1 -1
- package/dist/bundle/chunks/{jiti-static-loader-E6ANQD5T.js → jiti-static-loader-2RCDI6B4.js} +1 -1
- package/dist/bundle/chunks/{lib-HGQMNYVT.js → lib-4AVRLBHM.js} +2 -2
- package/dist/bundle/chunks/llama-cpp-classify-5YHLY3RC.js +22 -0
- package/dist/bundle/chunks/mistral-conversations-BDARVJTT.js +5 -0
- package/dist/bundle/chunks/{multipart-parser-SQ6GDJL7.js → multipart-parser-FMGQ7342.js} +1 -1
- package/dist/bundle/chunks/{node-TWVVAGPO.js → node-AUOGOBCN.js} +1 -1
- package/dist/bundle/chunks/node-KCMANYC2.js +16 -0
- package/dist/bundle/chunks/openai-chatgpt.js +86 -0
- package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
- package/dist/bundle/chunks/openai-codex.js +2 -2
- package/dist/bundle/chunks/openai-completions-UOA7MELD.js +7 -0
- package/dist/bundle/chunks/openai-decisions-HLM372N6.js +5 -0
- package/dist/bundle/chunks/openai-responses-TII7ZY5X.js +3 -0
- package/dist/bundle/chunks/{openrouter-images-JVEJN44Q.js → openrouter-images-7T452AS5.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +2 -2
- package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
- package/dist/bundle/chunks/radius.js +2 -2
- package/dist/bundle/chunks/runtime-O3ELDOM7.js +2 -0
- package/dist/bundle/chunks/{src-UK77SYZE.js → src-QKGKDFSU.js} +1 -1
- package/dist/bundle/chunks/typesafe-system-one-KNCICMO5.js +2 -0
- package/dist/bundle/chunks/virtual-modules-IKEARUOZ.js +2 -0
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/dist/bundle/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/export-html/template.js +37 -16
- package/dist/modes/interactive/theme/dark.json +60 -73
- package/dist/modes/interactive/theme/light.json +58 -70
- package/dist/modes/interactive/theme/system-theme.d.ts +55 -0
- package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/system-theme.js +546 -0
- package/dist/modes/interactive/theme/system-theme.js.map +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +43 -9
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +121 -79
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.js +105 -0
- package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.js +94 -0
- package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
- package/dist/modes/interactive/theme/theme.d.ts +47 -56
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +149 -143
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/dist/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/docs/cli-integration.md +1 -1
- package/docs/cli.md +78 -13
- package/docs/codemode.md +230 -0
- package/docs/compaction.md +5 -5
- package/docs/configuration.md +2 -0
- package/docs/custom-provider.md +53 -1
- package/docs/docs.json +21 -1
- package/docs/environment-variables.md +5 -3
- package/docs/extensions.md +172 -10
- package/docs/index.md +1 -1
- package/docs/json.md +3 -3
- package/docs/keybindings.md +7 -6
- package/docs/llama-cpp.md +21 -1
- package/docs/mcp.md +272 -0
- package/docs/message-types.md +22 -4
- package/docs/models-configuration.md +187 -0
- package/docs/models.md +100 -2
- package/docs/nvidia-rtx-llama-cpp.md +96 -0
- package/docs/packages.md +1 -1
- package/docs/providers.md +66 -6
- package/docs/quickstart.md +16 -2
- package/docs/rpc-commands.md +9 -3
- package/docs/rpc.md +3 -1
- package/docs/sdk.md +8 -3
- package/docs/security.md +2 -0
- package/docs/session-format.md +5 -1
- package/docs/sessions.md +1 -1
- package/docs/settings.md +30 -8
- package/docs/terminal-setup.md +14 -0
- package/docs/themes.md +31 -7
- package/docs/tui.md +71 -1
- package/docs/usage.md +2 -2
- package/docs/virtual-models.md +114 -0
- package/docs/windows.md +2 -0
- package/examples/README.md +1 -4
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/built-in-tool-renderer.ts +16 -40
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/jev-router.ts +113 -0
- package/examples/extensions/minimal-mode.ts +28 -101
- package/examples/extensions/overlay-test.ts +2 -2
- package/examples/extensions/plan-mode/index.ts +6 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/index.ts +4 -6
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-client.ts +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/examples/sdk/14-codemode-mcp.ts +61 -0
- package/examples/sdk/README.md +2 -1
- package/judge/THIRD_PARTY_NOTICES.md +63 -0
- package/judge/dist/auth.js +169 -123
- package/judge/dist/import.js +36 -30
- package/judge/dist/setup.js +250 -120
- package/judge/manifest.json +1008 -316
- package/judge/{dist/kyrn-judge.js → mu/index.js} +6933 -5995
- package/judge/themes/mu-dark.json +80 -0
- package/judge/themes/mu-light.json +80 -0
- package/kyrn/bin/kyrn-doctor +75 -25
- package/kyrn/bin/kyrn-judge-local +2 -2
- package/kyrn/bin/kyrn-ledger +1 -1
- package/kyrn/bin/mu.mjs +149 -107
- package/package.json +4 -5
- package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +0 -6
- package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +0 -2
- package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
- package/dist/bundle/chunks/chunk-AYFRR3OD.js +0 -2
- package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +0 -42
- package/dist/bundle/chunks/chunk-FU4XQUSL.js +0 -11
- package/dist/bundle/chunks/chunk-GNYZK6XN.js +0 -2
- package/dist/bundle/chunks/chunk-HEMXN7VJ.js +0 -1653
- package/dist/bundle/chunks/chunk-MVPXOVOJ.js +0 -2
- package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
- package/dist/bundle/chunks/chunk-V7IXECST.js +0 -11
- package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +0 -2
- package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
- package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +0 -5
- package/dist/bundle/chunks/node-O3RIBJRH.js +0 -16
- package/dist/bundle/chunks/openai-codex-responses-3UAYOSSR.js +0 -10
- package/dist/bundle/chunks/openai-completions-FIEQGWAH.js +0 -7
- package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +0 -2
- package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +0 -2
- package/dist/bundle/chunks/virtual-modules-V7SXVVLP.js +0 -2
- package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
- package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-json.js +0 -132
- package/dist/modes/interactive/theme/theme-json.js.map +0 -1
- package/dist/modes/interactive/theme/theme-schema.json +0 -361
- package/examples/plugins/pi-example-plugin/README.md +0 -38
- package/examples/plugins/pi-example-plugin/package.json +0 -10
- package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
- package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
- package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# MCP Servers
|
|
2
|
+
|
|
3
|
+
Pi connects to [Model Context Protocol](https://modelcontextprotocol.io) servers over stdio or streamable HTTP and makes their tools and resources available to the model.
|
|
4
|
+
|
|
5
|
+
## Quick setup
|
|
6
|
+
|
|
7
|
+
Add a local stdio server, check the connection, then start Pi:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pi mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem .
|
|
11
|
+
pi mcp list
|
|
12
|
+
pi
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
For a remote server:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pi mcp add docs --url https://example.com/mcp --bearer-token-env-var DOCS_TOKEN
|
|
19
|
+
pi mcp list
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
These commands add user-level servers by default. Add `--local` or `-l` to write the project configuration instead:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pi mcp add -l tools --env API_KEY='${TOOLS_KEY}' -- uvx tools-mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use `/mcp` inside an interactive session to inspect connections, sign in, reconnect, change exposure, or enable and disable servers. Run `/reload` after adding, removing, or changing a server outside the session.
|
|
29
|
+
|
|
30
|
+
## Configure servers
|
|
31
|
+
|
|
32
|
+
Pi reads user-level servers from `~/.pi/agent/mcp.json` and project servers from `.pi/mcp.json`. Project configuration is read only after [project trust](security.md#understand-project-trust) is granted. A project entry replaces a user-level entry with the same name.
|
|
33
|
+
|
|
34
|
+
A project entry without `command`, `url`, or `type` overrides only `enabled`, `exposure`, and `toolExposure` of the user-level server with the same name and keeps the rest, including `env`, `headers`, and `auth`. For example, this turns off a user-level server in one project:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"internal-tools": { "enabled": false }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The format matches other MCP clients:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"filesystem": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
|
52
|
+
},
|
|
53
|
+
"docs": {
|
|
54
|
+
"url": "https://example.com/mcp",
|
|
55
|
+
"headers": { "Authorization": "Bearer ${DOCS_TOKEN}" },
|
|
56
|
+
"description": "Search and read the product documentation"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Stdio servers use `command`, `args`, `env`, and `cwd`. Relative `cwd` values resolve against the session directory. A leading `~/` in `command`, an argument, or `cwd` names the home directory.
|
|
63
|
+
|
|
64
|
+
HTTP servers use `url`, `headers`, and `oauth` (see [Authenticate with OAuth](#authenticate-with-oauth)). The legacy SSE transport is not supported.
|
|
65
|
+
|
|
66
|
+
Both server types support:
|
|
67
|
+
|
|
68
|
+
- `timeout`: per-request timeout in seconds (default 60). Progress notifications reset it.
|
|
69
|
+
- `enabled: false`: keep the entry without connecting to it.
|
|
70
|
+
- `exposure` and `toolExposure`: control how tools reach the model (see [Control tool exposure](#control-tool-exposure)).
|
|
71
|
+
- `description`: what the server offers, in a sentence. It lists the server in the system prompt (see [Control tool exposure](#control-tool-exposure)), tool search ranks the server's tools by it, and codemode's `describeNamespace()` returns it. Without it, the first line of the server instructions is used once the server connects.
|
|
72
|
+
|
|
73
|
+
Keep personal servers and servers with credentials in the user-level file. Use the project file only for servers the project requires, and only in trusted projects.
|
|
74
|
+
|
|
75
|
+
### Configuration rules
|
|
76
|
+
|
|
77
|
+
- Server names may contain only letters, digits, `_`, and `-`. Tools are named `mcp__<server>__<tool>`, with every character other than letters, digits, and `_` replaced by `_`; tools of a server whose names then collide all get a hash suffix. Server names that differ only in `-` and `_` count as the same server: a second one is rejected, and a `mcp.json` server overrides a registered one.
|
|
78
|
+
- `type` is optional. A `command` selects stdio and a `url` selects streamable HTTP. When present, `type` must be `stdio`, `http`, or `streamable-http`.
|
|
79
|
+
- `sse` is rejected. Servers that document an SSE endpoint often also provide streamable HTTP, commonly at `/mcp` instead of `/sse`.
|
|
80
|
+
- `command` is one executable and `args` contains its arguments. It is not a shell command string.
|
|
81
|
+
- `env` and `headers` values can use environment variables such as `${GITHUB_TOKEN}`. They can also run a command with `!command`, but the command must make up the whole value, for example `"Authorization": "!echo Bearer $(gh auth token)"`.
|
|
82
|
+
- Invalid entries are reported and skipped without preventing other servers from connecting.
|
|
83
|
+
|
|
84
|
+
`pi mcp add` and `pi mcp remove` cover common changes from a shell. See [MCP commands](cli.md#mcp-commands) for their options.
|
|
85
|
+
|
|
86
|
+
### Inspect or change a server
|
|
87
|
+
|
|
88
|
+
`/mcp` lists configured servers with their state, tool count, exposure, and configuration source. Servers that need attention appear first. Select a server to inspect its tools and connection details, reconnect, sign in or out, change exposure, or enable and disable it.
|
|
89
|
+
|
|
90
|
+
Exposure and enabled-state changes are saved to the file that defines the server without replacing unrelated content. In a trusted project, "Enable in this project" and "Disable in this project" add a project override for a user-level server; later changes to that server are saved to the override. Disabled servers remain listed. Outside the interactive TUI, `/mcp` prints server status; `/mcp login <server>`, `/mcp logout <server>`, and `/mcp reconnect <server>` perform those actions directly.
|
|
91
|
+
|
|
92
|
+
Shell commands work without a session: `pi mcp add`, `pi mcp remove`, `pi mcp list`, `pi mcp login`, and `pi mcp logout`. Shell commands do not load extensions.
|
|
93
|
+
|
|
94
|
+
### Diagnose connection problems
|
|
95
|
+
|
|
96
|
+
Run `pi mcp list` to connect to every enabled server and print its state, tools, and errors. It exits with status 1 when an entry is invalid or an enabled server is not connected. `/mcp` shows the full connection error and the tail of stderr from a failed stdio server.
|
|
97
|
+
|
|
98
|
+
Pi reports configuration errors, failed connections, and required sign-ins once after startup. Server logging notifications are appended to `~/.pi/agent/mcp.log` as `<time> [<server>] <level> <logger>: <message>`. The file moves to `mcp.log.1` after it grows past 5 MB.
|
|
99
|
+
|
|
100
|
+
Pi connects every enabled server in the background when a session starts. A server's tools appear once it connects; the `codemode` description does not list them, so it does not change when servers connect. The first prompt waits up to 10 seconds only for servers with `direct` tools, which must be declared in its request. Other servers are waited for when they are needed: a codemode script waits for the servers it names (`mcp__<server>`) and, when it calls `searchTools()` or reads `ALL_TOOLS`, for all of them; `tool_search` and the resource tools also wait for all of them. HTTP network errors and transient statuses (408, 429, and 5xx) are retried twice. A dropped connection is shown as disconnected and reconnects on the next call. When a server announces a changed tool list, new tools are added and withdrawn tools become unreachable.
|
|
101
|
+
|
|
102
|
+
Stopping a stdio server closes its stdin, sends SIGTERM, then sends SIGKILL to its process group. This also stops servers launched through wrappers such as `npx` or `uvx`.
|
|
103
|
+
|
|
104
|
+
## Migrate configuration from another client
|
|
105
|
+
|
|
106
|
+
Move the converted entry under `mcpServers` in `mcp.json`, then run `pi mcp list` to validate it.
|
|
107
|
+
|
|
108
|
+
| Client | Conversion |
|
|
109
|
+
|---|---|
|
|
110
|
+
| Claude Desktop, Claude Code, or Cursor | Copy the existing `mcpServers` entry. |
|
|
111
|
+
| VS Code | Move an entry from the top-level `servers` object and replace `${input:...}` prompts with `${NAME}` environment variables. |
|
|
112
|
+
| Codex | Convert `[mcp_servers.<name>]` TOML fields such as `command`, `args`, `env`, and `url` to JSON. |
|
|
113
|
+
| OpenCode | Convert `"type": "local"` to a stdio entry, split its `command` array into `command` and `args`, rename `environment` to `env`, and replace `{env:NAME}` with `${NAME}`. Convert `"type": "remote"` to a URL entry. |
|
|
114
|
+
|
|
115
|
+
## Authenticate with OAuth
|
|
116
|
+
|
|
117
|
+
Remote servers that use OAuth, such as Sentry, need no credentials in `mcp.json`:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"mcpServers": {
|
|
122
|
+
"sentry": { "url": "https://mcp.sentry.dev/mcp" }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
When the server rejects an unauthenticated connection, `/mcp` shows that it needs sign-in. Select "Sign in", run `/mcp login sentry`, or run `pi mcp login sentry`. Pi opens the authorization page and waits for approval. If the browser runs on another machine, such as over SSH, paste its redirected URL into the sign-in screen. A running session uses the new credentials on its next turn.
|
|
128
|
+
|
|
129
|
+
Pi registers itself with the authorization server, stores tokens in `~/.pi/agent/mcp-auth.json`, and refreshes access tokens when they expire or the server rejects them. If a server later requests additional scope, Pi asks for sign-in again. Signing out deletes the stored credentials.
|
|
130
|
+
|
|
131
|
+
Credentials belong to a server name and URL. Servers with the same URL under different names, such as one per account, sign in separately; servers with the same name and URL in different `mcp.json` files share one sign-in.
|
|
132
|
+
|
|
133
|
+
OAuth applies to HTTP servers without an `Authorization` header. For a server that does not support dynamic client registration, configure a registered client:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mcpServers": {
|
|
138
|
+
"example": {
|
|
139
|
+
"url": "https://mcp.example.com/mcp",
|
|
140
|
+
"oauth": { "clientId": "my-client", "clientSecret": "${EXAMPLE_SECRET}", "callbackPort": 8765 }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The redirect URI must match the registered URI. `callbackPort` uses `http://127.0.0.1:<port>/callback`. To use another URI, set `callbackUrl`; it must use HTTP on `localhost`, `127.0.0.1`, or `[::1]`. Pi sends it exactly as written. When `callbackUrl` omits a port, Pi uses `callbackPort` or a free port and adds it to the URI, as allowed for loopback redirects by RFC 8252. `clientSecret` is optional and can use an environment variable or command.
|
|
147
|
+
|
|
148
|
+
Set `scope` to a space-separated list for servers that do not advertise their required scopes. Otherwise, Pi requests the advertised scopes. Later scope requests are added to the configured value.
|
|
149
|
+
|
|
150
|
+
Pi registers as `pi`. Some servers only accept registrations from known clients. Set `clientName` to send another name:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"mcpServers": {
|
|
155
|
+
"figma": { "url": "https://mcp.figma.com/mcp", "oauth": { "clientName": "Claude Code" } }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The name is only sent when Pi registers a client. To register again under a new name, sign out first.
|
|
161
|
+
|
|
162
|
+
Some authorization servers allow clients by their Client ID Metadata Document URL instead of registering them. Set `clientRegistration` to `cimd` to identify as Pi's document on pi.dev instead of registering:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"mcpServers": {
|
|
167
|
+
"example": { "url": "https://mcp.example.com/mcp", "oauth": { "clientRegistration": "cimd" } }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The client ID is `https://pi.dev/oauth/client.json` with the redirect URI `http://127.0.0.1:<port>/callback`. If the authorization server does not send the `iss` parameter in authorization responses (RFC 9207), Pi uses a document and redirect path specific to the MCP server instead: `https://pi.dev/oauth/<id>/client.json` with `http://127.0.0.1:<port>/callback/<id>`. The authorization server must advertise Client ID Metadata Document support and public clients, or sign-in fails. `cimd` cannot be combined with `clientId` or `clientName`, and a `callbackUrl` must use `localhost` or `127.0.0.1` with the path `/callback`.
|
|
173
|
+
|
|
174
|
+
Pi finds the authorization server through the server's protected resource metadata (RFC 9728) and checks that the authorization server's metadata names the expected issuer (RFC 8414). Some servers advertise the wrong authorization server or none, so sign-in opens a page that does not exist. Set `authServerMetadataUrl` to the metadata document of the right authorization server:
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"mcpServers": {
|
|
179
|
+
"example": {
|
|
180
|
+
"url": "https://mcp.example.com/mcp",
|
|
181
|
+
"oauth": { "authServerMetadataUrl": "https://example.okta.com/.well-known/openid-configuration" }
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Pi uses that document instead of discovery and trusts it as configured, so only point it at a document you trust. The URL must use HTTPS, except on `localhost`, `127.0.0.1`, or `[::1]`.
|
|
188
|
+
|
|
189
|
+
## Control tool exposure
|
|
190
|
+
|
|
191
|
+
Each server tool is registered as `mcp__<server>__<tool>`. The server's `exposure` determines how the model reaches it:
|
|
192
|
+
|
|
193
|
+
| Exposure | Behavior | Typical use |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `codemode` (default) | Callable from [`codemode`](cli.md#tools) scripts, but neither declared to the model nor listed in the codemode description. Scripts find tools with `searchTools()`, `describeTool()`, or `ALL_TOOLS`. | General MCP servers, especially when scripts should combine or filter calls. |
|
|
196
|
+
| `deferred` | Not declared until [`tool_search`](cli.md#tools) loads a match for the next model call. | Large servers whose tools should be called directly after discovery. |
|
|
197
|
+
| `direct` | Declared to the model like a built-in tool and also callable from codemode. | Small, frequently used tool sets. |
|
|
198
|
+
| `hidden` | Registered but unreachable. | Servers or tools that should remain unavailable. |
|
|
199
|
+
|
|
200
|
+
`codemode-deferred` is accepted as an alias for `codemode`.
|
|
201
|
+
|
|
202
|
+
Servers with `codemode` or `deferred` tools are listed in the `mcp_servers` section of the system prompt, with how their tools are reached and one line from the configured `description` or, once connected, from the server instructions. Pi updates the section when a prompt starts, after waiting for servers with `direct` tools. When it changed, for example because a server connected and its summary became available, Pi appends the new section to the conversation instead of changing tool declarations, so earlier messages stay cached. `describeNamespace()` and the `namespace` option of `searchTools()` accept `mcp__dev-radius`, `mcp__dev_radius`, `dev-radius`, or `dev_radius`.
|
|
203
|
+
|
|
204
|
+
Pi activates `codemode` when a server with `codemode` exposure connects. It activates `tool_search` for a server with `deferred` exposure. To make the model see a tool without searching, give it `direct` exposure with `toolExposure`.
|
|
205
|
+
|
|
206
|
+
`toolExposure` overrides the server exposure for individual tools. Keys are exact server tool names or patterns where `*` matches any characters. Exact names win over patterns; among patterns, the first match wins. A server with `hidden` exposure can expose only selected tools:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"mcpServers": {
|
|
211
|
+
"github": {
|
|
212
|
+
"url": "https://api.githubcopilot.com/mcp/",
|
|
213
|
+
"exposure": "deferred",
|
|
214
|
+
"toolExposure": {
|
|
215
|
+
"search_code": "direct",
|
|
216
|
+
"get_*": "codemode",
|
|
217
|
+
"delete_*": "hidden"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`pi mcp list` marks tools whose exposure differs from their server. The Tools view in `/mcp` also shows the effective exposure.
|
|
225
|
+
|
|
226
|
+
Tools with `codemode` or `deferred` exposure can be reached through either indirect mechanism: codemode scripts can call them, and `tool_search` can load them. Codemode calls do not depend on the active tool set, so they remain available after `/tree`, resume, and fork. Tools loaded by `tool_search` are recorded in the transcript and remain declared on that branch.
|
|
227
|
+
|
|
228
|
+
`--tools` does not remove MCP tools unless one of its entries starts with `mcp__`; `pi --tools read,codemode,'mcp__radius__*'` keeps only the tools of `radius`. `--exclude-tools` accepts the same patterns, and `--no-mcp` disables MCP for one run (see [Tools](cli.md#mcp-tools)).
|
|
229
|
+
|
|
230
|
+
To keep `codemode` active without MCP servers, add `"defaultTools": ["+codemode"]` to [settings](settings.md#tools). To prevent automatic codemode activation, set `"autoEnableCodemode": false` beside `mcpServers`. A project value overrides the user-level value. Pi warns once when neither `codemode` nor `tool_search` is active and non-direct tools cannot be called.
|
|
231
|
+
|
|
232
|
+
Text results over 20 KB reach the model with their middle removed around a `…N chars truncated…` marker. The full text is saved to a temporary file named in the result. Codemode scripts receive the complete result and can reduce it before returning output to the model.
|
|
233
|
+
|
|
234
|
+
Codemode scripts receive the complete MCP `CallToolResult`, including `content`, `structuredContent`, and `isError`. A result with `isError` resolves inside scripts but is reported as an error for direct calls. `image(result.content[0])` forwards an image block. Server instructions are not part of any tool description; scripts read them with `describeNamespace("mcp__<server>")`, which also returns the server's tool names.
|
|
235
|
+
|
|
236
|
+
## Use resources
|
|
237
|
+
|
|
238
|
+
When a connected server offers [resources](https://modelcontextprotocol.io/specification/2025-11-25/server/resources), Pi adds the resource tools used by Codex and OpenCode:
|
|
239
|
+
|
|
240
|
+
- `list_mcp_resources` lists resources as JSON: `{ server?, resources: [{ server, uri, name, ... }], nextCursor? }`. With `server`, it lists one page; `cursor` continues with the next page. Without `server`, it lists every resource from every server.
|
|
241
|
+
- `list_mcp_resource_templates` lists URI templates for resources the servers do not list directly.
|
|
242
|
+
- `read_mcp_resource` reads a resource by `server` and `uri`. Text reaches the model as text and images as images. Other binary resources are saved to temporary files, and the model receives the path. Scripts receive `{ server, uri, contents }`.
|
|
243
|
+
|
|
244
|
+
These tools reach every enabled, non-hidden server with resources. Their exposure is the widest exposure among those servers: `direct`, then `codemode` or `deferred`. Resource links in tool results identify `read_mcp_resource` and the server.
|
|
245
|
+
|
|
246
|
+
Resources for MCP Apps, identified by `ui://` URIs or `text/html;profile=mcp-app`, are omitted because Pi does not render them. Resource icons are also omitted.
|
|
247
|
+
|
|
248
|
+
Reading and listing resources is retried once after a transient HTTP error (408, 429, or 5xx). Tool calls are not retried because the server may already have performed them.
|
|
249
|
+
|
|
250
|
+
## Permissions
|
|
251
|
+
|
|
252
|
+
Every MCP call passes through Pi's tool pipeline. Extension `tool_call` and `tool_result` handlers, including permission gates, therefore apply to MCP tools. Calls made from codemode scripts carry the codemode call ID as `parentToolCallId`.
|
|
253
|
+
|
|
254
|
+
`pi.getAllTools()` reports the annotations declared by each server: `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint`. Permission extensions can use these hints to decide which calls require confirmation (see [Tool exposure](extensions.md#tool-exposure)). Resource tools are marked read-only.
|
|
255
|
+
|
|
256
|
+
## Extensions and SDK
|
|
257
|
+
|
|
258
|
+
### Add servers from extensions
|
|
259
|
+
|
|
260
|
+
Extensions can add servers for the current session with `pi.registerMcpServer(name, config)`, using the same shape as an `mcpServers` entry (see [MCP servers in extensions](extensions.md#mcp-servers)). Registered servers connect like configured servers and appear in `/mcp` with the extension as their source.
|
|
261
|
+
|
|
262
|
+
Changes to enabled state or exposure apply only to the current session. A file-configured server with the same name takes precedence, and `/mcp` lists the overridden registration. `pi mcp` shell commands do not load extensions and only see file-configured servers.
|
|
263
|
+
|
|
264
|
+
### Replace the built-in MCP support
|
|
265
|
+
|
|
266
|
+
An installed extension that registers `/mcp`, such as `pi-mcp-adapter`, replaces the built-in MCP support for sessions. Pi then does not read `mcp.json` or connect its servers in a session, and `/mcp` belongs to the extension. Remove the extension to restore the built-in behavior. To disable built-in MCP support without a replacement, disable `mcp` under Built-in in `pi config`, or set `"extensions": ["-builtin:mcp"]` in [settings](settings.md#resources). `--no-mcp` disables it for one run.
|
|
267
|
+
|
|
268
|
+
An extension that registers `codemode` or `tool_search` similarly replaces the built-in tool with that name. Pi activates the replacement for MCP servers and waits for the servers its calls need only when it declares [`reachesTools`](extensions.md#tool-exposure). Shell-level `pi mcp` commands always use the built-in implementation.
|
|
269
|
+
|
|
270
|
+
### Use MCP from the SDK
|
|
271
|
+
|
|
272
|
+
SDK sessions do not load built-in extensions. Add the MCP extension, the codemode extension for `codemode` servers, and the tool-search extension for `deferred` servers to the resource loader. See [Codemode and MCP](sdk.md#codemode-mcp).
|
package/docs/message-types.md
CHANGED
|
@@ -100,12 +100,11 @@ interface SystemMessage {
|
|
|
100
100
|
sections?: Record<string, string | null>;
|
|
101
101
|
toolsAdded?: Tool[];
|
|
102
102
|
toolsRemoved?: ToolReference[];
|
|
103
|
-
replace?: boolean;
|
|
104
103
|
timestamp: number;
|
|
105
104
|
}
|
|
106
105
|
```
|
|
107
106
|
|
|
108
|
-
The leading system message declares the initial prompt and tools. Later system messages can append instructions, replace or remove named prompt sections, and add or remove tools. Replaying them in order yields the current state.
|
|
107
|
+
The leading system message declares the initial prompt and tools. Later system messages can append instructions, replace or remove named prompt sections, and add or remove tools. Replaying them in order yields the current state.
|
|
109
108
|
|
|
110
109
|
### UserMessage
|
|
111
110
|
|
|
@@ -129,6 +128,7 @@ interface AssistantMessage {
|
|
|
129
128
|
responseModel?: string;
|
|
130
129
|
responseId?: string;
|
|
131
130
|
providerThinkingLevel?: string;
|
|
131
|
+
thinkingLevel?: ModelThinkingLevel;
|
|
132
132
|
diagnostics?: AssistantMessageDiagnostic[];
|
|
133
133
|
usage: Usage;
|
|
134
134
|
stopReason: "pending" | "stop" | "length" | "toolUse" | "error" | "aborted" | "deferred";
|
|
@@ -140,7 +140,7 @@ interface AssistantMessage {
|
|
|
140
140
|
}
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
`responseModel` records a concrete provider response model when it differs from the requested model. `responseId`, `providerThinkingLevel`, `diagnostics`, and `rawStopReason` preserve provider or runtime details.
|
|
143
|
+
`responseModel` records a concrete provider response model when it differs from the requested model. `responseId`, `providerThinkingLevel`, `thinkingLevel`, `diagnostics`, and `rawStopReason` preserve provider or runtime details.
|
|
144
144
|
|
|
145
145
|
`"pending"` is used for a partial assistant message while it streams. The completed message in `message_end` has a terminal stop reason, and Pi does not persist `"pending"` assistant messages in session JSONL.
|
|
146
146
|
|
|
@@ -168,12 +168,30 @@ interface ToolResultMessage<TDetails = any> {
|
|
|
168
168
|
content: (TextContent | ImageContent)[];
|
|
169
169
|
details?: TDetails;
|
|
170
170
|
usage?: Usage;
|
|
171
|
+
nestedCalls?: NestedToolCalls;
|
|
171
172
|
isError: boolean;
|
|
172
173
|
timestamp: number;
|
|
173
174
|
}
|
|
174
175
|
```
|
|
175
176
|
|
|
176
|
-
`details` is tool-specific. Optional `usage` reports nested model work performed by the tool and contributes to full-session statistics, but it is not part of the main model-call usage.
|
|
177
|
+
`details` is tool-specific. Optional `usage` reports nested model work performed by the tool and contributes to full-session statistics, but it is not part of the main model-call usage. `nestedCalls` records bounded metadata about calls this tool made to other tools:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
interface NestedToolCalls {
|
|
181
|
+
calls: NestedToolCallRecord[];
|
|
182
|
+
complete: boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
interface NestedToolCallRecord {
|
|
186
|
+
id: string;
|
|
187
|
+
name: string;
|
|
188
|
+
arguments?: JsonObject;
|
|
189
|
+
argumentsBytes?: number;
|
|
190
|
+
status: "ok" | "error" | "unfinished";
|
|
191
|
+
durationMs?: number;
|
|
192
|
+
error?: string;
|
|
193
|
+
}
|
|
194
|
+
```
|
|
177
195
|
|
|
178
196
|
## Coding-agent messages
|
|
179
197
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Models Configuration
|
|
2
|
+
|
|
3
|
+
<!-- This file is generated from TypeScript source. Do not edit it manually; run npm run generate:references. -->
|
|
4
|
+
|
|
5
|
+
This reference lists the fields of `models.json`. See [Configure a compatible endpoint](models.md#configure-a-compatible-endpoint) for examples and [Configuration](configuration.md#agent-directory) for the file location.
|
|
6
|
+
|
|
7
|
+
Add `"$schema": "https://pi.dev/schemas/models.schema.json"` to `models.json` for editor validation and completion.
|
|
8
|
+
|
|
9
|
+
## Providers
|
|
10
|
+
|
|
11
|
+
Each key under `providers` is a provider ID. A built-in provider ID changes that provider. Any other ID adds a provider, which needs `baseUrl` and an `api` at provider or model level.
|
|
12
|
+
|
|
13
|
+
| Field | Type | Default | Description |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `name` | string | | Display name. |
|
|
16
|
+
| `baseUrl` | string | | API base URL. Also applies to the provider's built-in models. |
|
|
17
|
+
| `apiKey` | string | | Literal key, "$NAME" environment interpolation, or "!command" output. |
|
|
18
|
+
| `api` | string | | API for the provider's models, such as "openai-completions", "openai-responses", "anthropic-messages", or "google-generative-ai". |
|
|
19
|
+
| `oauth` | `"radius"` | | OAuth login flow. Requires baseUrl. |
|
|
20
|
+
| `headers` | object | | Request headers. Values resolve like apiKey. |
|
|
21
|
+
| `compat` | [object](#compatibility) | | Provider and model compatibility overrides. |
|
|
22
|
+
| `authHeader` | boolean | `false` | Whether to send the resolved API key as Authorization: Bearer. |
|
|
23
|
+
| `models` | [`object[]`](#models) | | |
|
|
24
|
+
| `modelOverrides` | [object](#model-overrides) | | |
|
|
25
|
+
|
|
26
|
+
## Models
|
|
27
|
+
|
|
28
|
+
Each `models` entry adds a model to the provider. An entry whose `id` matches an existing model replaces it.
|
|
29
|
+
|
|
30
|
+
| Field | Type | Default | Description |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `id` | string | | Required. Model ID sent to the API. |
|
|
33
|
+
| `name` | string | | Display name, also matched by --model patterns. |
|
|
34
|
+
| `api` | string | | Overrides the provider api. |
|
|
35
|
+
| `baseUrl` | string | | Overrides the provider baseUrl. |
|
|
36
|
+
| `reasoning` | boolean | `false` | Whether the model supports thinking. |
|
|
37
|
+
| `thinkingLevelMap` | object | | Provider value sent for each thinking level. null marks a level unsupported. Levels the model does not map use the provider's default value through high; xhigh and max are unsupported. |
|
|
38
|
+
| `input` | `("text" \| "image")[]` | `["text"]` | |
|
|
39
|
+
| `inputLimits` | [object](#input-limits) | | |
|
|
40
|
+
| `cost` | object | | |
|
|
41
|
+
| `cost.input` | number | | Required. Input cost in USD per million tokens. |
|
|
42
|
+
| `cost.output` | number | | Required. Output cost in USD per million tokens. |
|
|
43
|
+
| `cost.cacheRead` | number | | Required. Cache-read cost in USD per million tokens. |
|
|
44
|
+
| `cost.cacheWrite` | number | | Required. Cache-write cost in USD per million tokens. |
|
|
45
|
+
| `cost.tiers` | `object[]` | | Request-wide pricing tiers. The highest matching input threshold applies to the full request. |
|
|
46
|
+
| `cost.tiers[].inputTokensAbove` | number | | Required. Use this tier when total request input exceeds this token count. |
|
|
47
|
+
| `cost.tiers[].input` | number | | Required. Input cost in USD per million tokens. |
|
|
48
|
+
| `cost.tiers[].output` | number | | Required. Output cost in USD per million tokens. |
|
|
49
|
+
| `cost.tiers[].cacheRead` | number | | Required. Cache-read cost in USD per million tokens. |
|
|
50
|
+
| `cost.tiers[].cacheWrite` | number | | Required. Cache-write cost in USD per million tokens. |
|
|
51
|
+
| `promptCache` | object | | Best-effort prompt cache lifetime in seconds for the short and long retention tiers. Pi warms only tiers with a known lifetime. |
|
|
52
|
+
| `contextWindow` | number | `128000` | Context window in tokens. |
|
|
53
|
+
| `maxTokens` | number | `16384` | Maximum output tokens. |
|
|
54
|
+
| `samplingParams` | object | | Fields merged into every request body. Applies only to OpenAI-compatible APIs. |
|
|
55
|
+
| `samplingParamsByThinkingLevel` | object | | samplingParams per thinking level, merged over samplingParams. |
|
|
56
|
+
| `headers` | object | | Request headers. Values resolve like apiKey. |
|
|
57
|
+
| `compat` | [object](#compatibility) | | Provider and model compatibility overrides. |
|
|
58
|
+
|
|
59
|
+
## Model overrides
|
|
60
|
+
|
|
61
|
+
Each `modelOverrides` key is the ID of a built-in or extension model. Unknown IDs are ignored. Object fields, such as `cost`, merge with the model's value field by field; other fields replace it.
|
|
62
|
+
|
|
63
|
+
| Field | Type | Default | Description |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `name` | string | | Display name, also matched by --model patterns. |
|
|
66
|
+
| `reasoning` | boolean | | Whether the model supports thinking. |
|
|
67
|
+
| `thinkingLevelMap` | object | | Provider value sent for each thinking level. null marks a level unsupported. Levels the model does not map use the provider's default value through high; xhigh and max are unsupported. |
|
|
68
|
+
| `input` | `("text" \| "image")[]` | | |
|
|
69
|
+
| `inputLimits` | [object](#input-limits) | | |
|
|
70
|
+
| `cost` | object | | |
|
|
71
|
+
| `cost.input` | number | | Input cost in USD per million tokens. |
|
|
72
|
+
| `cost.output` | number | | Output cost in USD per million tokens. |
|
|
73
|
+
| `cost.cacheRead` | number | | Cache-read cost in USD per million tokens. |
|
|
74
|
+
| `cost.cacheWrite` | number | | Cache-write cost in USD per million tokens. |
|
|
75
|
+
| `cost.tiers` | `object[]` | | Request-wide pricing tiers. The highest matching input threshold applies to the full request. |
|
|
76
|
+
| `cost.tiers[].inputTokensAbove` | number | | Required. Use this tier when total request input exceeds this token count. |
|
|
77
|
+
| `cost.tiers[].input` | number | | Required. Input cost in USD per million tokens. |
|
|
78
|
+
| `cost.tiers[].output` | number | | Required. Output cost in USD per million tokens. |
|
|
79
|
+
| `cost.tiers[].cacheRead` | number | | Required. Cache-read cost in USD per million tokens. |
|
|
80
|
+
| `cost.tiers[].cacheWrite` | number | | Required. Cache-write cost in USD per million tokens. |
|
|
81
|
+
| `promptCache` | object | | Best-effort prompt cache lifetime in seconds for the short and long retention tiers. Pi warms only tiers with a known lifetime. |
|
|
82
|
+
| `contextWindow` | number | | Context window in tokens. |
|
|
83
|
+
| `maxTokens` | number | | Maximum output tokens. |
|
|
84
|
+
| `samplingParams` | object | | Fields merged into every request body. Applies only to OpenAI-compatible APIs. |
|
|
85
|
+
| `samplingParamsByThinkingLevel` | object | | samplingParams per thinking level, merged over samplingParams. |
|
|
86
|
+
| `headers` | object | | Request headers. Values resolve like apiKey. |
|
|
87
|
+
| `compat` | [object](#compatibility) | | Provider and model compatibility overrides. |
|
|
88
|
+
|
|
89
|
+
## Input limits
|
|
90
|
+
|
|
91
|
+
See [Describe model input and caching](models.md#describe-model-input-and-caching).
|
|
92
|
+
|
|
93
|
+
| Field | Type | Default | Description |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| `maxRequestBytes` | integer | | Maximum serialized provider request size in bytes. |
|
|
96
|
+
| `images` | object | | |
|
|
97
|
+
| `images.resize` | object | | Cache-safe resize profile applied before a new image enters conversation history. |
|
|
98
|
+
| `images.resize.maxWidth` | integer | | |
|
|
99
|
+
| `images.resize.maxHeight` | integer | | |
|
|
100
|
+
| `images.resize.maxBytes` | integer | | Maximum base64-encoded payload size in bytes. |
|
|
101
|
+
| `images.resize.jpegQuality` | integer | | |
|
|
102
|
+
| `images.maxPerMessage` | integer | | Maximum images accepted in one provider message. |
|
|
103
|
+
| `images.maxPerRequest` | integer | | Maximum images accepted across one provider request. |
|
|
104
|
+
|
|
105
|
+
## Compatibility
|
|
106
|
+
|
|
107
|
+
`compat` describes verified differences from an API's standard request and response behavior. Model values override provider values per field. The fields that apply depend on the model's `api`.
|
|
108
|
+
|
|
109
|
+
### `openai-completions`
|
|
110
|
+
|
|
111
|
+
| Field | Type | Default | Description |
|
|
112
|
+
|---|---|---|---|
|
|
113
|
+
| `supportsStore` | boolean | | Whether the provider supports the store field. Default: auto-detected from URL. |
|
|
114
|
+
| `supportsDeveloperRole` | boolean | | Whether the provider supports the developer role instead of system. Default: auto-detected from URL. |
|
|
115
|
+
| `supportsReasoningEffort` | boolean | | Whether the provider supports reasoning_effort. Default: auto-detected from URL. |
|
|
116
|
+
| `supportsUsageInStreaming` | boolean | `true` | Whether the provider supports stream_options.include_usage for token usage in streaming responses. |
|
|
117
|
+
| `supportsFinishReason` | boolean | `true` | Whether streamed responses include finish_reason. When false, pi infers stop or toolUse when the stream ends. |
|
|
118
|
+
| `maxTokensField` | `"max_completion_tokens" \| "max_tokens"` | | Which field to use for max tokens. Default: auto-detected from URL. |
|
|
119
|
+
| `requiresToolResultName` | boolean | | Whether tool results require the name field. Default: auto-detected from URL. |
|
|
120
|
+
| `requiresAssistantAfterToolResult` | boolean | | Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. |
|
|
121
|
+
| `requiresThinkingAsText` | boolean | | Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. |
|
|
122
|
+
| `requiresReasoningContentOnAssistantMessages` | boolean | | Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL. |
|
|
123
|
+
| `thinkingFormat` | `"openai" \| "openrouter" \| "deepseek" \| "together" \| "baseten" \| "zai" \| "qwen" \| "chat-template" \| "qwen-chat-template" \| "string-thinking" \| "ant-ling"` | | Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, "string-thinking" uses top-level thinking, and "ant-ling" uses reasoning.effort only when the mapped effort is non-null. |
|
|
124
|
+
| `chatTemplateKwargs` | object | | Kwargs sent as chat_template_kwargs when thinkingFormat is "chat-template". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values. |
|
|
125
|
+
| `chatTemplateArgs` | object | | Arguments sent as chat_template_args when thinkingFormat is "baseten". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values. |
|
|
126
|
+
| `openRouterRouting` | object | | OpenRouter provider routing preferences. Controls which upstream providers OpenRouter routes requests to. Sent as the provider field in the OpenRouter API request body. See https://openrouter.ai/docs/guides/routing/provider-selection. |
|
|
127
|
+
| `vercelGatewayRouting` | object | | Vercel AI Gateway routing preferences. Controls which upstream providers the gateway routes requests to. See https://vercel.com/docs/ai-gateway/models-and-providers/provider-options. |
|
|
128
|
+
| `zaiToolStream` | boolean | `false` | Whether z.ai supports top-level tool_stream for streaming tool call deltas. |
|
|
129
|
+
| `thinkingTokenBudgetField` | `"thinking_token_budget" \| "thinking_budget" \| "thinking_budget_tokens"` | | Top-level request field used to cap reasoning tokens from thinkingBudgets. Reasoning and the answer share max_tokens on these endpoints. "thinking_token_budget" is vLLM, "thinking_budget" is Qwen, DashScope, or SGLang, and "thinking_budget_tokens" is llama.cpp. Off by default and not set on the generated catalog. |
|
|
130
|
+
| `supportsThinkingTokenBudget` | boolean | `false` | Alias for thinkingTokenBudgetField: "thinking_token_budget" (vLLM). Prefer thinkingTokenBudgetField. |
|
|
131
|
+
| `supportsOpenAIGrammarTools` | boolean | `false` | Whether the provider supports OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools. The generated catalog enables this for capable models. |
|
|
132
|
+
| `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system or developer messages after the conversation has started. When false, later system messages are folded into the leading system message. The generated catalog enables this for verified models. |
|
|
133
|
+
| `supportsMidConvoToolAdditions` | boolean | `false` | Whether system messages can introduce additional tools mid-conversation. Requires supportsMidConvoSystemMessages. The generated catalog enables this for capable models. |
|
|
134
|
+
| `supportsStrictMode` | boolean | `false` | Whether the provider supports the strict field in tool definitions. Generated capable models enable it explicitly. |
|
|
135
|
+
| `cacheControlFormat` | `"anthropic"` | | Cache control convention for prompt caching. Anthropic applies cache_control markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content. |
|
|
136
|
+
| `sendSessionAffinityHeaders` | boolean | | Whether to send session-affinity data from options.sessionId. Default: true for OpenRouter endpoints, false otherwise. |
|
|
137
|
+
| `sessionAffinityFormat` | `"openai" \| "openai-nosession" \| "openrouter"` | | Session-affinity header format. openai sends session_id, x-client-request-id, and x-session-affinity; openai-nosession sends x-client-request-id and x-session-affinity; openrouter sends x-session-id. Does not affect prompt_cache_key. Default: auto-detected. |
|
|
138
|
+
| `supportsLongCacheRetention` | boolean | | Whether the provider supports long prompt cache retention (prompt_cache_retention: "24h" or Anthropic-style cache_control.ttl: "1h", depending on format). Default: auto-detected from provider and URL. |
|
|
139
|
+
| `vllmPriority` | number | | vLLM scheduler priority sent as the top-level priority request field. Lower values are handled earlier and the server default is 0. Only meaningful with --scheduling-policy priority. Off by default and not set on the generated catalog. |
|
|
140
|
+
|
|
141
|
+
### `openai-responses`
|
|
142
|
+
|
|
143
|
+
Also applies to `azure-openai-responses` and `openai-codex-responses`.
|
|
144
|
+
|
|
145
|
+
| Field | Type | Default | Description |
|
|
146
|
+
|---|---|---|---|
|
|
147
|
+
| `supportsDeveloperRole` | boolean | `true` | Whether the provider supports the developer role instead of system. |
|
|
148
|
+
| `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts developer or system messages after the conversation has started. When false, later system messages are folded into the leading system message. The generated catalog enables this for verified models. |
|
|
149
|
+
| `sessionAffinityFormat` | `"openai" \| "openai-nosession" \| "openrouter"` | | Session-affinity header format. openai sends session_id and x-client-request-id; openai-nosession sends x-client-request-id; openrouter sends x-session-id. Does not affect prompt_cache_key. Default: auto-detected. |
|
|
150
|
+
| `supportsLongCacheRetention` | boolean | `true` | Whether the provider supports long prompt cache retention. This uses prompt_cache_options.ttl: "30m" on GPT-5.6+ and prompt_cache_retention: "24h" on earlier models. |
|
|
151
|
+
| `supportsStrictMode` | boolean | | Whether the provider supports strict JSON-schema function tools. Defaults are API-specific; generated OpenAI models enable it explicitly. |
|
|
152
|
+
| `supportsOpenAIGrammarTools` | boolean | `false` | Whether to emit OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools. The generated catalog enables this for capable models. |
|
|
153
|
+
| `supportsAdditionalTools` | boolean | `false` | Whether the model supports message-anchored additional_tools input items. |
|
|
154
|
+
| `supportsToolSearch` | boolean | `false` | Whether the model supports client-executed tool search for transcript-anchored additions. |
|
|
155
|
+
| `supportsExplicitPromptCacheMode` | boolean | `false` | Whether the model accepts prompt_cache_options. Older OpenAI models reject the parameter. |
|
|
156
|
+
| `supportsMidConvoEffort` | boolean | `false` | Whether thinking level changes are sent as configuration_update input items instead of changing reasoning.effort, so a change keeps the prompt cache. Only used by the openai-responses API, and ignored with Sign in with ChatGPT on the openai provider. |
|
|
157
|
+
| `supportsMaxOutputTokens` | boolean | `true` | Whether the provider accepts max_output_tokens. Some Codex-protocol gateways reject it. |
|
|
158
|
+
|
|
159
|
+
### `anthropic-messages`
|
|
160
|
+
|
|
161
|
+
| Field | Type | Default | Description |
|
|
162
|
+
|---|---|---|---|
|
|
163
|
+
| `supportsEagerToolInputStreaming` | boolean | `true` | Whether the provider accepts per-tool eager_input_streaming. When false, the Anthropic provider omits tools[].eager_input_streaming and sends the legacy fine-grained-tool-streaming-2025-05-14 beta header for tool-enabled requests. |
|
|
164
|
+
| `supportsLongCacheRetention` | boolean | `true` | Whether the provider supports Anthropic long cache retention through cache_control.ttl. |
|
|
165
|
+
| `sendSessionAffinityHeaders` | boolean | | Whether to send x-session-affinity from options.sessionId when caching is enabled. Required for providers like Fireworks that use session affinity for prompt cache routing; requests to the same replica maximize cache hits. Default: true for OpenRouter endpoints, false otherwise. |
|
|
166
|
+
| `sessionAffinityFormat` | `"openrouter"` | | Session-affinity format. openrouter sends x-session-id; when unset, sends x-session-affinity. |
|
|
167
|
+
| `supportsCacheControlOnTools` | boolean | `true` | Whether the provider supports Anthropic-style cache_control markers on tool definitions. When false, cache_control is omitted from tool parameters. Some Anthropic-compatible providers, such as Fireworks, do not support this field on tools and may reject or ignore it. |
|
|
168
|
+
| `supportsTemperature` | boolean | `true` | Whether the model accepts the Anthropic temperature request field. Claude Opus 4.7+ rejects non-default values. |
|
|
169
|
+
| `forceAdaptiveThinking` | boolean | `false` | Whether to force adaptive thinking (thinking.type: adaptive plus output_config.effort) regardless of model ID. Built-in models that require adaptive thinking set this in generated metadata. Custom Anthropic-compatible providers can set this to true for any model whose upstream requires the adaptive format. Set false to opt out on overridden built-in models. |
|
|
170
|
+
| `allowEmptySignature` | boolean | `false` | Whether to replay empty thinking signatures instead of converting thinking to text. |
|
|
171
|
+
| `supportsStrictTools` | boolean | `false` | Whether the provider supports Anthropic strict tool schemas. Generated Anthropic models enable it explicitly. |
|
|
172
|
+
| `supportsMidConvoEffort` | boolean | `false` | Whether the exact model transport supports effort-only system messages and thinking binding controls. |
|
|
173
|
+
| `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system-role messages inside the conversation. When false, later system messages are folded into the top-level system prompt. |
|
|
174
|
+
| `supportsMidConvoToolChanges` | boolean | `false` | Whether the exact model accepts mid-conversation tool_addition and tool_removal blocks. Requires supportsMidConvoSystemMessages. |
|
|
175
|
+
| `allowedFallbackModels` | `object[]` | | Models Anthropic accepts for server-side refusal fallback, with local pricing metadata for returned fallback responses. When absent or empty, callers must omit fallbacks; Anthropic rejects the field for models with no permitted fallback targets. |
|
|
176
|
+
|
|
177
|
+
### `bedrock-converse-stream`
|
|
178
|
+
|
|
179
|
+
| Field | Type | Default | Description |
|
|
180
|
+
|---|---|---|---|
|
|
181
|
+
| `supportsStrictMode` | boolean | `false` | Whether the model supports Bedrock strict tool schemas. |
|
|
182
|
+
|
|
183
|
+
### `mistral-conversations`
|
|
184
|
+
|
|
185
|
+
| Field | Type | Default | Description |
|
|
186
|
+
|---|---|---|---|
|
|
187
|
+
| `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system messages after the conversation has started. When false, later system messages are folded into the leading system message. |
|