@earendil-works/pi-coding-agent 0.81.0 → 0.82.0
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 +59 -0
- package/README.md +13 -0
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session.d.ts +33 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +37 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +5 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +5 -7
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +13 -4
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +29 -17
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +4 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +5 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-config.d.ts +30 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +6 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +7 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +0 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +3 -5
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +5 -10
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +1 -2
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +16 -46
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +58 -46
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +3 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +5 -2
- package/docs/environment-variables.md +88 -0
- package/docs/extensions.md +11 -3
- package/docs/index.md +1 -0
- package/docs/json.md +5 -1
- package/docs/models.md +6 -2
- package/docs/providers.md +8 -1
- package/docs/rpc.md +56 -6
- package/docs/sdk.md +3 -0
- package/docs/settings.md +1 -1
- package/docs/usage.md +0 -13
- package/examples/extensions/custom-compaction.ts +3 -0
- 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/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +9 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +3 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +16 -15
- package/package.json +5 -4
package/docs/custom-provider.md
CHANGED
|
@@ -259,7 +259,7 @@ models: [{
|
|
|
259
259
|
```
|
|
260
260
|
|
|
261
261
|
Use `openrouter` for OpenRouter-style `reasoning: { effort }` controls. Use `together` for Together-style `reasoning: { enabled }` controls; with `supportsReasoningEffort`, it also sends `reasoning_effort`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`.
|
|
262
|
-
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user
|
|
262
|
+
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|
|
263
263
|
|
|
264
264
|
For Anthropic-compatible providers using `api: "anthropic-messages"`, set `compat.forceAdaptiveThinking: true` on models or providers whose upstream model requires adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`). Built-in adaptive Claude models set this automatically. Set `compat.allowEmptySignature: true` only for providers that emit empty thinking signatures and expect `signature: ""` on replay.
|
|
265
265
|
|
|
@@ -737,6 +737,8 @@ interface ProviderModelConfig {
|
|
|
737
737
|
supportsDeveloperRole?: boolean;
|
|
738
738
|
supportsReasoningEffort?: boolean;
|
|
739
739
|
supportsUsageInStreaming?: boolean;
|
|
740
|
+
supportsStrictMode?: boolean;
|
|
741
|
+
supportsOpenAIGrammarTools?: boolean; // openai-completions/openai-responses; false falls back to normal function tools
|
|
740
742
|
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
741
743
|
requiresToolResultName?: boolean;
|
|
742
744
|
requiresAssistantAfterToolResult?: boolean;
|
|
@@ -755,9 +757,10 @@ interface ProviderModelConfig {
|
|
|
755
757
|
supportsCacheControlOnTools?: boolean;
|
|
756
758
|
forceAdaptiveThinking?: boolean;
|
|
757
759
|
allowEmptySignature?: boolean;
|
|
760
|
+
supportsStrictTools?: boolean;
|
|
758
761
|
};
|
|
759
762
|
}
|
|
760
763
|
```
|
|
761
764
|
|
|
762
765
|
`openrouter` sends `reasoning: { effort }`. `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when enabled. `together` sends `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` is for DashScope-style top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`. Use `chat-template` for configurable `chat_template_kwargs`, for example DeepSeek V3.x behind vLLM with `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }`.
|
|
763
|
-
`cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user
|
|
766
|
+
`cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Environment Variables
|
|
2
|
+
|
|
3
|
+
Pi uses environment variables in three ways:
|
|
4
|
+
|
|
5
|
+
- Variables such as `PI_OFFLINE` configure the Pi process.
|
|
6
|
+
- Pi sets `PI_CODING_AGENT` so child processes can detect that they run inside Pi.
|
|
7
|
+
- Commands run by the LLM-callable bash tool receive `PI_*` variables describing the current session.
|
|
8
|
+
|
|
9
|
+
Provider API-key variables are documented separately in [Providers](providers.md#environment-variables-or-auth-file).
|
|
10
|
+
|
|
11
|
+
## Process Marker
|
|
12
|
+
|
|
13
|
+
The CLI and RPC entry points set `PI_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside Pi. It is not session-specific and is not set automatically when Pi is embedded through the SDK.
|
|
14
|
+
|
|
15
|
+
## Bash Tool Session Environment
|
|
16
|
+
|
|
17
|
+
Commands run by the bash tool receive the current Pi session state:
|
|
18
|
+
|
|
19
|
+
| Variable | Description |
|
|
20
|
+
|----------|-------------|
|
|
21
|
+
| `PI_SESSION_ID` | Current session ID |
|
|
22
|
+
| `PI_SESSION_FILE` | Absolute path to the current session JSONL file; unset for ephemeral sessions |
|
|
23
|
+
| `PI_PROVIDER` | Currently selected model provider |
|
|
24
|
+
| `PI_MODEL` | Currently selected model ID |
|
|
25
|
+
| `PI_REASONING_LEVEL` | Current effective reasoning level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` |
|
|
26
|
+
|
|
27
|
+
The values are resolved when each command starts. Switching models or changing the reasoning level therefore affects the next bash command without restarting Pi. `PI_PROVIDER` and `PI_MODEL` identify the selected Pi model, not a different upstream model that a router may choose internally.
|
|
28
|
+
|
|
29
|
+
When asked which model or provider is running, inspect these variables instead of inferring the answer from the system prompt:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
printf '%s/%s\n' "$PI_PROVIDER" "$PI_MODEL"
|
|
33
|
+
printf 'reasoning=%s session=%s\n' "$PI_REASONING_LEVEL" "$PI_SESSION_ID"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The session file can be inspected directly when the session is persistent:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
if [ -n "$PI_SESSION_FILE" ]; then
|
|
40
|
+
tail -n 1 "$PI_SESSION_FILE"
|
|
41
|
+
fi
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
These variables are injected into the LLM-callable bash tool. They are not injected into user-entered `!` or `!!` commands.
|
|
45
|
+
|
|
46
|
+
### Custom Bash Tools
|
|
47
|
+
|
|
48
|
+
Bash tools created with `createBashTool()` expose the session environment by default when registered with Pi. Injection happens before `spawnHook`, so a hook receives the variables in `ctx.env`:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const bashTool = createBashTool(cwd, {
|
|
52
|
+
spawnHook: (ctx) => ({
|
|
53
|
+
...ctx,
|
|
54
|
+
env: { ...ctx.env, CI: "1" },
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Disable session metadata independently of the spawn hook:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const bashTool = createBashTool(cwd, {
|
|
63
|
+
exposeSessionEnvironment: false,
|
|
64
|
+
spawnHook: (ctx) => ctx,
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When disabled, Pi removes inherited values for these variables so nested Pi processes do not expose stale parent-session metadata.
|
|
69
|
+
|
|
70
|
+
## Pi Process Configuration
|
|
71
|
+
|
|
72
|
+
These variables are read by Pi itself:
|
|
73
|
+
|
|
74
|
+
| Variable | Description |
|
|
75
|
+
|----------|-------------|
|
|
76
|
+
| `PI_CODING_AGENT_DIR` | Override the config directory; default is `~/.pi/agent` |
|
|
77
|
+
| `PI_CODING_AGENT_SESSION_DIR` | Override session storage; overridden by `--session-dir` |
|
|
78
|
+
| `PI_PACKAGE_DIR` | Override the package directory, useful for Nix/Guix store paths |
|
|
79
|
+
| `PI_OFFLINE` | Disable startup network operations, including update checks, package updates, and install/update telemetry |
|
|
80
|
+
| `PI_SKIP_VERSION_CHECK` | Disable the `pi.dev` latest-version request |
|
|
81
|
+
| `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no` |
|
|
82
|
+
| `PI_CACHE_RETENTION` | Set to `long` for extended provider prompt caching where supported |
|
|
83
|
+
| `PI_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
|
|
84
|
+
| `PI_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
|
|
85
|
+
| `VISUAL`, `EDITOR` | External editor fallback when `externalEditor` is unset |
|
|
86
|
+
| `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
|
|
87
|
+
|
|
88
|
+
Provider credentials such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and cloud-provider configuration are listed in [Providers](providers.md#environment-variables-or-auth-file).
|
package/docs/extensions.md
CHANGED
|
@@ -982,9 +982,9 @@ ctx.sessionManager.buildContextEntries() // Active branch entries with compac
|
|
|
982
982
|
ctx.sessionManager.getLeafId() // Current leaf entry ID
|
|
983
983
|
```
|
|
984
984
|
|
|
985
|
-
### ctx.modelRegistry / ctx.model
|
|
985
|
+
### ctx.modelRegistry / ctx.model / ctx.thinkingLevel
|
|
986
986
|
|
|
987
|
-
Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model.
|
|
987
|
+
Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model, and `ctx.thinkingLevel` is its current effective thinking level.
|
|
988
988
|
|
|
989
989
|
### ctx.signal
|
|
990
990
|
|
|
@@ -2096,7 +2096,15 @@ const bashTool = createBashTool(cwd, {
|
|
|
2096
2096
|
});
|
|
2097
2097
|
```
|
|
2098
2098
|
|
|
2099
|
-
|
|
2099
|
+
`createBashTool()` exposes the current session to commands through `PI_SESSION_ID`, `PI_SESSION_FILE`, `PI_PROVIDER`, `PI_MODEL`, and `PI_REASONING_LEVEL`. Injection happens before `spawnHook`, so hooks receive these values in `env` and preserve them when they spread the existing environment as above. Set `exposeSessionEnvironment: false` to disable them:
|
|
2100
|
+
|
|
2101
|
+
```typescript
|
|
2102
|
+
const bashTool = createBashTool(cwd, {
|
|
2103
|
+
exposeSessionEnvironment: false,
|
|
2104
|
+
});
|
|
2105
|
+
```
|
|
2106
|
+
|
|
2107
|
+
See [Bash tool session environment](environment-variables.md#bash-tool-session-environment) for variable semantics. See [examples/extensions/ssh.ts](../examples/extensions/ssh.ts) for a complete SSH example with `--ssh` flag.
|
|
2100
2108
|
|
|
2101
2109
|
### Output Truncation
|
|
2102
2110
|
|
package/docs/index.md
CHANGED
|
@@ -68,6 +68,7 @@ For the full first-run flow, see [Quickstart](quickstart.md).
|
|
|
68
68
|
|
|
69
69
|
## Reference
|
|
70
70
|
|
|
71
|
+
- [Environment variables](environment-variables.md) - Pi process configuration and session metadata available to bash tools.
|
|
71
72
|
- [Session format](session-format.md) - JSONL session file format, entry types, and SessionManager API.
|
|
72
73
|
|
|
73
74
|
## Platform setup
|
package/docs/json.md
CHANGED
|
@@ -17,7 +17,11 @@ type AgentSessionEvent =
|
|
|
17
17
|
| { type: "compaction_start"; reason: "manual" | "threshold" | "overflow" }
|
|
18
18
|
| { type: "compaction_end"; reason: "manual" | "threshold" | "overflow"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
|
|
19
19
|
| { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
|
|
20
|
-
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
20
|
+
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
21
|
+
| { type: "summarization_retry_scheduled"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
|
|
22
|
+
| { type: "summarization_retry_attempt_start"; source: "branchSummary" }
|
|
23
|
+
| { type: "summarization_retry_attempt_start"; source: "compaction"; reason: "manual" | "threshold" | "overflow" }
|
|
24
|
+
| { type: "summarization_retry_finished" };
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
`queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.
|
package/docs/models.md
CHANGED
|
@@ -375,6 +375,8 @@ Some Anthropic models require adaptive thinking (`thinking.type: "adaptive"` plu
|
|
|
375
375
|
|
|
376
376
|
Some Anthropic-compatible providers emit thinking blocks with empty signatures and still expect them on replay. Set `allowEmptySignature` to `true` only for those providers; real Anthropic rejects empty thinking signatures.
|
|
377
377
|
|
|
378
|
+
Built-in Anthropic models enable `supportsStrictTools` in their model metadata. Custom Anthropic-compatible models must set it to `true` when their endpoint accepts strict JSON-schema tool definitions.
|
|
379
|
+
|
|
378
380
|
```json
|
|
379
381
|
{
|
|
380
382
|
"providers": {
|
|
@@ -408,6 +410,7 @@ Some Anthropic-compatible providers emit thinking blocks with empty signatures a
|
|
|
408
410
|
| `supportsCacheControlOnTools` | Whether the provider accepts Anthropic-style `cache_control` markers on tool definitions. Default: `true`. |
|
|
409
411
|
| `forceAdaptiveThinking` | Whether to send adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) for this model. Built-in adaptive models set this automatically. Default: `false`. |
|
|
410
412
|
| `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
|
|
413
|
+
| `supportsStrictTools` | Whether the provider accepts strict JSON-schema tool definitions. Default: `false`; built-in Anthropic models enable it in generated metadata. |
|
|
411
414
|
|
|
412
415
|
## OpenAI Compatibility
|
|
413
416
|
|
|
@@ -445,10 +448,11 @@ For providers with partial OpenAI compatibility, use the `compat` field.
|
|
|
445
448
|
| `requiresReasoningContentOnAssistantMessages` | Include empty `reasoning_content` on all replayed assistant messages when reasoning is enabled |
|
|
446
449
|
| `thinkingFormat` | Use `reasoning_effort`, `openrouter`, `deepseek`, `together`, `zai`, `qwen`, `chat-template`, or `qwen-chat-template` thinking parameters |
|
|
447
450
|
| `chatTemplateKwargs` | `chat_template_kwargs` values for `thinkingFormat: "chat-template"`; use `{ "$var": "thinking.enabled" }` or `{ "$var": "thinking.effort" }` for pi-controlled thinking values |
|
|
448
|
-
| `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user
|
|
451
|
+
| `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user, assistant, or tool-result text content. Currently only `anthropic` is supported. |
|
|
449
452
|
| `sendSessionAffinityHeaders` | For `openai-completions`, send session-affinity headers from the session id when caching is enabled. Default: `false`. |
|
|
450
453
|
| `sessionAffinityFormat` | For `openai-completions` and `openai-responses`, the session-affinity header format: `openai` sends `session_id`/`x-client-request-id` (completions also `x-session-affinity`), `openai-nosession` omits the underscore-containing `session_id` header, `openrouter` sends `x-session-id`. Does not affect the `prompt_cache_key` body param. Default: auto-detected. |
|
|
451
|
-
| `supportsStrictMode` |
|
|
454
|
+
| `supportsStrictMode` | Whether the provider accepts strict JSON-schema function tool definitions. Defaults depend on the API; built-in OpenAI models carry explicit capability metadata. |
|
|
455
|
+
| `supportsOpenAIGrammarTools` | Whether OpenAI-compatible APIs emit custom Lark/regex grammar tools. When `false`, grammar-constrained tools fall back to normal function tools. Default: `false`; the built-in model catalog enables it for GPT-5+ models on OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode, and Cloudflare AI Gateway. |
|
|
452
456
|
| `deferredToolsMode` | Use provider-specific deferred tool serialization. Currently only `"kimi"` is supported for Kimi's OpenAI-compatible Chat Completions format. |
|
|
453
457
|
| `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_retention: "24h"` for OpenAI prompt caching, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
|
|
454
458
|
| `openRouterRouting` | OpenRouter provider routing preferences. This object is sent as-is in the `provider` field of the [OpenRouter API request](https://openrouter.ai/docs/guides/routing/provider-selection). |
|
package/docs/providers.md
CHANGED
|
@@ -20,9 +20,10 @@ Use `/login` in interactive mode, then select a provider:
|
|
|
20
20
|
- Claude Pro/Max
|
|
21
21
|
- GitHub Copilot
|
|
22
22
|
- xAI (Grok/X subscription)
|
|
23
|
+
- OpenRouter (OAuth-minted API key billed from OpenRouter credits)
|
|
23
24
|
- Radius
|
|
24
25
|
|
|
25
|
-
Use `/logout` to clear credentials. Tokens are stored in `~/.pi/agent/auth.json` and auto-refresh when expired.
|
|
26
|
+
Use `/logout` to clear credentials. Tokens are stored in `~/.pi/agent/auth.json` and auto-refresh when expired. OpenRouter instead mints a user-controlled API key that does not expire automatically.
|
|
26
27
|
|
|
27
28
|
### OpenAI Codex
|
|
28
29
|
|
|
@@ -43,6 +44,12 @@ Anthropic subscription auth is active for Claude Pro/Max accounts. Third-party h
|
|
|
43
44
|
- Run `/login xai`, then select **Use a subscription**
|
|
44
45
|
- `XAI_API_KEY` remains available through **Use an API key**
|
|
45
46
|
|
|
47
|
+
### OpenRouter
|
|
48
|
+
|
|
49
|
+
- Run `/login openrouter`, then select **Sign in with OpenRouter** to open the OpenRouter PKCE authorization flow
|
|
50
|
+
- The authorization creates a user-controlled OpenRouter API key billed from your OpenRouter credits
|
|
51
|
+
- `OPENROUTER_API_KEY` remains available through **Use an API key**
|
|
52
|
+
|
|
46
53
|
### Radius
|
|
47
54
|
|
|
48
55
|
Radius is a dynamic `pi-messages` gateway. `/login radius` stores OAuth tokens in `auth.json`; the gateway catalog is refreshed independently and cached in `models-store.json`. Custom Radius gateways can be declared in `models.json` with `"oauth": "radius"` and a gateway `baseUrl`.
|
package/docs/rpc.md
CHANGED
|
@@ -23,7 +23,7 @@ Common options:
|
|
|
23
23
|
- **Responses**: JSON objects with `type: "response"` indicating command success/failure
|
|
24
24
|
- **Events**: Agent events streamed to stdout as JSON lines
|
|
25
25
|
|
|
26
|
-
All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`.
|
|
26
|
+
All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`. `bash_execution_update` events also include the `id` of their originating `bash` command.
|
|
27
27
|
|
|
28
28
|
### Framing
|
|
29
29
|
|
|
@@ -455,15 +455,18 @@ Response:
|
|
|
455
455
|
|
|
456
456
|
#### bash
|
|
457
457
|
|
|
458
|
-
Execute a shell command and add output to conversation context.
|
|
458
|
+
Execute a shell command and add output to conversation context. Output streams as `bash_execution_update` events while the command runs; the response contains the final result.
|
|
459
459
|
|
|
460
460
|
```json
|
|
461
|
-
{"type": "bash", "command": "ls -la"}
|
|
461
|
+
{"id": "req-1", "type": "bash", "command": "ls -la"}
|
|
462
462
|
```
|
|
463
463
|
|
|
464
|
+
Include an `id` to associate streamed `bash_execution_update` events with this command.
|
|
465
|
+
|
|
464
466
|
Response:
|
|
465
467
|
```json
|
|
466
468
|
{
|
|
469
|
+
"id": "req-1",
|
|
467
470
|
"type": "response",
|
|
468
471
|
"command": "bash",
|
|
469
472
|
"success": true,
|
|
@@ -494,7 +497,7 @@ If output was truncated, includes `fullOutputPath`:
|
|
|
494
497
|
|
|
495
498
|
**How bash results reach the LLM:**
|
|
496
499
|
|
|
497
|
-
The `bash` command executes immediately and returns a `BashResult`. Internally, a `BashExecutionMessage` is created and stored in the agent's message state.
|
|
500
|
+
The `bash` command executes immediately and returns a `BashResult`. Internally, a `BashExecutionMessage` is created and stored in the agent's message state.
|
|
498
501
|
|
|
499
502
|
When the next `prompt` command is sent, all messages (including `BashExecutionMessage`) are transformed before being sent to the LLM. The `BashExecutionMessage` is converted to a `UserMessage` with this format:
|
|
500
503
|
|
|
@@ -509,7 +512,6 @@ drwxr-xr-x ...
|
|
|
509
512
|
This means:
|
|
510
513
|
1. Bash output is included in the LLM context on the **next prompt**, not immediately
|
|
511
514
|
2. Multiple bash commands can be executed before a prompt; all outputs will be included
|
|
512
|
-
3. No event is emitted for the `BashExecutionMessage` itself
|
|
513
515
|
|
|
514
516
|
#### abort_bash
|
|
515
517
|
|
|
@@ -829,7 +831,7 @@ Each command has:
|
|
|
829
831
|
|
|
830
832
|
## Events
|
|
831
833
|
|
|
832
|
-
Events are streamed to stdout as JSON lines during agent operation. Events do
|
|
834
|
+
Events are streamed to stdout as JSON lines during agent operation. Events do not generally include an `id` field; `bash_execution_update` includes the `id` of its originating `bash` command when one was provided.
|
|
833
835
|
|
|
834
836
|
### Event Types
|
|
835
837
|
|
|
@@ -843,6 +845,7 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
|
|
|
843
845
|
| `message_start` | Message begins |
|
|
844
846
|
| `message_update` | Streaming update (text/thinking/toolcall deltas) |
|
|
845
847
|
| `message_end` | Message completes |
|
|
848
|
+
| `bash_execution_update` | Direct RPC bash command output chunk |
|
|
846
849
|
| `tool_execution_start` | Tool begins execution |
|
|
847
850
|
| `tool_execution_update` | Tool execution progress (streaming output) |
|
|
848
851
|
| `tool_execution_end` | Tool completes |
|
|
@@ -851,6 +854,9 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
|
|
|
851
854
|
| `compaction_end` | Compaction completes |
|
|
852
855
|
| `auto_retry_start` | Auto-retry begins (after transient error) |
|
|
853
856
|
| `auto_retry_end` | Auto-retry completes (success or final failure) |
|
|
857
|
+
| `summarization_retry_scheduled` | Retry scheduled for a transient compaction or branch-summary summarization error |
|
|
858
|
+
| `summarization_retry_attempt_start` | Retried summarization request starts |
|
|
859
|
+
| `summarization_retry_finished` | Summarization retry loop completes |
|
|
854
860
|
| `extension_error` | Extension threw an error |
|
|
855
861
|
|
|
856
862
|
### agent_start
|
|
@@ -948,6 +954,20 @@ Example streaming a text response:
|
|
|
948
954
|
{"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world","partial":{...}}}
|
|
949
955
|
```
|
|
950
956
|
|
|
957
|
+
### bash_execution_update
|
|
958
|
+
|
|
959
|
+
Emitted once for each output chunk from a direct `bash` command. `id` matches the command's `id`, allowing clients to associate output with the correct command.
|
|
960
|
+
|
|
961
|
+
Events stream all output while the command runs, even if the final `bash` response's `output` is truncated.
|
|
962
|
+
|
|
963
|
+
```json
|
|
964
|
+
{
|
|
965
|
+
"type": "bash_execution_update",
|
|
966
|
+
"id": "req-1",
|
|
967
|
+
"delta": "total 48\n"
|
|
968
|
+
}
|
|
969
|
+
```
|
|
970
|
+
|
|
951
971
|
### tool_execution_start / tool_execution_update / tool_execution_end
|
|
952
972
|
|
|
953
973
|
Emitted when a tool begins, streams progress, and completes execution.
|
|
@@ -1077,6 +1097,36 @@ On final failure (max retries exceeded):
|
|
|
1077
1097
|
}
|
|
1078
1098
|
```
|
|
1079
1099
|
|
|
1100
|
+
### summarization_retry_scheduled / summarization_retry_attempt_start / summarization_retry_finished
|
|
1101
|
+
|
|
1102
|
+
Emitted when compaction or branch-summary summarization retries after a transient provider error. These events use the same retry settings as automatic assistant-turn retries.
|
|
1103
|
+
|
|
1104
|
+
```json
|
|
1105
|
+
{
|
|
1106
|
+
"type": "summarization_retry_scheduled",
|
|
1107
|
+
"attempt": 1,
|
|
1108
|
+
"maxAttempts": 3,
|
|
1109
|
+
"delayMs": 2000,
|
|
1110
|
+
"errorMessage": "terminated"
|
|
1111
|
+
}
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
```json
|
|
1115
|
+
{
|
|
1116
|
+
"type": "summarization_retry_attempt_start",
|
|
1117
|
+
"source": "compaction",
|
|
1118
|
+
"reason": "threshold"
|
|
1119
|
+
}
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
For branch summaries, `source` is `"branchSummary"` and no `reason` is present.
|
|
1123
|
+
|
|
1124
|
+
```json
|
|
1125
|
+
{
|
|
1126
|
+
"type": "summarization_retry_finished"
|
|
1127
|
+
}
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1080
1130
|
### extension_error
|
|
1081
1131
|
|
|
1082
1132
|
Emitted when an extension throws an error.
|
package/docs/sdk.md
CHANGED
|
@@ -319,6 +319,9 @@ session.subscribe((event) => {
|
|
|
319
319
|
case "compaction_end":
|
|
320
320
|
case "auto_retry_start":
|
|
321
321
|
case "auto_retry_end":
|
|
322
|
+
case "summarization_retry_scheduled":
|
|
323
|
+
case "summarization_retry_attempt_start":
|
|
324
|
+
case "summarization_retry_finished":
|
|
322
325
|
break;
|
|
323
326
|
}
|
|
324
327
|
});
|
package/docs/settings.md
CHANGED
|
@@ -142,7 +142,7 @@ Set `PI_SKIP_VERSION_CHECK=1` to disable the Pi version update check. Use `--off
|
|
|
142
142
|
| `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts |
|
|
143
143
|
| `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s) |
|
|
144
144
|
|
|
145
|
-
When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs
|
|
145
|
+
When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs`, the request fails immediately with an informative error instead of waiting silently. Set it to `0` to disable the limit.
|
|
146
146
|
|
|
147
147
|
Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explicitly needed. Setting it above `0` can make SDK/provider retries handle out-of-usage-limit errors before Pi sees them, which may block the agent until the provider quota resets in some circumstances.
|
|
148
148
|
|
package/docs/usage.md
CHANGED
|
@@ -289,19 +289,6 @@ pi --tools read,grep,find,ls -p "Review the code"
|
|
|
289
289
|
pi --exclude-tools ask_question
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
-
### Environment Variables
|
|
293
|
-
|
|
294
|
-
| Variable | Description |
|
|
295
|
-
|----------|-------------|
|
|
296
|
-
| `PI_CODING_AGENT_DIR` | Override config directory; default is `~/.pi/agent` |
|
|
297
|
-
| `PI_CODING_AGENT_SESSION_DIR` | Override session storage directory; overridden by `--session-dir` |
|
|
298
|
-
| `PI_PACKAGE_DIR` | Override package directory, useful for Nix/Guix store paths |
|
|
299
|
-
| `PI_OFFLINE` | Disable startup network operations, including update checks, package update checks, and install/update telemetry |
|
|
300
|
-
| `PI_SKIP_VERSION_CHECK` | Skip the Pi version update check at startup. This prevents the `pi.dev` latest-version request |
|
|
301
|
-
| `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no`. This does not disable update checks |
|
|
302
|
-
| `PI_CACHE_RETENTION` | Set to `long` for extended prompt cache where supported |
|
|
303
|
-
| `VISUAL`, `EDITOR` | Fallback external editor for Ctrl+G when `externalEditor` is unset; defaults to Notepad on Windows and `nano` elsewhere |
|
|
304
|
-
|
|
305
292
|
## Design Principles
|
|
306
293
|
|
|
307
294
|
Pi keeps the core small and pushes workflow-specific behavior into extensions, skills, prompt templates, and packages.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* pi --extension examples/extensions/custom-compaction.ts
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { uuidv7 } from "@earendil-works/pi-ai";
|
|
16
17
|
import { complete } from "@earendil-works/pi-ai/compat";
|
|
17
18
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
18
19
|
import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
|
|
@@ -96,6 +97,8 @@ ${conversationText}
|
|
|
96
97
|
env: auth.env,
|
|
97
98
|
maxTokens: 8192,
|
|
98
99
|
signal,
|
|
100
|
+
cacheRetention: "none",
|
|
101
|
+
sessionId: uuidv7(),
|
|
99
102
|
},
|
|
100
103
|
);
|
|
101
104
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-custom-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-custom-provider",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.82.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
12
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-gondolin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-gondolin",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.82.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@earendil-works/gondolin": "0.12.0"
|
|
12
12
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
16
|
+
import { uuidv7 } from "@earendil-works/pi-ai";
|
|
16
17
|
import { complete, type Message } from "@earendil-works/pi-ai/compat";
|
|
17
18
|
import type { ExtensionAPI, SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
18
19
|
import { BorderedLoader, convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
|
|
@@ -136,7 +137,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
136
137
|
const response = await complete(
|
|
137
138
|
ctx.model!,
|
|
138
139
|
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
|
139
|
-
{
|
|
140
|
+
{
|
|
141
|
+
apiKey: auth.apiKey,
|
|
142
|
+
headers: auth.headers,
|
|
143
|
+
env: auth.env,
|
|
144
|
+
signal: loader.signal,
|
|
145
|
+
cacheRetention: "none",
|
|
146
|
+
sessionId: uuidv7(),
|
|
147
|
+
},
|
|
140
148
|
);
|
|
141
149
|
|
|
142
150
|
if (response.stopReason === "aborted") {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-sandbox",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-sandbox",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.12.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sandbox-runtime": "^0.0.26"
|
|
12
12
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { uuidv7 } from "@earendil-works/pi-ai";
|
|
1
2
|
import { complete, getModel } from "@earendil-works/pi-ai/compat";
|
|
2
3
|
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
3
4
|
import { DynamicBorder, getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
@@ -193,6 +194,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
193
194
|
headers: auth.headers,
|
|
194
195
|
env: auth.env,
|
|
195
196
|
reasoningEffort: "high",
|
|
197
|
+
cacheRetention: "none",
|
|
198
|
+
sessionId: uuidv7(),
|
|
196
199
|
},
|
|
197
200
|
);
|
|
198
201
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.82.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|