@draht/coding-agent 2026.3.14 → 2026.3.25
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/README.md +45 -30
- package/dist/bun/cli.d.ts +3 -0
- package/dist/bun/cli.d.ts.map +1 -0
- package/dist/bun/cli.js +7 -0
- package/dist/bun/cli.js.map +1 -0
- package/dist/bun/register-bedrock.d.ts +2 -0
- package/dist/bun/register-bedrock.d.ts.map +1 -0
- package/dist/bun/register-bedrock.js +4 -0
- package/dist/bun/register-bedrock.js.map +1 -0
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +11 -6
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +4 -0
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +18 -0
- package/dist/cli/initial-message.d.ts.map +1 -0
- package/dist/cli/initial-message.js +22 -0
- package/dist/cli/initial-message.js.map +1 -0
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +2 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -3
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +38 -5
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +201 -73
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts +6 -7
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +8 -107
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +2 -0
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +7 -3
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/index.d.ts +2 -2
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +7 -6
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.css +43 -13
- package/dist/core/export-html/template.html +1 -0
- package/dist/core/export-html/template.js +107 -0
- package/dist/core/export-html/tool-renderer.d.ts +2 -2
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +41 -16
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +4 -3
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +16 -6
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +9 -9
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +89 -71
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +49 -13
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts +4 -11
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +6 -86
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +13 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +155 -37
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +270 -50
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +222 -134
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +49 -23
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +6 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +41 -17
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts +6 -0
- package/dist/core/output-guard.d.ts.map +1 -0
- package/dist/core/output-guard.js +59 -0
- package/dist/core/output-guard.js.map +1 -0
- package/dist/core/package-manager.d.ts +22 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +373 -53
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +2 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +39 -39
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +43 -8
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +6 -7
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +141 -118
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +9 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +5 -3
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +54 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts +2 -3
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/source-info.d.ts +18 -0
- package/dist/core/source-info.d.ts.map +1 -0
- package/dist/core/source-info.js +19 -0
- package/dist/core/source-info.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +17 -60
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +24 -6
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +210 -110
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +1 -0
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +14 -2
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +95 -23
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts +6 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/core/tools/file-mutation-queue.js +37 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -0
- package/dist/core/tools/find.d.ts +11 -4
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +82 -30
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +15 -4
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +83 -29
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +58 -19
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +51 -26
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +9 -3
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +67 -13
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +10 -3
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +110 -51
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +21 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -0
- package/dist/core/tools/render-utils.js +49 -0
- package/dist/core/tools/render-utils.js.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.js +30 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
- package/dist/core/tools/write.d.ts +9 -3
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +168 -30
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +105 -226
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +22 -9
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +2 -2
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +2 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +8 -8
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +6 -6
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +9 -9
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +5 -5
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +8 -8
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +3 -36
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +5 -44
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +6 -6
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +13 -9
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +6 -6
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +4 -4
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +32 -35
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +5 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +5 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +5 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +16 -34
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +128 -636
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +27 -16
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +6 -6
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +2 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +7 -11
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +353 -214
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +3 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +63 -37
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +5 -11
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +27 -17
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +3 -4
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/child-process.d.ts +11 -0
- package/dist/utils/child-process.d.ts.map +1 -0
- package/dist/utils/child-process.js +78 -0
- package/dist/utils/child-process.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +94 -11
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +27 -16
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts +5 -0
- package/dist/utils/exif-orientation.d.ts.map +1 -0
- package/dist/utils/exif-orientation.js +158 -0
- package/dist/utils/exif-orientation.js.map +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +5 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-resize.d.ts +5 -5
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +51 -95
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +5 -4
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +6 -2
- package/docs/extensions.md +108 -21
- package/docs/keybindings.md +103 -112
- package/docs/models.md +39 -1
- package/docs/packages.md +9 -0
- package/docs/providers.md +7 -0
- package/docs/rpc.md +15 -6
- package/docs/sdk.md +2 -2
- package/docs/settings.md +9 -0
- package/docs/terminal-setup.md +11 -0
- package/docs/tui.md +2 -2
- package/examples/extensions/README.md +2 -2
- package/examples/extensions/antigravity-image-gen.ts +5 -3
- package/examples/extensions/built-in-tool-renderer.ts +8 -8
- package/examples/extensions/commands.ts +3 -3
- package/examples/extensions/minimal-mode.ts +14 -14
- package/examples/extensions/question.ts +2 -2
- package/examples/extensions/questionnaire.ts +2 -2
- package/examples/extensions/subagent/index.ts +30 -8
- package/examples/extensions/titlebar-spinner.ts +2 -2
- package/examples/extensions/todo.ts +2 -2
- package/examples/extensions/tool-override.ts +9 -7
- package/examples/extensions/truncated-tool.ts +8 -5
- package/examples/sdk/04-skills.ts +8 -2
- package/examples/sdk/08-prompt-templates.ts +8 -2
- package/examples/sdk/12-full-control.ts +0 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +4 -4
package/docs/extensions.md
CHANGED
|
@@ -247,11 +247,11 @@ user sends prompt ────────────────────
|
|
|
247
247
|
│ ├─► before_provider_request (can inspect or replace payload)
|
|
248
248
|
│ │ │ │
|
|
249
249
|
│ │ LLM responds, may call tools: │ │
|
|
250
|
-
│ │ ├─► tool_call (can block) │ │
|
|
251
250
|
│ │ ├─► tool_execution_start │ │
|
|
251
|
+
│ │ ├─► tool_call (can block) │ │
|
|
252
252
|
│ │ ├─► tool_execution_update │ │
|
|
253
|
-
│ │ ├─►
|
|
254
|
-
│ │ └─►
|
|
253
|
+
│ │ ├─► tool_result (can modify) │ │
|
|
254
|
+
│ │ └─► tool_execution_end │ │
|
|
255
255
|
│ │ │ │
|
|
256
256
|
│ └─► turn_end │ │
|
|
257
257
|
│ │
|
|
@@ -485,6 +485,11 @@ pi.on("message_end", async (event, ctx) => {
|
|
|
485
485
|
|
|
486
486
|
Fired for tool execution lifecycle updates.
|
|
487
487
|
|
|
488
|
+
In parallel tool mode:
|
|
489
|
+
- `tool_execution_start` is emitted in assistant source order during the preflight phase
|
|
490
|
+
- `tool_execution_update` events may interleave across tools
|
|
491
|
+
- `tool_execution_end` is emitted in assistant source order, matching final tool result message order
|
|
492
|
+
|
|
488
493
|
```typescript
|
|
489
494
|
pi.on("tool_execution_start", async (event, ctx) => {
|
|
490
495
|
// event.toolCallId, event.toolName, event.args
|
|
@@ -553,7 +558,11 @@ Use this to update UI elements (status bars, footers) or perform model-specific
|
|
|
553
558
|
|
|
554
559
|
#### tool_call
|
|
555
560
|
|
|
556
|
-
Fired before tool executes. **Can block.** Use `isToolCallEventType` to narrow and get typed inputs.
|
|
561
|
+
Fired after `tool_execution_start`, before the tool executes. **Can block.** Use `isToolCallEventType` to narrow and get typed inputs.
|
|
562
|
+
|
|
563
|
+
Before `tool_call` runs, pi waits for previously emitted Agent events to finish draining through `AgentSession`. This means `ctx.sessionManager` is up to date through the current assistant tool-calling message.
|
|
564
|
+
|
|
565
|
+
In the default parallel tool execution mode, sibling tool calls from the same assistant message are preflighted sequentially, then executed concurrently. `tool_call` is not guaranteed to see sibling tool results from that same assistant message in `ctx.sessionManager`.
|
|
557
566
|
|
|
558
567
|
```typescript
|
|
559
568
|
import { isToolCallEventType } from "@draht/coding-agent";
|
|
@@ -602,7 +611,7 @@ pi.on("tool_call", (event) => {
|
|
|
602
611
|
|
|
603
612
|
#### tool_result
|
|
604
613
|
|
|
605
|
-
Fired after tool
|
|
614
|
+
Fired after tool execution finishes and before `tool_execution_end` plus the final tool result message events are emitted. **Can modify result.**
|
|
606
615
|
|
|
607
616
|
`tool_result` handlers chain like middleware:
|
|
608
617
|
- Handlers run in extension load order
|
|
@@ -632,6 +641,8 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
632
641
|
Fired when user executes `!` or `!!` commands. **Can intercept.**
|
|
633
642
|
|
|
634
643
|
```typescript
|
|
644
|
+
import { createLocalBashOperations } from "@mariozechner/pi-coding-agent";
|
|
645
|
+
|
|
635
646
|
pi.on("user_bash", (event, ctx) => {
|
|
636
647
|
// event.command - the bash command
|
|
637
648
|
// event.excludeFromContext - true if !! prefix
|
|
@@ -640,7 +651,17 @@ pi.on("user_bash", (event, ctx) => {
|
|
|
640
651
|
// Option 1: Provide custom operations (e.g., SSH)
|
|
641
652
|
return { operations: remoteBashOps };
|
|
642
653
|
|
|
643
|
-
// Option 2:
|
|
654
|
+
// Option 2: Wrap pi's built-in local bash backend
|
|
655
|
+
const local = createLocalBashOperations();
|
|
656
|
+
return {
|
|
657
|
+
operations: {
|
|
658
|
+
exec(command, cwd, options) {
|
|
659
|
+
return local.exec(`source ~/.profile\n${command}`, cwd, options);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
// Option 3: Full replacement - return result directly
|
|
644
665
|
return { result: { output: "...", exitCode: 0, cancelled: false, truncated: false } };
|
|
645
666
|
});
|
|
646
667
|
```
|
|
@@ -715,6 +736,8 @@ Current working directory.
|
|
|
715
736
|
|
|
716
737
|
Read-only access to session state. See [session.md](session.md) for the full SessionManager API and entry types.
|
|
717
738
|
|
|
739
|
+
For `tool_call`, this state is synchronized through the current assistant message before handlers run. In parallel tool execution mode it is still not guaranteed to include sibling tool results from the same assistant message.
|
|
740
|
+
|
|
718
741
|
```typescript
|
|
719
742
|
ctx.sessionManager.getEntries() // All entries
|
|
720
743
|
ctx.sessionManager.getBranch() // Current branch
|
|
@@ -923,7 +946,7 @@ Register a custom tool callable by the LLM. See [Custom Tools](#custom-tools) fo
|
|
|
923
946
|
|
|
924
947
|
Use `pi.setActiveTools()` to enable or disable tools (including dynamically added tools) at runtime.
|
|
925
948
|
|
|
926
|
-
Use `promptSnippet` to
|
|
949
|
+
Use `promptSnippet` to opt a custom tool into a one-line entry in `Available tools`, and `promptGuidelines` to append tool-specific bullets to the default `Guidelines` section when the tool is active.
|
|
927
950
|
|
|
928
951
|
See [dynamic-tools.ts](../examples/extensions/dynamic-tools.ts) for a full example.
|
|
929
952
|
|
|
@@ -976,7 +999,7 @@ pi.sendMessage({
|
|
|
976
999
|
|
|
977
1000
|
**Options:**
|
|
978
1001
|
- `deliverAs` - Delivery mode:
|
|
979
|
-
- `"steer"` (default) -
|
|
1002
|
+
- `"steer"` (default) - Queues the message while streaming. Delivered after the current assistant turn finishes executing its tool calls, before the next LLM call.
|
|
980
1003
|
- `"followUp"` - Waits for agent to finish. Delivered only when agent has no more tool calls.
|
|
981
1004
|
- `"nextTurn"` - Queued for next user prompt. Does not interrupt or trigger anything.
|
|
982
1005
|
- `triggerTurn: true` - If agent is idle, trigger an LLM response immediately. Only applies to `"steer"` and `"followUp"` modes (ignored for `"nextTurn"`).
|
|
@@ -1002,7 +1025,7 @@ pi.sendUserMessage("And then summarize", { deliverAs: "followUp" });
|
|
|
1002
1025
|
|
|
1003
1026
|
**Options:**
|
|
1004
1027
|
- `deliverAs` - Required when agent is streaming:
|
|
1005
|
-
- `"steer"` -
|
|
1028
|
+
- `"steer"` - Queues the message for delivery after the current assistant turn finishes executing its tool calls
|
|
1006
1029
|
- `"followUp"` - Waits for agent to finish all tools
|
|
1007
1030
|
|
|
1008
1031
|
When not streaming, the message is sent immediately and triggers a new turn. When streaming without `deliverAs`, throws an error.
|
|
@@ -1066,6 +1089,8 @@ Labels persist in the session and survive restarts. Use them to mark important p
|
|
|
1066
1089
|
|
|
1067
1090
|
Register a command.
|
|
1068
1091
|
|
|
1092
|
+
If multiple extensions register the same command name, pi keeps them all and assigns numeric invocation suffixes in load order, for example `/review:1` and `/review:2`.
|
|
1093
|
+
|
|
1069
1094
|
```typescript
|
|
1070
1095
|
pi.registerCommand("stats", {
|
|
1071
1096
|
description: "Show session statistics",
|
|
@@ -1103,20 +1128,28 @@ The list matches the RPC `get_commands` ordering: extensions first, then templat
|
|
|
1103
1128
|
```typescript
|
|
1104
1129
|
const commands = pi.getCommands();
|
|
1105
1130
|
const bySource = commands.filter((command) => command.source === "extension");
|
|
1131
|
+
const userScoped = commands.filter((command) => command.sourceInfo.scope === "user");
|
|
1106
1132
|
```
|
|
1107
1133
|
|
|
1108
1134
|
Each entry has this shape:
|
|
1109
1135
|
|
|
1110
1136
|
```typescript
|
|
1111
1137
|
{
|
|
1112
|
-
name: string; //
|
|
1138
|
+
name: string; // Invokable command name without the leading slash. May be suffixed like "review:1"
|
|
1113
1139
|
description?: string;
|
|
1114
1140
|
source: "extension" | "prompt" | "skill";
|
|
1115
|
-
|
|
1116
|
-
|
|
1141
|
+
sourceInfo: {
|
|
1142
|
+
path: string;
|
|
1143
|
+
source: string;
|
|
1144
|
+
scope: "user" | "project" | "temporary";
|
|
1145
|
+
origin: "package" | "top-level";
|
|
1146
|
+
baseDir?: string;
|
|
1147
|
+
};
|
|
1117
1148
|
}
|
|
1118
1149
|
```
|
|
1119
1150
|
|
|
1151
|
+
Use `sourceInfo` as the canonical provenance field. Do not infer ownership from command names or from ad hoc path parsing.
|
|
1152
|
+
|
|
1120
1153
|
Built-in interactive commands (like `/model` and `/settings`) are not included here. They are handled only in interactive
|
|
1121
1154
|
mode and would not execute if sent via `prompt`.
|
|
1122
1155
|
|
|
@@ -1168,12 +1201,27 @@ const result = await pi.exec("git", ["status"], { signal, timeout: 5000 });
|
|
|
1168
1201
|
Manage active tools. This works for both built-in tools and dynamically registered tools.
|
|
1169
1202
|
|
|
1170
1203
|
```typescript
|
|
1171
|
-
const active = pi.getActiveTools();
|
|
1172
|
-
const all = pi.getAllTools();
|
|
1173
|
-
|
|
1204
|
+
const active = pi.getActiveTools();
|
|
1205
|
+
const all = pi.getAllTools();
|
|
1206
|
+
// [{
|
|
1207
|
+
// name: "read",
|
|
1208
|
+
// description: "Read file contents...",
|
|
1209
|
+
// parameters: ...,
|
|
1210
|
+
// sourceInfo: { path: "<builtin:read>", source: "builtin", scope: "temporary", origin: "top-level" }
|
|
1211
|
+
// }, ...]
|
|
1212
|
+
const names = all.map(t => t.name);
|
|
1213
|
+
const builtinTools = all.filter((t) => t.sourceInfo.source === "builtin");
|
|
1214
|
+
const extensionTools = all.filter((t) => t.sourceInfo.source !== "builtin" && t.sourceInfo.source !== "sdk");
|
|
1174
1215
|
pi.setActiveTools(["read", "bash"]); // Switch to read-only
|
|
1175
1216
|
```
|
|
1176
1217
|
|
|
1218
|
+
`pi.getAllTools()` returns `name`, `description`, `parameters`, and `sourceInfo`.
|
|
1219
|
+
|
|
1220
|
+
Typical `sourceInfo.source` values:
|
|
1221
|
+
- `builtin` for built-in tools
|
|
1222
|
+
- `sdk` for tools passed via `createAgentSession({ customTools })`
|
|
1223
|
+
- extension source metadata for tools registered by extensions
|
|
1224
|
+
|
|
1177
1225
|
### pi.setModel(model)
|
|
1178
1226
|
|
|
1179
1227
|
Set the current model. Returns `false` if no API key is available for the model. See [models.md](models.md) for configuring custom models.
|
|
@@ -1325,12 +1373,42 @@ export default function (pi: ExtensionAPI) {
|
|
|
1325
1373
|
|
|
1326
1374
|
Register tools the LLM can call via `pi.registerTool()`. Tools appear in the system prompt and can have custom rendering.
|
|
1327
1375
|
|
|
1328
|
-
Use `promptSnippet` for a short one-line entry in the `Available tools` section in the default system prompt. If omitted,
|
|
1376
|
+
Use `promptSnippet` for a short one-line entry in the `Available tools` section in the default system prompt. If omitted, custom tools are left out of that section.
|
|
1329
1377
|
|
|
1330
1378
|
Use `promptGuidelines` to add tool-specific bullets to the default system prompt `Guidelines` section. These bullets are included only while the tool is active (for example, after `pi.setActiveTools([...])`).
|
|
1331
1379
|
|
|
1332
1380
|
Note: Some models are idiots and include the @ prefix in tool path arguments. Built-in tools strip a leading @ before resolving paths. If your custom tool accepts a path, normalize a leading @ as well.
|
|
1333
1381
|
|
|
1382
|
+
If your custom tool mutates files, use `withFileMutationQueue()` so it participates in the same per-file queue as built-in `edit` and `write`. This matters because tool calls run in parallel by default. Without the queue, two tools can read the same old file contents, compute different updates, and then whichever write lands last overwrites the other.
|
|
1383
|
+
|
|
1384
|
+
Example failure case: your custom tool edits `foo.ts` while built-in `edit` also changes `foo.ts` in the same assistant turn. If your tool does not participate in the queue, both can read the original `foo.ts`, apply separate changes, and one of those changes is lost.
|
|
1385
|
+
|
|
1386
|
+
Pass the real target file path to `withFileMutationQueue()`, not the raw user argument. Resolve it to an absolute path first, relative to `ctx.cwd` or your tool's working directory. For existing files, the helper canonicalizes through `realpath()`, so symlink aliases for the same file share one queue. For new files, it falls back to the resolved absolute path because there is nothing to `realpath()` yet.
|
|
1387
|
+
|
|
1388
|
+
Queue the entire mutation window on that target path. That includes read-modify-write logic, not just the final write.
|
|
1389
|
+
|
|
1390
|
+
```typescript
|
|
1391
|
+
import { withFileMutationQueue } from "@mariozechner/pi-coding-agent";
|
|
1392
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1393
|
+
import { dirname, resolve } from "node:path";
|
|
1394
|
+
|
|
1395
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1396
|
+
const absolutePath = resolve(ctx.cwd, params.path);
|
|
1397
|
+
|
|
1398
|
+
return withFileMutationQueue(absolutePath, async () => {
|
|
1399
|
+
await mkdir(dirname(absolutePath), { recursive: true });
|
|
1400
|
+
const current = await readFile(absolutePath, "utf8");
|
|
1401
|
+
const next = current.replace(params.oldText, params.newText);
|
|
1402
|
+
await writeFile(absolutePath, next, "utf8");
|
|
1403
|
+
|
|
1404
|
+
return {
|
|
1405
|
+
content: [{ type: "text", text: `Updated ${params.path}` }],
|
|
1406
|
+
details: {},
|
|
1407
|
+
};
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1334
1412
|
### Tool Definition
|
|
1335
1413
|
|
|
1336
1414
|
```typescript
|
|
@@ -1454,6 +1532,8 @@ pi.registerTool({
|
|
|
1454
1532
|
|
|
1455
1533
|
**Operations interfaces:** `ReadOperations`, `WriteOperations`, `EditOperations`, `BashOperations`, `LsOperations`, `GrepOperations`, `FindOperations`
|
|
1456
1534
|
|
|
1535
|
+
For `user_bash`, extensions can reuse pi's local shell backend via `createLocalBashOperations()` instead of reimplementing local process spawning, shell resolution, and process-tree termination.
|
|
1536
|
+
|
|
1457
1537
|
The bash tool also supports a spawn hook to adjust the command, cwd, or env before execution:
|
|
1458
1538
|
|
|
1459
1539
|
```typescript
|
|
@@ -1592,7 +1672,7 @@ renderResult(result, { expanded, isPartial }, theme) {
|
|
|
1592
1672
|
|
|
1593
1673
|
#### Keybinding Hints
|
|
1594
1674
|
|
|
1595
|
-
Use `keyHint()` to display keybinding hints that respect
|
|
1675
|
+
Use `keyHint()` to display keybinding hints that respect the active keybinding configuration:
|
|
1596
1676
|
|
|
1597
1677
|
```typescript
|
|
1598
1678
|
import { keyHint } from "@draht/coding-agent";
|
|
@@ -1600,18 +1680,25 @@ import { keyHint } from "@draht/coding-agent";
|
|
|
1600
1680
|
renderResult(result, { expanded }, theme) {
|
|
1601
1681
|
let text = theme.fg("success", "✓ Done");
|
|
1602
1682
|
if (!expanded) {
|
|
1603
|
-
text += ` (${keyHint("
|
|
1683
|
+
text += ` (${keyHint("app.tools.expand", "to expand")})`;
|
|
1604
1684
|
}
|
|
1605
1685
|
return new Text(text, 0, 0);
|
|
1606
1686
|
}
|
|
1607
1687
|
```
|
|
1608
1688
|
|
|
1609
1689
|
Available functions:
|
|
1610
|
-
- `keyHint(
|
|
1611
|
-
- `
|
|
1612
|
-
- `editorKey(action)` - Get raw key string for editor action
|
|
1690
|
+
- `keyHint(keybinding, description)` - Formats a configured keybinding id such as `"app.tools.expand"` or `"tui.select.confirm"`
|
|
1691
|
+
- `keyText(keybinding)` - Returns the raw configured key text for a keybinding id
|
|
1613
1692
|
- `rawKeyHint(key, description)` - Format a raw key string
|
|
1614
1693
|
|
|
1694
|
+
Use namespaced keybinding ids:
|
|
1695
|
+
- Coding-agent ids use the `app.*` namespace, for example `app.tools.expand`, `app.editor.external`, `app.session.rename`
|
|
1696
|
+
- Shared TUI ids use the `tui.*` namespace, for example `tui.select.confirm`, `tui.select.cancel`, `tui.input.tab`
|
|
1697
|
+
|
|
1698
|
+
For the exhaustive list of keybinding ids and defaults, see [keybindings.md](keybindings.md). `keybindings.json` uses those same namespaced ids.
|
|
1699
|
+
|
|
1700
|
+
Custom editors and `ctx.ui.custom()` components receive `keybindings: KeybindingsManager` as an injected argument. They should use that injected manager directly instead of calling `getKeybindings()` or `setKeybindings()`.
|
|
1701
|
+
|
|
1615
1702
|
#### Best Practices
|
|
1616
1703
|
|
|
1617
1704
|
- Use `Text` with padding `(0, 0)` - the Box handles padding
|
package/docs/keybindings.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All keyboard shortcuts can be customized via `~/.pi/agent/keybindings.json`. Each action can be bound to one or more keys.
|
|
4
4
|
|
|
5
|
+
The config file uses the same namespaced keybinding ids that pi uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.
|
|
6
|
+
|
|
7
|
+
Older configs using pre-namespaced ids such as `cursorUp` or `expandTools` are migrated automatically to the namespaced ids on startup.
|
|
8
|
+
|
|
9
|
+
After editing `keybindings.json`, run `/reload` in pi to apply the changes without restarting the session.
|
|
10
|
+
|
|
5
11
|
## Key Format
|
|
6
12
|
|
|
7
13
|
`modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:
|
|
@@ -16,127 +22,112 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
|
|
|
16
22
|
|
|
17
23
|
## All Actions
|
|
18
24
|
|
|
19
|
-
### Cursor Movement
|
|
25
|
+
### TUI Editor Cursor Movement
|
|
20
26
|
|
|
21
|
-
|
|
|
27
|
+
| Keybinding id | Default | Description |
|
|
22
28
|
|--------|---------|-------------|
|
|
23
|
-
| `cursorUp` | `up` | Move cursor up |
|
|
24
|
-
| `cursorDown` | `down` | Move cursor down |
|
|
25
|
-
| `cursorLeft` | `left`, `ctrl+b` | Move cursor left |
|
|
26
|
-
| `cursorRight` | `right`, `ctrl+f` | Move cursor right |
|
|
27
|
-
| `cursorWordLeft` | `alt+left`, `ctrl+left`, `alt+b` | Move cursor word left |
|
|
28
|
-
| `cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right |
|
|
29
|
-
| `cursorLineStart` | `home`, `ctrl+a` | Move to line start |
|
|
30
|
-
| `cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
|
|
31
|
-
| `jumpForward` | `ctrl+]` | Jump forward to character |
|
|
32
|
-
| `jumpBackward` | `ctrl+alt+]` | Jump backward to character |
|
|
33
|
-
| `pageUp` | `pageUp` | Scroll up by page |
|
|
34
|
-
| `pageDown` | `pageDown` | Scroll down by page |
|
|
35
|
-
|
|
36
|
-
### Deletion
|
|
37
|
-
|
|
38
|
-
|
|
|
29
|
+
| `tui.editor.cursorUp` | `up` | Move cursor up |
|
|
30
|
+
| `tui.editor.cursorDown` | `down` | Move cursor down |
|
|
31
|
+
| `tui.editor.cursorLeft` | `left`, `ctrl+b` | Move cursor left |
|
|
32
|
+
| `tui.editor.cursorRight` | `right`, `ctrl+f` | Move cursor right |
|
|
33
|
+
| `tui.editor.cursorWordLeft` | `alt+left`, `ctrl+left`, `alt+b` | Move cursor word left |
|
|
34
|
+
| `tui.editor.cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right |
|
|
35
|
+
| `tui.editor.cursorLineStart` | `home`, `ctrl+a` | Move to line start |
|
|
36
|
+
| `tui.editor.cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
|
|
37
|
+
| `tui.editor.jumpForward` | `ctrl+]` | Jump forward to character |
|
|
38
|
+
| `tui.editor.jumpBackward` | `ctrl+alt+]` | Jump backward to character |
|
|
39
|
+
| `tui.editor.pageUp` | `pageUp` | Scroll up by page |
|
|
40
|
+
| `tui.editor.pageDown` | `pageDown` | Scroll down by page |
|
|
41
|
+
|
|
42
|
+
### TUI Editor Deletion
|
|
43
|
+
|
|
44
|
+
| Keybinding id | Default | Description |
|
|
39
45
|
|--------|---------|-------------|
|
|
40
|
-
| `deleteCharBackward` | `backspace` | Delete character backward |
|
|
41
|
-
| `deleteCharForward` | `delete`, `ctrl+d` | Delete character forward |
|
|
42
|
-
| `deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
|
|
43
|
-
| `deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
|
|
44
|
-
| `deleteToLineStart` | `ctrl+u` | Delete to line start |
|
|
45
|
-
| `deleteToLineEnd` | `ctrl+k` | Delete to line end |
|
|
46
|
+
| `tui.editor.deleteCharBackward` | `backspace` | Delete character backward |
|
|
47
|
+
| `tui.editor.deleteCharForward` | `delete`, `ctrl+d` | Delete character forward |
|
|
48
|
+
| `tui.editor.deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
|
|
49
|
+
| `tui.editor.deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
|
|
50
|
+
| `tui.editor.deleteToLineStart` | `ctrl+u` | Delete to line start |
|
|
51
|
+
| `tui.editor.deleteToLineEnd` | `ctrl+k` | Delete to line end |
|
|
46
52
|
|
|
47
|
-
###
|
|
53
|
+
### TUI Input
|
|
48
54
|
|
|
49
|
-
|
|
|
55
|
+
| Keybinding id | Default | Description |
|
|
50
56
|
|--------|---------|-------------|
|
|
51
|
-
| `newLine` | `shift+enter` | Insert new line |
|
|
52
|
-
| `submit` | `enter` | Submit input |
|
|
53
|
-
| `tab` | `tab` | Tab / autocomplete |
|
|
57
|
+
| `tui.input.newLine` | `shift+enter` | Insert new line |
|
|
58
|
+
| `tui.input.submit` | `enter` | Submit input |
|
|
59
|
+
| `tui.input.tab` | `tab` | Tab / autocomplete |
|
|
54
60
|
|
|
55
|
-
### Kill Ring
|
|
61
|
+
### TUI Kill Ring
|
|
56
62
|
|
|
57
|
-
|
|
|
63
|
+
| Keybinding id | Default | Description |
|
|
58
64
|
|--------|---------|-------------|
|
|
59
|
-
| `yank` | `ctrl+y` | Paste most recently deleted text |
|
|
60
|
-
| `yankPop` | `alt+y` | Cycle through deleted text after yank |
|
|
61
|
-
| `undo` | `ctrl+-` | Undo last edit |
|
|
65
|
+
| `tui.editor.yank` | `ctrl+y` | Paste most recently deleted text |
|
|
66
|
+
| `tui.editor.yankPop` | `alt+y` | Cycle through deleted text after yank |
|
|
67
|
+
| `tui.editor.undo` | `ctrl+-` | Undo last edit |
|
|
62
68
|
|
|
63
|
-
### Clipboard
|
|
69
|
+
### TUI Clipboard and Selection
|
|
64
70
|
|
|
65
|
-
|
|
|
71
|
+
| Keybinding id | Default | Description |
|
|
66
72
|
|--------|---------|-------------|
|
|
67
|
-
| `copy` | `ctrl+c` | Copy selection |
|
|
68
|
-
| `
|
|
73
|
+
| `tui.input.copy` | `ctrl+c` | Copy selection |
|
|
74
|
+
| `tui.select.up` | `up` | Move selection up |
|
|
75
|
+
| `tui.select.down` | `down` | Move selection down |
|
|
76
|
+
| `tui.select.pageUp` | `pageUp` | Page up in list |
|
|
77
|
+
| `tui.select.pageDown` | `pageDown` | Page down in list |
|
|
78
|
+
| `tui.select.confirm` | `enter` | Confirm selection |
|
|
79
|
+
| `tui.select.cancel` | `escape`, `ctrl+c` | Cancel selection |
|
|
69
80
|
|
|
70
81
|
### Application
|
|
71
82
|
|
|
72
|
-
|
|
|
73
|
-
|--------|---------|-------------|
|
|
74
|
-
| `interrupt` | `escape` | Cancel / abort |
|
|
75
|
-
| `clear` | `ctrl+c` | Clear editor |
|
|
76
|
-
| `exit` | `ctrl+d` | Exit (when editor empty) |
|
|
77
|
-
| `suspend` | `ctrl+z` | Suspend to background |
|
|
78
|
-
| `externalEditor` | `ctrl+g` | Open in external editor (`$VISUAL` or `$EDITOR`) |
|
|
79
|
-
|
|
80
|
-
### Session
|
|
81
|
-
|
|
82
|
-
| Action | Default | Description |
|
|
83
|
-
|--------|---------|-------------|
|
|
84
|
-
| `newSession` | *(none)* | Start a new session (`/new`) |
|
|
85
|
-
| `tree` | *(none)* | Open session tree navigator (`/tree`) |
|
|
86
|
-
| `fork` | *(none)* | Fork current session (`/fork`) |
|
|
87
|
-
| `resume` | *(none)* | Open session resume picker (`/resume`) |
|
|
88
|
-
|
|
89
|
-
### Models & Thinking
|
|
90
|
-
|
|
91
|
-
| Action | Default | Description |
|
|
83
|
+
| Keybinding id | Default | Description |
|
|
92
84
|
|--------|---------|-------------|
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
85
|
+
| `app.interrupt` | `escape` | Cancel / abort |
|
|
86
|
+
| `app.clear` | `ctrl+c` | Clear editor |
|
|
87
|
+
| `app.exit` | `ctrl+d` | Exit (when editor empty) |
|
|
88
|
+
| `app.suspend` | `ctrl+z` | Suspend to background |
|
|
89
|
+
| `app.editor.external` | `ctrl+g` | Open in external editor (`$VISUAL` or `$EDITOR`) |
|
|
90
|
+
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image from clipboard |
|
|
97
91
|
|
|
98
|
-
###
|
|
92
|
+
### Sessions
|
|
99
93
|
|
|
100
|
-
|
|
|
94
|
+
| Keybinding id | Default | Description |
|
|
101
95
|
|--------|---------|-------------|
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
|
96
|
+
| `app.session.new` | *(none)* | Start a new session (`/new`) |
|
|
97
|
+
| `app.session.tree` | *(none)* | Open session tree navigator (`/tree`) |
|
|
98
|
+
| `app.session.fork` | *(none)* | Fork current session (`/fork`) |
|
|
99
|
+
| `app.session.resume` | *(none)* | Open session resume picker (`/resume`) |
|
|
100
|
+
| `app.session.togglePath` | `ctrl+p` | Toggle path display |
|
|
101
|
+
| `app.session.toggleSort` | `ctrl+s` | Toggle sort mode |
|
|
102
|
+
| `app.session.toggleNamedFilter` | `ctrl+n` | Toggle named-only filter |
|
|
103
|
+
| `app.session.rename` | `ctrl+r` | Rename session |
|
|
104
|
+
| `app.session.delete` | `ctrl+d` | Delete session |
|
|
105
|
+
| `app.session.deleteNoninvasive` | `ctrl+backspace` | Delete session when query is empty |
|
|
106
|
+
|
|
107
|
+
### Models and Thinking
|
|
108
|
+
|
|
109
|
+
| Keybinding id | Default | Description |
|
|
108
110
|
|--------|---------|-------------|
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
+
| `app.model.select` | `ctrl+l` | Open model selector |
|
|
112
|
+
| `app.model.cycleForward` | `ctrl+p` | Cycle to next model |
|
|
113
|
+
| `app.model.cycleBackward` | `shift+ctrl+p` | Cycle to previous model |
|
|
114
|
+
| `app.thinking.cycle` | `shift+tab` | Cycle thinking level |
|
|
115
|
+
| `app.thinking.toggle` | `ctrl+t` | Collapse or expand thinking blocks |
|
|
111
116
|
|
|
112
|
-
###
|
|
117
|
+
### Display and Message Queue
|
|
113
118
|
|
|
114
|
-
|
|
|
119
|
+
| Keybinding id | Default | Description |
|
|
115
120
|
|--------|---------|-------------|
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `selectPageDown` | `pageDown` | Page down in list |
|
|
120
|
-
| `selectConfirm` | `enter` | Confirm selection |
|
|
121
|
-
| `selectCancel` | `escape`, `ctrl+c` | Cancel selection |
|
|
121
|
+
| `app.tools.expand` | `ctrl+o` | Collapse or expand tool output |
|
|
122
|
+
| `app.message.followUp` | `alt+enter` | Queue follow-up message |
|
|
123
|
+
| `app.message.dequeue` | `alt+up` | Restore queued messages to editor |
|
|
122
124
|
|
|
123
125
|
### Tree Navigation
|
|
124
126
|
|
|
125
|
-
|
|
|
126
|
-
|--------|---------|-------------|
|
|
127
|
-
| `treeFoldOrUp` | `ctrl+left`, `alt+left` | Fold current branch segment, or jump to the previous segment start |
|
|
128
|
-
| `treeUnfoldOrDown` | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
|
|
129
|
-
|
|
130
|
-
### Session Picker
|
|
131
|
-
|
|
132
|
-
| Action | Default | Description |
|
|
127
|
+
| Keybinding id | Default | Description |
|
|
133
128
|
|--------|---------|-------------|
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `toggleSessionNamedFilter` | `ctrl+n` | Toggle named-only filter |
|
|
137
|
-
| `renameSession` | `ctrl+r` | Rename session |
|
|
138
|
-
| `deleteSession` | `ctrl+d` | Delete session |
|
|
139
|
-
| `deleteSessionNoninvasive` | `ctrl+backspace` | Delete session (when query empty) |
|
|
129
|
+
| `app.tree.foldOrUp` | `ctrl+left`, `alt+left` | Fold current branch segment, or jump to the previous segment start |
|
|
130
|
+
| `app.tree.unfoldOrDown` | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
|
|
140
131
|
|
|
141
132
|
## Custom Configuration
|
|
142
133
|
|
|
@@ -144,9 +135,9 @@ Create `~/.pi/agent/keybindings.json`:
|
|
|
144
135
|
|
|
145
136
|
```json
|
|
146
137
|
{
|
|
147
|
-
"cursorUp": ["up", "ctrl+p"],
|
|
148
|
-
"cursorDown": ["down", "ctrl+n"],
|
|
149
|
-
"deleteWordBackward": ["ctrl+w", "alt+backspace"]
|
|
138
|
+
"tui.editor.cursorUp": ["up", "ctrl+p"],
|
|
139
|
+
"tui.editor.cursorDown": ["down", "ctrl+n"],
|
|
140
|
+
"tui.editor.deleteWordBackward": ["ctrl+w", "alt+backspace"]
|
|
150
141
|
}
|
|
151
142
|
```
|
|
152
143
|
|
|
@@ -156,15 +147,15 @@ Each action can have a single key or an array of keys. User config overrides def
|
|
|
156
147
|
|
|
157
148
|
```json
|
|
158
149
|
{
|
|
159
|
-
"cursorUp": ["up", "ctrl+p"],
|
|
160
|
-
"cursorDown": ["down", "ctrl+n"],
|
|
161
|
-
"cursorLeft": ["left", "ctrl+b"],
|
|
162
|
-
"cursorRight": ["right", "ctrl+f"],
|
|
163
|
-
"cursorWordLeft": ["alt+left", "alt+b"],
|
|
164
|
-
"cursorWordRight": ["alt+right", "alt+f"],
|
|
165
|
-
"deleteCharForward": ["delete", "ctrl+d"],
|
|
166
|
-
"deleteCharBackward": ["backspace", "ctrl+h"],
|
|
167
|
-
"newLine": ["shift+enter", "ctrl+j"]
|
|
150
|
+
"tui.editor.cursorUp": ["up", "ctrl+p"],
|
|
151
|
+
"tui.editor.cursorDown": ["down", "ctrl+n"],
|
|
152
|
+
"tui.editor.cursorLeft": ["left", "ctrl+b"],
|
|
153
|
+
"tui.editor.cursorRight": ["right", "ctrl+f"],
|
|
154
|
+
"tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
|
|
155
|
+
"tui.editor.cursorWordRight": ["alt+right", "alt+f"],
|
|
156
|
+
"tui.editor.deleteCharForward": ["delete", "ctrl+d"],
|
|
157
|
+
"tui.editor.deleteCharBackward": ["backspace", "ctrl+h"],
|
|
158
|
+
"tui.input.newLine": ["shift+enter", "ctrl+j"]
|
|
168
159
|
}
|
|
169
160
|
```
|
|
170
161
|
|
|
@@ -172,11 +163,11 @@ Each action can have a single key or an array of keys. User config overrides def
|
|
|
172
163
|
|
|
173
164
|
```json
|
|
174
165
|
{
|
|
175
|
-
"cursorUp": ["up", "alt+k"],
|
|
176
|
-
"cursorDown": ["down", "alt+j"],
|
|
177
|
-
"cursorLeft": ["left", "alt+h"],
|
|
178
|
-
"cursorRight": ["right", "alt+l"],
|
|
179
|
-
"cursorWordLeft": ["alt+left", "alt+b"],
|
|
180
|
-
"cursorWordRight": ["alt+right", "alt+w"]
|
|
166
|
+
"tui.editor.cursorUp": ["up", "alt+k"],
|
|
167
|
+
"tui.editor.cursorDown": ["down", "alt+j"],
|
|
168
|
+
"tui.editor.cursorLeft": ["left", "alt+h"],
|
|
169
|
+
"tui.editor.cursorRight": ["right", "alt+l"],
|
|
170
|
+
"tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
|
|
171
|
+
"tui.editor.cursorWordRight": ["alt+right", "alt+w"]
|
|
181
172
|
}
|
|
182
173
|
```
|
package/docs/models.md
CHANGED
|
@@ -35,6 +35,32 @@ For local models (Ollama, LM Studio, vLLM), only `id` is required per model:
|
|
|
35
35
|
|
|
36
36
|
The `apiKey` is required but Ollama ignores it, so any value works.
|
|
37
37
|
|
|
38
|
+
Some OpenAI-compatible servers do not understand the `developer` role used for reasoning-capable models. For those providers, set `compat.supportsDeveloperRole` to `false` so pi sends the system prompt as a `system` message instead. If the server also does not support `reasoning_effort`, set `compat.supportsReasoningEffort` to `false` too.
|
|
39
|
+
|
|
40
|
+
You can set `compat` at the provider level to apply to all models, or at the model level to override a specific model. This commonly applies to Ollama, vLLM, SGLang, and similar OpenAI-compatible servers.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"providers": {
|
|
45
|
+
"ollama": {
|
|
46
|
+
"baseUrl": "http://localhost:11434/v1",
|
|
47
|
+
"api": "openai-completions",
|
|
48
|
+
"apiKey": "ollama",
|
|
49
|
+
"compat": {
|
|
50
|
+
"supportsDeveloperRole": false,
|
|
51
|
+
"supportsReasoningEffort": false
|
|
52
|
+
},
|
|
53
|
+
"models": [
|
|
54
|
+
{
|
|
55
|
+
"id": "gpt-oss:20b",
|
|
56
|
+
"reasoning": true
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
38
64
|
## Full Example
|
|
39
65
|
|
|
40
66
|
Override defaults when you need specific values:
|
|
@@ -136,6 +162,7 @@ The `apiKey` and `headers` fields support three formats:
|
|
|
136
162
|
| `contextWindow` | No | `128000` | Context window size in tokens |
|
|
137
163
|
| `maxTokens` | No | `16384` | Maximum output tokens |
|
|
138
164
|
| `cost` | No | all zeros | `{"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}` (per million tokens) |
|
|
165
|
+
| `compat` | No | provider `compat` | OpenAI compatibility overrides. Merged with provider-level `compat` when both are set. |
|
|
139
166
|
|
|
140
167
|
Current behavior:
|
|
141
168
|
- `/model` and `--list-models` list entries by model `id`.
|
|
@@ -211,7 +238,10 @@ Behavior notes:
|
|
|
211
238
|
|
|
212
239
|
## OpenAI Compatibility
|
|
213
240
|
|
|
214
|
-
For providers with partial OpenAI compatibility, use the `compat` field
|
|
241
|
+
For providers with partial OpenAI compatibility, use the `compat` field.
|
|
242
|
+
|
|
243
|
+
- Provider-level `compat` applies defaults to all models under that provider.
|
|
244
|
+
- Model-level `compat` overrides provider-level values for that model.
|
|
215
245
|
|
|
216
246
|
```json
|
|
217
247
|
{
|
|
@@ -234,11 +264,19 @@ For providers with partial OpenAI compatibility, use the `compat` field:
|
|
|
234
264
|
| `supportsStore` | Provider supports `store` field |
|
|
235
265
|
| `supportsDeveloperRole` | Use `developer` vs `system` role |
|
|
236
266
|
| `supportsReasoningEffort` | Support for `reasoning_effort` parameter |
|
|
267
|
+
| `reasoningEffortMap` | Map pi thinking levels to provider-specific `reasoning_effort` values |
|
|
237
268
|
| `supportsUsageInStreaming` | Supports `stream_options: { include_usage: true }` (default: `true`) |
|
|
238
269
|
| `maxTokensField` | Use `max_completion_tokens` or `max_tokens` |
|
|
270
|
+
| `requiresToolResultName` | Include `name` on tool result messages |
|
|
271
|
+
| `requiresAssistantAfterToolResult` | Insert an assistant message before a user message after tool results |
|
|
272
|
+
| `requiresThinkingAsText` | Convert thinking blocks to plain text |
|
|
273
|
+
| `thinkingFormat` | Use `reasoning_effort`, `zai`, `qwen`, or `qwen-chat-template` thinking parameters |
|
|
274
|
+
| `supportsStrictMode` | Include the `strict` field in tool definitions |
|
|
239
275
|
| `openRouterRouting` | OpenRouter routing config passed to OpenRouter for model/provider selection |
|
|
240
276
|
| `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
|
|
241
277
|
|
|
278
|
+
`qwen` uses top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that require `chat_template_kwargs.enable_thinking`.
|
|
279
|
+
|
|
242
280
|
Example:
|
|
243
281
|
|
|
244
282
|
```json
|
package/docs/packages.md
CHANGED
|
@@ -54,6 +54,15 @@ npm:pkg
|
|
|
54
54
|
- Versioned specs are pinned and skipped by `pi update`.
|
|
55
55
|
- Global installs use `npm install -g`.
|
|
56
56
|
- Project installs go under `.pi/npm/`.
|
|
57
|
+
- Set `npmCommand` in `settings.json` to pin npm package lookup and install operations to a specific wrapper command such as `mise` or `asdf`.
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"npmCommand": ["mise", "exec", "node@20", "--", "npm"]
|
|
64
|
+
}
|
|
65
|
+
```
|
|
57
66
|
|
|
58
67
|
### git
|
|
59
68
|
|
package/docs/providers.md
CHANGED
|
@@ -147,6 +147,13 @@ Also supports ECS task roles (`AWS_CONTAINER_CREDENTIALS_*`) and IRSA (`AWS_WEB_
|
|
|
147
147
|
pi --provider amazon-bedrock --model us.anthropic.claude-sonnet-4-20250514-v1:0
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
Prompt caching is enabled automatically for Claude models whose ID contains a recognizable model name (base models and system-defined inference profiles). For application inference profiles (whose ARNs don't contain the model name), set `AWS_BEDROCK_FORCE_CACHE=1` to enable cache points:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
export AWS_BEDROCK_FORCE_CACHE=1
|
|
154
|
+
pi --provider amazon-bedrock --model arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/abc123
|
|
155
|
+
```
|
|
156
|
+
|
|
150
157
|
If you are connecting to a Bedrock API proxy, the following environment variables can be used:
|
|
151
158
|
|
|
152
159
|
```bash
|