apex-code 0.5.0 → 0.5.1
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 +257 -5
- package/README.md +624 -0
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +3 -9
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/runtime-setup.d.ts +2 -0
- package/dist/bun/runtime-setup.d.ts.map +1 -0
- package/dist/bun/runtime-setup.js +9 -0
- package/dist/bun/runtime-setup.js.map +1 -0
- package/dist/bun/sandbox-env-setup.d.ts +2 -0
- package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
- package/dist/bun/sandbox-env-setup.js +4 -0
- package/dist/bun/sandbox-env-setup.js.map +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +16 -5
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +2 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.d.ts +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +13 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +16 -8
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +85 -15
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +685 -266
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +55 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bug-report.d.ts +176 -0
- package/dist/core/bug-report.d.ts.map +1 -0
- package/dist/core/bug-report.js +291 -0
- package/dist/core/bug-report.js.map +1 -0
- package/dist/core/cache-stats.d.ts.map +1 -1
- package/dist/core/cache-stats.js +12 -1
- package/dist/core/cache-stats.js.map +1 -1
- package/dist/core/cache-warmer.d.ts +103 -0
- package/dist/core/cache-warmer.d.ts.map +1 -0
- package/dist/core/cache-warmer.js +356 -0
- package/dist/core/cache-warmer.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +4 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +5 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +163 -66
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context/pipeline.d.ts +8 -8
- package/dist/core/context/pipeline.d.ts.map +1 -1
- package/dist/core/context/pipeline.js +21 -12
- package/dist/core/context/pipeline.js.map +1 -1
- package/dist/core/crash-log.d.ts +27 -0
- package/dist/core/crash-log.d.ts.map +1 -0
- package/dist/core/crash-log.js +139 -0
- package/dist/core/crash-log.js.map +1 -0
- package/dist/core/export-html/template.js +6 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/jiti-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-loader.js +4 -0
- package/dist/core/extensions/jiti-loader.js.map +1 -0
- package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-static-loader.js +4 -0
- package/dist/core/extensions/jiti-static-loader.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +40 -59
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +24 -8
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +195 -72
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +142 -55
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts +3 -0
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/virtual-modules.js +41 -0
- package/dist/core/extensions/virtual-modules.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +1 -20
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +2 -0
- package/dist/core/http-dispatcher.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.map +1 -1
- package/dist/core/keybindings.d.ts +6 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +5 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +168 -20
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +44 -18
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +8 -0
- 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 +4 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +1 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +12 -6
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/permissions/store.d.ts.map +1 -1
- package/dist/core/permissions/store.js +11 -8
- package/dist/core/permissions/store.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +6 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +61 -35
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-composer.d.ts +4 -2
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +29 -2
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/radius.d.ts +3 -0
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +6 -0
- package/dist/core/radius.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +6 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +63 -42
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +6 -2
- package/dist/core/session-export.d.ts.map +1 -1
- package/dist/core/session-export.js +14 -13
- package/dist/core/session-export.js.map +1 -1
- package/dist/core/session-manager.d.ts +66 -15
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +295 -115
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +27 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +55 -7
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +5 -4
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +49 -6
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +140 -79
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +7 -8
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +20 -115
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +1 -12
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +6 -204
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +4 -55
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +4 -60
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +4 -49
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +4 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +10 -125
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts +18 -0
- package/dist/core/tools/renderers/bash.d.ts.map +1 -0
- package/dist/core/tools/renderers/bash.js +126 -0
- package/dist/core/tools/renderers/bash.js.map +1 -0
- package/dist/core/tools/renderers/edit.d.ts +23 -0
- package/dist/core/tools/renderers/edit.d.ts.map +1 -0
- package/dist/core/tools/renderers/edit.js +207 -0
- package/dist/core/tools/renderers/edit.js.map +1 -0
- package/dist/core/tools/renderers/find.d.ts +10 -0
- package/dist/core/tools/renderers/find.d.ts.map +1 -0
- package/dist/core/tools/renderers/find.js +64 -0
- package/dist/core/tools/renderers/find.js.map +1 -0
- package/dist/core/tools/renderers/grep.d.ts +10 -0
- package/dist/core/tools/renderers/grep.d.ts.map +1 -0
- package/dist/core/tools/renderers/grep.js +69 -0
- package/dist/core/tools/renderers/grep.js.map +1 -0
- package/dist/core/tools/renderers/index.d.ts +34 -0
- package/dist/core/tools/renderers/index.d.ts.map +1 -0
- package/dist/core/tools/renderers/index.js +47 -0
- package/dist/core/tools/renderers/index.js.map +1 -0
- package/dist/core/tools/renderers/ls.d.ts +10 -0
- package/dist/core/tools/renderers/ls.d.ts.map +1 -0
- package/dist/core/tools/renderers/ls.js +58 -0
- package/dist/core/tools/renderers/ls.js.map +1 -0
- package/dist/core/tools/renderers/read.d.ts +11 -0
- package/dist/core/tools/renderers/read.d.ts.map +1 -0
- package/dist/core/tools/renderers/read.js +132 -0
- package/dist/core/tools/renderers/read.js.map +1 -0
- package/dist/core/tools/renderers/write.d.ts +10 -0
- package/dist/core/tools/renderers/write.d.ts.map +1 -0
- package/dist/core/tools/renderers/write.js +152 -0
- package/dist/core/tools/renderers/write.js.map +1 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +6 -146
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/usage-totals.d.ts +1 -1
- package/dist/core/usage-totals.d.ts.map +1 -1
- package/dist/core/usage-totals.js +5 -1
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/extensions/llama/client.d.ts +2 -0
- package/dist/extensions/llama/client.d.ts.map +1 -1
- package/dist/extensions/llama/client.js +7 -3
- package/dist/extensions/llama/client.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +20 -5
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +21 -13
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/bug-report.d.ts +16 -0
- package/dist/modes/interactive/bug-report.d.ts.map +1 -0
- package/dist/modes/interactive/bug-report.js +167 -0
- package/dist/modes/interactive/bug-report.js.map +1 -0
- package/dist/modes/interactive/chat-viewport.d.ts +20 -0
- package/dist/modes/interactive/chat-viewport.d.ts.map +1 -0
- package/dist/modes/interactive/chat-viewport.js +28 -0
- package/dist/modes/interactive/chat-viewport.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +7 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +63 -17
- package/dist/modes/interactive/components/assistant-message.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 +12 -5
- 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 +12 -5
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +12 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +38 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/error-summary.d.ts +11 -0
- package/dist/modes/interactive/components/error-summary.d.ts.map +1 -0
- package/dist/modes/interactive/components/error-summary.js +31 -0
- package/dist/modes/interactive/components/error-summary.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +6 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +6 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +2 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/footer.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.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +3 -3
- package/dist/modes/interactive/components/model-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 +13 -15
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +74 -48
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +5 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +35 -10
- package/dist/modes/interactive/components/settings-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 +11 -4
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +10 -3
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +6 -6
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +27 -5
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +64 -42
- 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 +9 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/trust-selector.js +2 -2
- package/dist/modes/interactive/components/trust-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +43 -29
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +431 -166
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +5 -0
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
- package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-json.js +130 -0
- package/dist/modes/interactive/theme/theme-json.js.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.json +6 -2
- package/dist/modes/interactive/theme/theme.d.ts +14 -5
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +18 -119
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/interactive/tui-renderer.d.ts +21 -0
- package/dist/modes/interactive/tui-renderer.d.ts.map +1 -0
- package/dist/modes/interactive/tui-renderer.js +66 -0
- package/dist/modes/interactive/tui-renderer.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/testing/replay/recorded-provider.d.ts +2 -2
- package/dist/testing/replay/recorded-provider.d.ts.map +1 -1
- package/dist/testing/replay/recorded-provider.js +2 -5
- package/dist/testing/replay/recorded-provider.js.map +1 -1
- package/dist/testing/replay/runner.d.ts.map +1 -1
- package/dist/testing/replay/runner.js +0 -1
- package/dist/testing/replay/runner.js.map +1 -1
- package/dist/utils/clipboard-command.d.ts +7 -0
- package/dist/utils/clipboard-command.d.ts.map +1 -0
- package/dist/utils/clipboard-command.js +45 -0
- package/dist/utils/clipboard-command.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +53 -81
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +111 -121
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js +2 -3
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +21 -21
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tool-result-images.d.ts +3 -1
- package/dist/utils/tool-result-images.d.ts.map +1 -1
- package/dist/utils/tool-result-images.js +4 -1
- package/dist/utils/tool-result-images.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +11 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/wsl.d.ts +3 -0
- package/dist/utils/wsl.d.ts.map +1 -0
- package/dist/utils/wsl.js +15 -0
- package/dist/utils/wsl.js.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/dist/utils/zip.js +60 -0
- package/dist/utils/zip.js.map +1 -0
- package/docs/cli-integration.md +107 -0
- package/docs/cli.md +269 -0
- package/docs/compaction.md +73 -24
- package/docs/configuration.md +45 -0
- package/docs/containerization.md +22 -21
- package/docs/custom-provider.md +21 -12
- package/docs/development.md +19 -0
- package/docs/docs.json +139 -95
- package/docs/extensions.md +243 -371
- package/docs/how-pi-works.md +49 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/index.md +3 -3
- package/docs/json.md +7 -3
- package/docs/keybindings.md +57 -54
- package/docs/llama-cpp.md +2 -2
- package/docs/message-types.md +261 -0
- package/docs/models.md +103 -49
- package/docs/packages.md +49 -47
- package/docs/prompt-templates.md +29 -56
- package/docs/providers.md +91 -139
- package/docs/quickstart.md +42 -14
- package/docs/rpc-commands.md +854 -0
- package/docs/rpc-extension-ui.md +200 -0
- package/docs/rpc.md +121 -223
- package/docs/sdk.md +99 -124
- package/docs/security.md +7 -7
- package/docs/session-format.md +85 -82
- package/docs/sessions.md +41 -57
- package/docs/settings.md +94 -87
- package/docs/shell-aliases.md +68 -3
- package/docs/skills.md +62 -49
- package/docs/slash-commands.md +60 -0
- package/docs/terminal-setup.md +86 -55
- package/docs/termux.md +65 -75
- package/docs/themes.md +64 -86
- package/docs/tmux.md +29 -7
- package/docs/tui.md +67 -122
- package/docs/usage.md +31 -42
- package/docs/windows.md +41 -13
- package/examples/README.md +16 -2
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
- 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/index.ts +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +2 -0
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/prompt-customizer.ts +19 -67
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/plugins/pi-example-plugin/README.md +38 -0
- package/examples/plugins/pi-example-plugin/package.json +10 -0
- package/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
- package/examples/plugins/pi-example-plugin/src/session.ts +24 -0
- package/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
- package/examples/rpc-client.ts +35 -0
- package/examples/rpc-extension-ui.ts +25 -5
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +861 -513
- package/package.json +27 -18
- package/dist/bun/register-bedrock.d.ts +0 -2
- package/dist/bun/register-bedrock.d.ts.map +0 -1
- package/dist/bun/register-bedrock.js +0 -4
- package/dist/bun/register-bedrock.js.map +0 -1
- package/dist/cli/experimental/auth.d.ts +0 -16
- package/dist/cli/experimental/auth.d.ts.map +0 -1
- package/dist/cli/experimental/auth.js +0 -13
- package/dist/cli/experimental/auth.js.map +0 -1
- package/dist/cli/experimental/cli.d.ts +0 -6
- package/dist/cli/experimental/cli.d.ts.map +0 -1
- package/dist/cli/experimental/cli.js +0 -5
- package/dist/cli/experimental/cli.js.map +0 -1
- package/dist/cli/experimental/command-options.d.ts +0 -17
- package/dist/cli/experimental/command-options.d.ts.map +0 -1
- package/dist/cli/experimental/command-options.js +0 -35
- package/dist/cli/experimental/command-options.js.map +0 -1
- package/dist/cli/experimental/command.d.ts +0 -63
- package/dist/cli/experimental/command.d.ts.map +0 -1
- package/dist/cli/experimental/command.js +0 -130
- package/dist/cli/experimental/command.js.map +0 -1
- package/dist/cli/experimental/commands/client.d.ts +0 -13
- package/dist/cli/experimental/commands/client.d.ts.map +0 -1
- package/dist/cli/experimental/commands/client.js +0 -25
- package/dist/cli/experimental/commands/client.js.map +0 -1
- package/dist/cli/experimental/commands/pi.d.ts +0 -15
- package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
- package/dist/cli/experimental/commands/pi.js +0 -28
- package/dist/cli/experimental/commands/pi.js.map +0 -1
- package/dist/cli/experimental/commands/server.d.ts +0 -13
- package/dist/cli/experimental/commands/server.d.ts.map +0 -1
- package/dist/cli/experimental/commands/server.js +0 -25
- package/dist/cli/experimental/commands/server.js.map +0 -1
- package/dist/cli/experimental/transport-address.d.ts +0 -10
- package/dist/cli/experimental/transport-address.d.ts.map +0 -1
- package/dist/cli/experimental/transport-address.js +0 -38
- package/dist/cli/experimental/transport-address.js.map +0 -1
- package/dist/client/index.d.ts +0 -3
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -3
- package/dist/client/index.js.map +0 -1
- package/dist/client/remote-session.d.ts +0 -53
- package/dist/client/remote-session.d.ts.map +0 -1
- package/dist/client/remote-session.js +0 -340
- package/dist/client/remote-session.js.map +0 -1
- package/dist/client/transcript.d.ts +0 -12
- package/dist/client/transcript.d.ts.map +0 -1
- package/dist/client/transcript.js +0 -98
- package/dist/client/transcript.js.map +0 -1
- package/dist/utils/clipboard-native.d.ts +0 -11
- package/dist/utils/clipboard-native.d.ts.map +0 -1
- package/dist/utils/clipboard-native.js +0 -20
- package/dist/utils/clipboard-native.js.map +0 -1
package/docs/extensions.md
CHANGED
|
@@ -6,29 +6,15 @@ Extensions are TypeScript modules that extend Apex Code's behavior. They can sub
|
|
|
6
6
|
|
|
7
7
|
> **Placement for /reload:** Put extensions in `~/.apex-code/agent/extensions/` (global) or `.apex-code/extensions/` (project-local) for auto-discovery. Use `apex-code -e ./path.ts` only for quick tests. Extensions in auto-discovered locations can be hot-reloaded with `/reload`.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
**Example use cases:**
|
|
19
|
-
- Permission gates (confirm before `rm -rf`, `sudo`, etc.)
|
|
20
|
-
- Git checkpointing (stash at each turn, restore on branch)
|
|
21
|
-
- Path protection (block writes to `.env`, `node_modules/`)
|
|
22
|
-
- Custom compaction (summarize conversation your way)
|
|
23
|
-
- Conversation summaries (see `summarize.ts` example)
|
|
24
|
-
- Interactive tools (questions, wizards, custom dialogs)
|
|
25
|
-
- Stateful tools (todo lists, connection pools)
|
|
26
|
-
- External integrations (file watchers, webhooks, CI triggers)
|
|
27
|
-
- Games while you wait (see `snake.ts` example)
|
|
28
|
-
|
|
29
|
-
See [examples/extensions/](../examples/extensions/) for working implementations.
|
|
30
|
-
|
|
31
|
-
## Table of Contents
|
|
9
|
+
Typical extensions add an agent tool, protect paths, confirm dangerous commands, react to session events, modify context, expose a command, or display persistent status.
|
|
10
|
+
|
|
11
|
+
<a id="quick-start"></a>
|
|
12
|
+
<a id="writing-an-extension"></a>
|
|
13
|
+
<a id="create-an-extension"></a>
|
|
14
|
+
|
|
15
|
+
## Create and load an extension
|
|
16
|
+
|
|
17
|
+
An extension exports a default factory that receives `ExtensionAPI`. The factory registers capabilities for the current extension runtime.
|
|
32
18
|
|
|
33
19
|
- [Quick Start](#quick-start)
|
|
34
20
|
- [Extension Locations](#extension-locations)
|
|
@@ -62,53 +48,26 @@ import type { ExtensionAPI } from "apex-code";
|
|
|
62
48
|
import { Type } from "typebox";
|
|
63
49
|
|
|
64
50
|
export default function (pi: ExtensionAPI) {
|
|
65
|
-
// React to events
|
|
66
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
67
|
-
ctx.ui.notify("Extension loaded!", "info");
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
pi.on("tool_call", async (event, ctx) => {
|
|
71
|
-
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
|
|
72
|
-
const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
|
|
73
|
-
if (!ok) return { block: true, reason: "Blocked by user" };
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Register a custom tool
|
|
78
|
-
pi.registerTool({
|
|
79
|
-
name: "greet",
|
|
80
|
-
label: "Greet",
|
|
81
|
-
description: "Greet someone by name",
|
|
82
|
-
parameters: Type.Object({
|
|
83
|
-
name: Type.String({ description: "Name to greet" }),
|
|
84
|
-
}),
|
|
85
|
-
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
86
|
-
return {
|
|
87
|
-
content: [{ type: "text", text: `Hello, ${params.name}!` }],
|
|
88
|
-
details: {},
|
|
89
|
-
};
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Register a command
|
|
94
51
|
pi.registerCommand("hello", {
|
|
95
|
-
description: "
|
|
96
|
-
handler: async (
|
|
97
|
-
ctx.ui.notify(`Hello ${
|
|
52
|
+
description: "Show a greeting",
|
|
53
|
+
handler: async (name, ctx) => {
|
|
54
|
+
ctx.ui.notify(`Hello, ${name || "world"}!`, "info");
|
|
98
55
|
},
|
|
99
56
|
});
|
|
100
57
|
}
|
|
101
58
|
```
|
|
102
59
|
|
|
103
|
-
|
|
60
|
+
Start Pi and run `/hello`. During development, load a file directly:
|
|
104
61
|
|
|
105
62
|
```bash
|
|
106
63
|
apex-code -e ./my-extension.ts
|
|
107
64
|
```
|
|
108
65
|
|
|
109
|
-
|
|
66
|
+
Pi uses `jiti`, so local TypeScript extensions do not need a separate compilation step. Use [Pi packages](packages.md) for distributed extensions and dependencies.
|
|
110
67
|
|
|
111
|
-
>
|
|
68
|
+
<a id="extension-locations"></a>
|
|
69
|
+
<a id="available-imports"></a>
|
|
70
|
+
<a id="choose-where-it-loads"></a>
|
|
112
71
|
|
|
113
72
|
Extensions are auto-discovered from trusted locations. Project-local `.apex-code/extensions` entries load only after the project is trusted.
|
|
114
73
|
|
|
@@ -119,7 +78,7 @@ Extensions are auto-discovered from trusted locations. Project-local `.apex-code
|
|
|
119
78
|
| `.apex-code/extensions/*.ts` | Project-local |
|
|
120
79
|
| `.apex-code/extensions/*/index.ts` | Project-local (subdirectory) |
|
|
121
80
|
|
|
122
|
-
|
|
81
|
+
Use a single file for a small extension and a directory for a multi-file implementation. Put npm dependencies in a nearby `package.json`. See [Configuration](configuration.md) for conventional locations and [Settings](settings.md#resources) for additional paths.
|
|
123
82
|
|
|
124
83
|
```json
|
|
125
84
|
{
|
|
@@ -294,7 +253,8 @@ user sends prompt ────────────────────
|
|
|
294
253
|
│ ┌─── turn (repeats while LLM calls tools) ───┐ │
|
|
295
254
|
│ │ │ │
|
|
296
255
|
│ ├─► turn_start │ │
|
|
297
|
-
│ ├─► context (can modify messages)
|
|
256
|
+
│ ├─► context (can modify conversation messages) │
|
|
257
|
+
│ ├─► context_with_system (can modify the full transcript)
|
|
298
258
|
│ ├─► before_provider_headers (can mutate headers) |
|
|
299
259
|
│ ├─► before_provider_request (can inspect or replace payload)
|
|
300
260
|
│ ├─► after_provider_response (status + headers, before stream consume)
|
|
@@ -307,9 +267,13 @@ user sends prompt ────────────────────
|
|
|
307
267
|
│ │ └─► tool_execution_end │ │
|
|
308
268
|
│ │ │ │
|
|
309
269
|
│ └─► turn_end │ │
|
|
270
|
+
│ └─► threshold compaction before a naturally required next turn
|
|
310
271
|
│ │
|
|
311
272
|
├─► agent_end │
|
|
312
|
-
|
|
273
|
+
├─► retry backoff or final-attempt recovery (when selected)
|
|
274
|
+
│ └─► fresh agent_start on successful recovery │
|
|
275
|
+
├─► agent_before_settle (can append entries and continue)│
|
|
276
|
+
└─► agent_settled (final, notification only) │
|
|
313
277
|
│
|
|
314
278
|
user sends another prompt ◄────────────────────────────────┘
|
|
315
279
|
|
|
@@ -538,10 +502,13 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
538
502
|
// event.systemPrompt - current chained system prompt for this handler
|
|
539
503
|
// (includes changes from earlier before_agent_start handlers)
|
|
540
504
|
// event.systemPromptOptions - structured options used to build the system prompt
|
|
541
|
-
// .customPrompt -
|
|
505
|
+
// .customPrompt - exact prompt prefix from --system-prompt, SYSTEM.md, or custom templates
|
|
506
|
+
// .forceSystemPrompt - optional exact replacement for the complete prompt
|
|
542
507
|
// .selectedTools - tools currently active in the prompt
|
|
543
508
|
// .toolSnippets - one-line descriptions for each tool
|
|
544
|
-
// .
|
|
509
|
+
// .toolGuidelines - guideline bullets keyed by tool name
|
|
510
|
+
// .promptGuidelines - additional custom guideline bullets
|
|
511
|
+
// .sections - custom XML-wrapped sections keyed by tag name
|
|
545
512
|
// .appendSystemPrompt - text from --append-system-prompt flags
|
|
546
513
|
// .cwd - working directory
|
|
547
514
|
// .contextFiles - AGENTS.md files and other loaded context files
|
|
@@ -564,9 +531,9 @@ The `systemPromptOptions` field gives extensions access to the same structured d
|
|
|
564
531
|
|
|
565
532
|
Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` both reflect the chained system prompt as of the current handler. Later `before_agent_start` handlers can still modify it again.
|
|
566
533
|
|
|
567
|
-
#### agent_start / agent_end / agent_settled
|
|
534
|
+
#### agent_start / agent_end / agent_before_settle / agent_settled
|
|
568
535
|
|
|
569
|
-
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Apex Code may still
|
|
536
|
+
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Apex Code may still retry, compact and retry, or continue with queued follow-up messages. `agent_before_settle` is the final actionable boundary. It can append session entries and request one continuation. `agent_settled` is final and notification-only. Use it when a status integration needs to know that Apex Code will not continue running automatically.
|
|
570
537
|
|
|
571
538
|
```typescript
|
|
572
539
|
pi.on("agent_start", async (_event, ctx) => {});
|
|
@@ -575,11 +542,28 @@ pi.on("agent_end", async (event, ctx) => {
|
|
|
575
542
|
// event.messages - messages from this low-level run
|
|
576
543
|
});
|
|
577
544
|
|
|
545
|
+
let addedReviewReminder = false;
|
|
546
|
+
pi.on("agent_before_settle", async (event, ctx) => {
|
|
547
|
+
if (addedReviewReminder) return;
|
|
548
|
+
addedReviewReminder = true;
|
|
549
|
+
return {
|
|
550
|
+
entries: [...event.entries, {
|
|
551
|
+
type: "custom_message",
|
|
552
|
+
customType: "review-reminder",
|
|
553
|
+
content: "Review the final diff before replying.",
|
|
554
|
+
display: false,
|
|
555
|
+
}],
|
|
556
|
+
continue: true,
|
|
557
|
+
};
|
|
558
|
+
});
|
|
559
|
+
|
|
578
560
|
pi.on("agent_settled", async (_event, ctx) => {
|
|
579
|
-
// ctx.isIdle() is true here
|
|
561
|
+
// ctx.isIdle() is true; runs requested here start after all settled handlers finish.
|
|
580
562
|
});
|
|
581
563
|
```
|
|
582
564
|
|
|
565
|
+
If the run is aborted while `agent_before_settle` handlers are running, valid returned entries are still committed, but requested continuation is suppressed. Work requested from `agent_settled` is deferred until every settled handler completes, so notification dispatch is non-reentrant.
|
|
566
|
+
|
|
583
567
|
#### ui_prompt_start / ui_prompt_end
|
|
584
568
|
|
|
585
569
|
Notification-only lifecycle events for blocking user-facing extension UI prompts. They fire around `ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`, `ctx.ui.editor()`, and `ctx.ui.custom()` so host/status integrations can report "waiting for user" instead of just "running".
|
|
@@ -607,11 +591,34 @@ pi.on("turn_start", async (event, ctx) => {
|
|
|
607
591
|
// event.turnIndex, event.timestamp
|
|
608
592
|
});
|
|
609
593
|
|
|
594
|
+
let replacedResponse = false;
|
|
610
595
|
pi.on("turn_end", async (event, ctx) => {
|
|
611
596
|
// event.turnIndex, event.message, event.toolResults
|
|
597
|
+
// event.entries contains the structural entries proposed so far.
|
|
598
|
+
if (replacedResponse || event.outcome !== "completed" || event.toolResults.length > 0) return;
|
|
599
|
+
replacedResponse = true;
|
|
600
|
+
return {
|
|
601
|
+
entries: [
|
|
602
|
+
...event.entries,
|
|
603
|
+
{ type: "context_edit", targetId: event.messageEntryId, replacement: null },
|
|
604
|
+
{
|
|
605
|
+
type: "custom_message",
|
|
606
|
+
customType: "replacement-instruction",
|
|
607
|
+
content: "Answer again using the persisted user request.",
|
|
608
|
+
display: false,
|
|
609
|
+
},
|
|
610
|
+
],
|
|
611
|
+
continue: true,
|
|
612
|
+
};
|
|
612
613
|
});
|
|
613
614
|
```
|
|
614
615
|
|
|
616
|
+
`turn_end` runs after the assistant and tool-result messages have been persisted and before the low-level `turn_end` event. Retry backoff and final-attempt recovery still happen after `agent_end`, preserving their existing lifecycle and queue ordering; `agent_before_settle` sees the repaired projection after that work completes. Boundary handlers run in extension load and registration order. Each handler sees prior proposals in `event.entries` and sees `event.context` rebuilt from them. Returning `entries` or `continue` replaces only that field; omitted fields preserve the current proposal. Allowed draft entry types are `custom`, `custom_message`, `context_edit`, and `compaction`. The complete proposal is validated before it is appended in list order after all handlers finish; a handler error is reported and later handlers still run. Validation prevents partially applied semantic errors, but persistence is not transactional.
|
|
617
|
+
|
|
618
|
+
`continue: true` ensures one next provider request for that boundary invocation. If tool results, steering, or a follow-up already cause that request, they satisfy the decision and no additional request is made; otherwise Pi makes one context-only request. Error and aborted responses remain hard exits. `continue: false` never suppresses natural work. Guard continuation conditions: an unconditional `continue: true` is evaluated again after the next response and can create an endless loop. A `custom_message` draft contributes a user-role model message but is extension-authored: it does not run human input hooks, slash commands, skills, or prompt templates.
|
|
619
|
+
|
|
620
|
+
Host integrations that construct `TurnEndEvent` values must now provide `messageEntryId`, `toolResultEntryIds`, `outcome`, `entries`, `continue`, and `context`. `ExtensionEvent` exhaustive switches must also handle `agent_before_settle`. `ExtensionRunner.emit()` excludes actionable turn boundaries; dispatch `turn_end` and `agent_before_settle` through `emitBoundary(baseEvent, buildContext)` so handlers receive chained previews. Other dedicated runner methods still return results for events such as `session_before_*`.
|
|
621
|
+
|
|
615
622
|
#### message_start / message_update / message_end
|
|
616
623
|
|
|
617
624
|
Fired for message lifecycle updates.
|
|
@@ -678,12 +685,31 @@ Fired before each LLM call. Modify messages non-destructively. See [Session Form
|
|
|
678
685
|
|
|
679
686
|
```typescript
|
|
680
687
|
pi.on("context", async (event, ctx) => {
|
|
681
|
-
// event.messages - deep copy, safe to modify
|
|
688
|
+
// event.messages - deep copy without system messages, safe to modify
|
|
682
689
|
const filtered = event.messages.filter(m => !shouldPrune(m));
|
|
683
690
|
return { messages: filtered };
|
|
684
691
|
});
|
|
685
692
|
```
|
|
686
693
|
|
|
694
|
+
`event.messages` holds the conversation without system messages. The prompt and tool declarations belong to Pi and are not part of this hook: when the handler returns a changed list, Pi replays the current prompt sections and tool declarations into one leading system message ahead of the returned messages. Filtering, windowing, or slicing from a compaction summary therefore cannot drop the prompt or the tools. An unchanged list keeps mid-conversation system messages in place, so models that accept them retain their cached prefix. System messages a handler adds are kept after Pi's head. To change the prompt or the tool set durably, use [`before_agent_start`](#before_agent_start) or `pi.setActiveTools()`; to edit system messages for one request, use [`context_with_system`](#context_with_system).
|
|
695
|
+
|
|
696
|
+
#### context_with_system
|
|
697
|
+
|
|
698
|
+
Fired before each LLM call, after every `context` handler has run and Pi has restored the prompt and tool state. `event.messages` is the full transcript, including the leading system message and any mid-conversation prompt or tool patches (see [Session Format](session-format.md#sessionmessageentry)). The returned messages are sent as they are: this hook owns the prompt and tool declarations for the request.
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
import { getCurrentSystemMessage } from "@earendil-works/pi-ai";
|
|
702
|
+
|
|
703
|
+
pi.on("context_with_system", async (event, ctx) => {
|
|
704
|
+
const cut = findCutIndex(event.messages);
|
|
705
|
+
// Fold the dropped prefix so its prompt and tool state survives as the new head.
|
|
706
|
+
const head = getCurrentSystemMessage(event.messages.slice(0, cut));
|
|
707
|
+
return { messages: head ? [head, ...event.messages.slice(cut)] : event.messages.slice(cut) };
|
|
708
|
+
});
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
Rules: keep a system message at index 0 (providers read the prompt and initial tool declarations there; Pi reports an error if a handler drops it). Removing a system message removes the tool declarations and section patches it carries. Check your output with `getCurrentSystemPrompt()` and `getCurrentTools()` from `@earendil-works/pi-ai`. Handlers run in extension load order; a `systemPrompt` forced from `before_agent_start` is still projected onto the request afterwards.
|
|
712
|
+
|
|
687
713
|
#### before_provider_headers
|
|
688
714
|
|
|
689
715
|
Fired after the outgoing HTTP headers are assembled. Use it to add, override, or remove request headers.
|
|
@@ -735,6 +761,25 @@ pi.on("after_provider_response", (event, ctx) => {
|
|
|
735
761
|
|
|
736
762
|
Header availability depends on provider and transport. Providers that abstract HTTP responses may not expose headers.
|
|
737
763
|
|
|
764
|
+
#### cache_warming_decision
|
|
765
|
+
|
|
766
|
+
Fired before each prompt-cache refresh with pi's decision filled in. The event carries only pi's cost estimates; use `ctx.model`, `ctx.isIdle()`, and `ctx.getContextUsage()` for everything else.
|
|
767
|
+
|
|
768
|
+
```typescript
|
|
769
|
+
pi.on("cache_warming_decision", (event, ctx) => {
|
|
770
|
+
// event.warmCost: price of this refresh
|
|
771
|
+
// event.missCost: extra price of the next request if the entry is lost
|
|
772
|
+
// event.continuationProbability: pi's estimate that a request arrives in time
|
|
773
|
+
// event.action: "warm" | "stop", pi's decision
|
|
774
|
+
|
|
775
|
+
if (ctx.model?.provider === "my-provider") {
|
|
776
|
+
return { action: "stop" };
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
Return `{ action: "warm" }` or `{ action: "stop" }` to override; the last handler that returns an action wins. `"stop"` ends warming until the next real request.
|
|
782
|
+
|
|
738
783
|
### Model Events
|
|
739
784
|
|
|
740
785
|
#### model_select
|
|
@@ -906,6 +951,8 @@ pi.on("user_bash", (event, ctx) => {
|
|
|
906
951
|
});
|
|
907
952
|
```
|
|
908
953
|
|
|
954
|
+
Returning `undefined` continues to the next handler, then local execution if none handles the event. A valid result stops propagation: `operations` executes the command through the supplied backend, while `result` records the completed command without executing it.
|
|
955
|
+
|
|
909
956
|
### Input Events
|
|
910
957
|
|
|
911
958
|
#### input
|
|
@@ -1016,6 +1063,12 @@ Access to models, providers, and resolved authentication. `ctx.modelRegistry.get
|
|
|
1016
1063
|
|
|
1017
1064
|
`ctx.scopedModels` is the read-only list of models scoped to the current session — the same set the `/scoped-models` command shows. It is resolved at session start from the `--models` CLI flag and the `enabledModels` setting (matched against the available catalogue with minimatch on `provider/modelId` or a bare `modelId`). It is empty when no scoping is configured, meaning every available model is usable. Each entry is `{ model, thinkingLevel? }`, where `thinkingLevel` is set only when a pattern pinned it (e.g. `anthropic/*:high`). Use it to populate a model picker that mirrors the built-in one instead of enumerating the whole catalogue via `ctx.modelRegistry.getAvailable()`.
|
|
1018
1065
|
|
|
1066
|
+
#### Streaming model calls
|
|
1067
|
+
|
|
1068
|
+
Use `ctx.modelRegistry.streamSimple(model, context, options)` for provider-neutral options such as `reasoning`, or `stream()` for API-specific options. Both use configured providers and resolve authentication, including for providers registered with `pi.registerProvider()`. Use these instead of `pi-ai/compat` streaming functions, which cannot see extension provider registrations.
|
|
1069
|
+
|
|
1070
|
+
Both return an `AssistantMessageEventStream`. Iterate it for response events and await `.result()` for the final message. Setup failures produce error events and error results.
|
|
1071
|
+
|
|
1019
1072
|
### ctx.signal
|
|
1020
1073
|
|
|
1021
1074
|
The current agent abort signal, or `undefined` when no agent turn is active.
|
|
@@ -1119,7 +1172,7 @@ const options = ctx.getSystemPromptOptions();
|
|
|
1119
1172
|
const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
|
|
1120
1173
|
```
|
|
1121
1174
|
|
|
1122
|
-
This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets,
|
|
1175
|
+
This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom or forced prompt, active tools, tool snippets, per-tool and custom rules, custom sections, appended prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
|
|
1123
1176
|
|
|
1124
1177
|
This reports the current base prompt inputs. It does not include per-turn `before_agent_start` chained system-prompt changes, later `context` event message mutations, or `before_provider_request` payload rewrites.
|
|
1125
1178
|
|
|
@@ -1197,7 +1250,7 @@ Options:
|
|
|
1197
1250
|
|
|
1198
1251
|
### ctx.navigateTree(targetId, options?)
|
|
1199
1252
|
|
|
1200
|
-
Navigate to a different point in the session tree:
|
|
1253
|
+
Navigate to a different point in the session tree. Rejects while an agent response, manual or automatic compaction, or another tree navigation is active, even with `summarize: false`. These conflicts leave the active branch unchanged and reject the promise rather than returning `{ cancelled: true }`. Wait for the active operation to finish (for example, with `await ctx.waitForIdle()` in a command handler) and retry:
|
|
1201
1254
|
|
|
1202
1255
|
```typescript
|
|
1203
1256
|
const result = await ctx.navigateTree("entry-id-456", {
|
|
@@ -1360,7 +1413,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
1360
1413
|
|
|
1361
1414
|
### pi.on(event, handler)
|
|
1362
1415
|
|
|
1363
|
-
Subscribe to events. See [Events](#events) for event types and return values.
|
|
1416
|
+
Subscribe to events. Returns an unsubscribe function that removes only that registration. See [Events](#events) for event types and return values.
|
|
1417
|
+
|
|
1418
|
+
```typescript
|
|
1419
|
+
const unsubscribe = pi.on("agent_end", async (event) => {
|
|
1420
|
+
unsubscribe();
|
|
1421
|
+
await updateIntegration(event.messages);
|
|
1422
|
+
});
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
Handlers run in extension load order, then registration order within each extension. Adding or removing a handler does not affect a dispatch already in progress.
|
|
1364
1426
|
|
|
1365
1427
|
### pi.registerTool(definition)
|
|
1366
1428
|
|
|
@@ -1615,22 +1677,15 @@ pi.registerMarkdownTransformer((markdown, { messageType, isStreaming }) => {
|
|
|
1615
1677
|
|
|
1616
1678
|
If a transformer throws, Apex Code keeps the Markdown produced so far and continues with the next transformer. The hook is display-only: the original message remains unchanged in the session and model context. It runs for new user messages, assistant streaming updates, restored session messages, and terminal width changes, so transformers should remain synchronous and inexpensive.
|
|
1617
1679
|
|
|
1618
|
-
|
|
1680
|
+
<a id="understand-the-lifecycle"></a>
|
|
1619
1681
|
|
|
1620
|
-
|
|
1682
|
+
## Respect the runtime lifecycle
|
|
1621
1683
|
|
|
1622
|
-
|
|
1623
|
-
import { Box, Text } from "@earendil-works/pi-tui";
|
|
1684
|
+
The factory can be synchronous or asynchronous. Pi waits for an asynchronous factory before startup continues, allowing it to fetch configuration or register providers needed during startup.
|
|
1624
1685
|
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
box.addChild(new Text(`${theme.bold(data.title)}: ${data.count}`));
|
|
1629
|
-
if (expanded) {
|
|
1630
|
-
box.addChild(new Text(theme.fg("dim", JSON.stringify(data, null, 2))));
|
|
1631
|
-
}
|
|
1632
|
-
return box;
|
|
1633
|
-
});
|
|
1686
|
+
Do not start processes, sockets, watchers, or timers in the factory because some invocations load extensions without starting a session.
|
|
1687
|
+
Start long-lived resources from `session_start` or from the command or tool that needs them.
|
|
1688
|
+
Close session-scoped resources from an idempotent `session_shutdown` handler.
|
|
1634
1689
|
|
|
1635
1690
|
pi.appendEntry("status-card", { title: "Indexed files", count: 17 });
|
|
1636
1691
|
```
|
|
@@ -1703,7 +1758,7 @@ Typical `sourceInfo.source` values:
|
|
|
1703
1758
|
|
|
1704
1759
|
### pi.setModel(model)
|
|
1705
1760
|
|
|
1706
|
-
Set the current
|
|
1761
|
+
Set the model for the current session. The change is recorded in session history and restored when that session is resumed, but it does not change the configured `defaultProvider` or `defaultModel` used by new sessions. Returns `false` if authentication is not configured for the model's provider. See [models.md](models.md) for configuring custom models.
|
|
1707
1762
|
|
|
1708
1763
|
```typescript
|
|
1709
1764
|
const model = ctx.modelRegistry.find("anthropic", "claude-sonnet-4-5");
|
|
@@ -1717,7 +1772,9 @@ if (model) {
|
|
|
1717
1772
|
|
|
1718
1773
|
### pi.getThinkingLevel() / pi.setThinkingLevel(level)
|
|
1719
1774
|
|
|
1720
|
-
Get
|
|
1775
|
+
Get the current thinking level. Level is clamped to model capabilities (non-reasoning models always use "off"). Changes emit `thinking_level_select`.
|
|
1776
|
+
|
|
1777
|
+
`pi.setThinkingLevel()` changes the thinking level for the current session. The change is recorded in session history and restored when that session is resumed, but it does not change the configured default used by new sessions.
|
|
1721
1778
|
|
|
1722
1779
|
```typescript
|
|
1723
1780
|
const current = pi.getThinkingLevel(); // "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
|
@@ -2184,26 +2241,26 @@ import {
|
|
|
2184
2241
|
DEFAULT_MAX_LINES, // 2000
|
|
2185
2242
|
} from "apex-code";
|
|
2186
2243
|
|
|
2187
|
-
|
|
2188
|
-
const output = await runCommand();
|
|
2244
|
+
<a id="extensionapi-methods"></a>
|
|
2189
2245
|
|
|
2190
|
-
|
|
2191
|
-
const truncation = truncateHead(output, {
|
|
2192
|
-
maxLines: DEFAULT_MAX_LINES,
|
|
2193
|
-
maxBytes: DEFAULT_MAX_BYTES,
|
|
2194
|
-
});
|
|
2246
|
+
## Choose an integration point
|
|
2195
2247
|
|
|
2196
|
-
|
|
2248
|
+
| Capability | Main API |
|
|
2249
|
+
|---|---|
|
|
2250
|
+
| Observe or modify lifecycle behavior | `pi.on()` |
|
|
2251
|
+
| Add a model-callable operation | `pi.registerTool()` |
|
|
2252
|
+
| Add a `/` command | `pi.registerCommand()` |
|
|
2253
|
+
| Add a shortcut or CLI flag | `pi.registerShortcut()` or `pi.registerFlag()` |
|
|
2254
|
+
| Send user or custom messages | `pi.sendUserMessage()` or `pi.sendMessage()` |
|
|
2255
|
+
| Persist non-context session data | `pi.appendEntry()` |
|
|
2256
|
+
| Change active tools, model, or thinking level | Session control methods on `pi` |
|
|
2257
|
+
| Add a model provider | `pi.registerProvider()` |
|
|
2258
|
+
| Add terminal rendering | Renderer registration and `ctx.ui` |
|
|
2259
|
+
| Communicate with another extension | `pi.events` |
|
|
2197
2260
|
|
|
2198
|
-
|
|
2199
|
-
// Write full output to temp file
|
|
2200
|
-
const tempFile = writeTempFile(output);
|
|
2261
|
+
Use the exported declarations in [`extensions/types.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/extensions/types.ts) for exact event, context, tool, and result types.
|
|
2201
2262
|
|
|
2202
|
-
|
|
2203
|
-
result += `\n\n[Output truncated: ${truncation.outputLines} of ${truncation.totalLines} lines`;
|
|
2204
|
-
result += ` (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}).`;
|
|
2205
|
-
result += ` Full output saved to: ${tempFile}]`;
|
|
2206
|
-
}
|
|
2263
|
+
## Follow the extension contracts
|
|
2207
2264
|
|
|
2208
2265
|
return { content: [{ type: "text", text: result }] };
|
|
2209
2266
|
}
|
|
@@ -2362,9 +2419,7 @@ If a slot renderer is not defined or throws:
|
|
|
2362
2419
|
|
|
2363
2420
|
### Dynamic Tool Loading
|
|
2364
2421
|
|
|
2365
|
-
Extensions can register many tools while keeping only a small initial set active. A tool can then
|
|
2366
|
-
|
|
2367
|
-
This works with every model. Models with native deferred-loading support preserve the stable prompt prefix and load the new definitions at the tool-result position. Other models use the fallback described below.
|
|
2422
|
+
Extensions can register many tools while keeping only a small initial set active. A tool can then change the active set with `pi.setActiveTools()` during execution. Pi stores the initial prompt and tool loadout in the transcript's first system message, then appends tool and prompt deltas before the next model request. Providers that cannot represent a transition receive a complete transcript checkpoint, which may invalidate the cached prefix.
|
|
2368
2423
|
|
|
2369
2424
|
The lifecycle is:
|
|
2370
2425
|
|
|
@@ -2495,7 +2550,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2495
2550
|
}
|
|
2496
2551
|
```
|
|
2497
2552
|
|
|
2498
|
-
When `search_tools` adds a match, the model receives
|
|
2553
|
+
When `search_tools` adds a match, the model receives the complete updated tool list on the immediately following request.
|
|
2499
2554
|
|
|
2500
2555
|
## Custom UI
|
|
2501
2556
|
|
|
@@ -2517,14 +2572,13 @@ Extensions can interact with users via `ctx.ui` methods and customize how messag
|
|
|
2517
2572
|
// Select from options
|
|
2518
2573
|
const choice = await ctx.ui.select("Pick one:", ["A", "B", "C"]);
|
|
2519
2574
|
|
|
2520
|
-
|
|
2521
|
-
const ok = await ctx.ui.confirm("Delete?", "This cannot be undone");
|
|
2575
|
+
### Events and concurrency
|
|
2522
2576
|
|
|
2523
|
-
|
|
2524
|
-
|
|
2577
|
+
Handlers run in extension load and registration order. `pi.on()` returns a function that unsubscribes that registration; changes do not affect a dispatch already in progress.
|
|
2578
|
+
Some events notify; others transform data, replace results, or cancel an operation.
|
|
2579
|
+
Use each event’s declared result type rather than assuming every return value has an effect.
|
|
2525
2580
|
|
|
2526
|
-
|
|
2527
|
-
const text = await ctx.ui.editor("Edit:", "prefilled text");
|
|
2581
|
+
Events cover resource discovery, sessions, agent and message lifecycle, providers, tools, and raw input.
|
|
2528
2582
|
|
|
2529
2583
|
// Notification (non-blocking)
|
|
2530
2584
|
ctx.ui.notify("Done!", "info"); // "info" | "warning" | "error"
|
|
@@ -2683,93 +2737,23 @@ Custom working-indicator frames are rendered verbatim. If you want colors, add t
|
|
|
2683
2737
|
|
|
2684
2738
|
### Autocomplete Providers
|
|
2685
2739
|
|
|
2686
|
-
|
|
2740
|
+
`message_end` can replace a finalized message while preserving its role. `tool_call` can mutate input or block execution. `tool_result` handlers compose, with each handler seeing prior changes.
|
|
2687
2741
|
|
|
2688
|
-
|
|
2742
|
+
<a id="context_with_system"></a>
|
|
2689
2743
|
|
|
2690
|
-
-
|
|
2691
|
-
- return your own suggestions when your extension-specific syntax matches
|
|
2692
|
-
- otherwise delegate to `current.getSuggestions(...)`
|
|
2693
|
-
- delegate `applyCompletion(...)` unless you need custom insertion behavior
|
|
2744
|
+
`context` transforms conversation messages without prompt and tool system messages; Pi restores that state afterward. Use `context_with_system` only when a request-local transformation must own the complete transcript, and keep a system message at index zero.
|
|
2694
2745
|
|
|
2695
|
-
|
|
2696
|
-
pi.on("session_start", (_event, ctx) => {
|
|
2697
|
-
ctx.ui.addAutocompleteProvider((current) => ({
|
|
2698
|
-
triggerCharacters: ["#"],
|
|
2699
|
-
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
2700
|
-
const line = lines[cursorLine] ?? "";
|
|
2701
|
-
const beforeCursor = line.slice(0, cursorCol);
|
|
2702
|
-
const match = beforeCursor.match(/(?:^|[ \t])#([^\s#]*)$/);
|
|
2703
|
-
if (!match) {
|
|
2704
|
-
return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
2705
|
-
}
|
|
2746
|
+
`turn_end` and `agent_before_settle` are actionable boundaries. Their handlers can chain proposed `custom`, `custom_message`, `context_edit`, or `compaction` entries and return `continue: true` for one next model request. Guard continuation conditions because an unconditional continuation can loop. Use the exported event declarations for the complete validation and ordering contract.
|
|
2706
2747
|
|
|
2707
|
-
|
|
2708
|
-
prefix: `#${match[1] ?? ""}`,
|
|
2709
|
-
items: [
|
|
2710
|
-
{ value: "#2983", label: "#2983", description: "Extension API for registering custom @ autocomplete providers" },
|
|
2711
|
-
{ value: "#2753", label: "#2753", description: "Reload stale resource settings" },
|
|
2712
|
-
],
|
|
2713
|
-
};
|
|
2714
|
-
},
|
|
2715
|
-
|
|
2716
|
-
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
2717
|
-
return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
2718
|
-
},
|
|
2719
|
-
|
|
2720
|
-
shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
|
|
2721
|
-
return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;
|
|
2722
|
-
},
|
|
2723
|
-
}));
|
|
2724
|
-
});
|
|
2725
|
-
```
|
|
2748
|
+
<a id="cache_warming_decision"></a>
|
|
2726
2749
|
|
|
2727
|
-
|
|
2750
|
+
`cache_warming_decision` can override an idle prompt-cache refresh with `{ action: "warm" }` or `{ action: "stop" }`. The last handler that returns an action wins.
|
|
2728
2751
|
|
|
2729
|
-
|
|
2752
|
+
Tool calls from one assistant message can run in parallel.
|
|
2753
|
+
Do not assume a sibling call or result exists when another tool event runs.
|
|
2754
|
+
Use `ctx.signal` for nested work owned by an active turn; commands and idle session events often have no operation signal.
|
|
2730
2755
|
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
```typescript
|
|
2734
|
-
import { Text, Component } from "@earendil-works/pi-tui";
|
|
2735
|
-
|
|
2736
|
-
const result = await ctx.ui.custom<boolean>((tui, theme, keybindings, done) => {
|
|
2737
|
-
const text = new Text("Press Enter to confirm, Escape to cancel", 1, 1);
|
|
2738
|
-
|
|
2739
|
-
text.onKey = (key) => {
|
|
2740
|
-
if (key === "return") done(true);
|
|
2741
|
-
if (key === "escape") done(false);
|
|
2742
|
-
return true;
|
|
2743
|
-
};
|
|
2744
|
-
|
|
2745
|
-
return text;
|
|
2746
|
-
});
|
|
2747
|
-
|
|
2748
|
-
if (result) {
|
|
2749
|
-
// User pressed Enter
|
|
2750
|
-
}
|
|
2751
|
-
```
|
|
2752
|
-
|
|
2753
|
-
The callback receives:
|
|
2754
|
-
- `tui` - TUI instance (for screen dimensions, focus management)
|
|
2755
|
-
- `theme` - Current theme for styling
|
|
2756
|
-
- `keybindings` - App keybinding manager (for checking shortcuts)
|
|
2757
|
-
- `done(value)` - Call to close component and return value
|
|
2758
|
-
|
|
2759
|
-
See [tui.md](tui.md) for the full component API.
|
|
2760
|
-
|
|
2761
|
-
#### Overlay Mode (Experimental)
|
|
2762
|
-
|
|
2763
|
-
Pass `{ overlay: true }` to render the component as a floating modal on top of existing content, without clearing the screen:
|
|
2764
|
-
|
|
2765
|
-
```typescript
|
|
2766
|
-
const result = await ctx.ui.custom<string | null>(
|
|
2767
|
-
(tui, theme, keybindings, done) => new MyOverlayComponent({ onClose: done }),
|
|
2768
|
-
{ overlay: true }
|
|
2769
|
-
);
|
|
2770
|
-
```
|
|
2771
|
-
|
|
2772
|
-
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control focus or visibility programmatically:
|
|
2756
|
+
A `user_bash` handler that returns `undefined` passes the command to the next handler and then to local execution if no handler handles it. Returning `operations` or `result` stops propagation. A handler failure blocks the command rather than falling through to local execution.
|
|
2773
2757
|
|
|
2774
2758
|
```typescript
|
|
2775
2759
|
const result = await ctx.ui.custom<string | null>(
|
|
@@ -2815,206 +2799,94 @@ class VimEditor extends CustomEditor {
|
|
|
2815
2799
|
}
|
|
2816
2800
|
}
|
|
2817
2801
|
|
|
2818
|
-
|
|
2819
|
-
pi.on("session_start", (_event, ctx) => {
|
|
2820
|
-
ctx.ui.setEditorComponent((tui, theme, keybindings) =>
|
|
2821
|
-
new VimEditor(tui, theme, keybindings)
|
|
2822
|
-
);
|
|
2823
|
-
});
|
|
2824
|
-
}
|
|
2825
|
-
```
|
|
2826
|
-
|
|
2827
|
-
**Key points:**
|
|
2828
|
-
- Extend `CustomEditor` (not base `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching)
|
|
2829
|
-
- Call `super.handleInput(data)` for keys you don't handle
|
|
2830
|
-
- Factory receives `tui`, `theme`, and `keybindings` from the app
|
|
2831
|
-
- Use `ctx.ui.getEditorComponent()` before `setEditorComponent()` to wrap the previously configured custom editor
|
|
2832
|
-
- Pass `undefined` to restore default: `ctx.ui.setEditorComponent(undefined)`
|
|
2802
|
+
### Tools
|
|
2833
2803
|
|
|
2834
|
-
|
|
2804
|
+
A custom tool defines a name, model-facing description, TypeBox parameter schema, and `execute()` function.
|
|
2805
|
+
Its result requires model-facing `content` and a `details` field for rendering or state reconstruction.
|
|
2806
|
+
Use `details: undefined` when there are no structured details. If the tool makes nested model calls, include their `usage` in the result so session totals remain accurate.
|
|
2835
2807
|
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
new MyEditor(tui, theme, keybindings, { base: previous?.(tui, theme, keybindings) })
|
|
2840
|
-
);
|
|
2841
|
-
```
|
|
2808
|
+
Throw from `execute()` to produce a failed tool result.
|
|
2809
|
+
Returning an object does not mark it as an error.
|
|
2810
|
+
Return `terminate: true` only when the agent should skip its automatic follow-up after every completed tool in that batch agrees to terminate.
|
|
2842
2811
|
|
|
2843
|
-
|
|
2812
|
+
Use sequential execution when tools share mutable in-memory state.
|
|
2813
|
+
File-mutating tools should wrap the complete read-modify-write operation with `withFileMutationQueue()`.
|
|
2814
|
+
Truncate large model-facing results and tell the model where to read the complete output.
|
|
2844
2815
|
|
|
2845
|
-
|
|
2816
|
+
See [`hello.ts`](../examples/extensions/hello.ts), [`todo.ts`](../examples/extensions/todo.ts), [`dynamic-tools.ts`](../examples/extensions/dynamic-tools.ts), and [`truncated-tool.ts`](../examples/extensions/truncated-tool.ts).
|
|
2846
2817
|
|
|
2847
|
-
|
|
2818
|
+
### Activate tools dynamically
|
|
2848
2819
|
|
|
2849
|
-
|
|
2850
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
2820
|
+
Register every tool first, keep optional tools inactive, and use `pi.setActiveTools()` from a loader tool to select the desired active tools. Names must already be registered; unknown names are ignored.
|
|
2851
2821
|
|
|
2852
|
-
|
|
2853
|
-
const { expanded, outputPad } = options;
|
|
2854
|
-
let text = theme.fg("accent", `[${message.customType}] `);
|
|
2855
|
-
text += message.content;
|
|
2822
|
+
Pi records the initial prompt and tool set in the transcript's first system message, then appends tool and prompt changes before the next model request. Providers that cannot represent the transition receive a complete transcript checkpoint, which can invalidate the cached prefix.
|
|
2856
2823
|
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2824
|
+
<a id="extensioncontext"></a>
|
|
2825
|
+
<a id="extensioncommandcontext"></a>
|
|
2826
|
+
<a id="use-extension-context"></a>
|
|
2860
2827
|
|
|
2861
|
-
|
|
2862
|
-
});
|
|
2863
|
-
```
|
|
2828
|
+
### Context and session changes
|
|
2864
2829
|
|
|
2865
|
-
|
|
2830
|
+
`ExtensionContext` provides the working directory, mode, UI, session manager, model runtime, abort signal, context usage, and controls for compaction and shutdown.
|
|
2831
|
+
Use `ctx.modelRegistry.streamSimple()` for provider-neutral nested model calls.
|
|
2866
2832
|
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
customType: "my-extension", // Matches registerMessageRenderer
|
|
2870
|
-
content: "Status update",
|
|
2871
|
-
display: true, // Show in TUI
|
|
2872
|
-
details: { ... }, // Available in renderer
|
|
2873
|
-
});
|
|
2874
|
-
```
|
|
2833
|
+
Command handlers receive `ExtensionCommandContext`, which adds operations for waiting until idle, reloading, tree navigation, and session replacement.
|
|
2834
|
+
These operations are command-only because calling them from lifecycle handlers can deadlock the runtime.
|
|
2875
2835
|
|
|
2876
|
-
|
|
2836
|
+
Session replacement invalidates the old context. Capture only plain data before switching, then use the fresh context supplied to `withSession` for session-bound work.
|
|
2877
2837
|
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
return new Text(theme.fg("accent", JSON.stringify(entry.data)));
|
|
2881
|
-
});
|
|
2838
|
+
<a id="state-management"></a>
|
|
2839
|
+
<a id="persist-state"></a>
|
|
2882
2840
|
|
|
2883
|
-
|
|
2884
|
-
```
|
|
2841
|
+
### State
|
|
2885
2842
|
|
|
2886
|
-
|
|
2843
|
+
Choose storage based on how state participates in the conversation:
|
|
2887
2844
|
|
|
2888
|
-
|
|
2845
|
+
| State | Storage |
|
|
2846
|
+
|---|---|
|
|
2847
|
+
| Tool state that follows the active branch | Tool-result `details` |
|
|
2848
|
+
| Durable data excluded from model context | `pi.appendEntry()` |
|
|
2849
|
+
| Custom content stored and sent to the model | `pi.sendMessage()` |
|
|
2850
|
+
| Data outside one session | External storage |
|
|
2889
2851
|
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
theme.fg("accent", text) // Highlights
|
|
2894
|
-
theme.fg("success", text) // Success (green)
|
|
2895
|
-
theme.fg("error", text) // Errors (red)
|
|
2896
|
-
theme.fg("warning", text) // Warnings (yellow)
|
|
2897
|
-
theme.fg("muted", text) // Secondary text
|
|
2898
|
-
theme.fg("dim", text) // Tertiary text
|
|
2852
|
+
Reconstruct branch-sensitive state from `ctx.sessionManager.getBranch()` during `session_start`.
|
|
2853
|
+
Do not rebuild it from every file entry because abandoned branches represent alternative histories.
|
|
2854
|
+
Register an entry or message renderer when custom stored content should appear in the transcript.
|
|
2899
2855
|
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
```
|
|
2856
|
+
<a id="custom-ui"></a>
|
|
2857
|
+
<a id="mode-behavior"></a>
|
|
2858
|
+
<a id="interact-with-the-user"></a>
|
|
2859
|
+
<a id="account-for-each-mode"></a>
|
|
2905
2860
|
|
|
2906
|
-
|
|
2861
|
+
### UI and modes
|
|
2907
2862
|
|
|
2908
2863
|
```typescript
|
|
2909
2864
|
import { highlightCode, getLanguageFromPath } from "apex-code";
|
|
2910
2865
|
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
All examples in [examples/extensions/](../examples/extensions/).
|
|
2939
|
-
|
|
2940
|
-
| Example | Description | Key APIs |
|
|
2941
|
-
|---------|-------------|----------|
|
|
2942
|
-
| **Tools** |||
|
|
2943
|
-
| `hello.ts` | Minimal tool registration | `registerTool` |
|
|
2944
|
-
| `question.ts` | Tool with user interaction | `registerTool`, `ui.select` |
|
|
2945
|
-
| `questionnaire.ts` | Multi-step wizard tool | `registerTool`, `ui.custom` |
|
|
2946
|
-
| `todo.ts` | Stateful tool with persistence | `registerTool`, `appendEntry`, `renderResult`, session events |
|
|
2947
|
-
| `dynamic-tools.ts` | Register tools after startup and during commands | `registerTool`, `session_start`, `registerCommand` |
|
|
2948
|
-
| `structured-output.ts` | Final structured-output tool with `terminate: true` | `registerTool`, terminating tool results |
|
|
2949
|
-
| `truncated-tool.ts` | Output truncation example | `registerTool`, `truncateHead` |
|
|
2950
|
-
| `tool-override.ts` | Override built-in read tool | `registerTool` (same name as built-in) |
|
|
2951
|
-
| **Commands** |||
|
|
2952
|
-
| `pirate.ts` | Modify system prompt per-turn | `registerCommand`, `before_agent_start` |
|
|
2953
|
-
| `summarize.ts` | Conversation summary command | `registerCommand`, `ui.custom` |
|
|
2954
|
-
| `handoff.ts` | Cross-provider model handoff | `registerCommand`, `ui.editor`, `ui.custom` |
|
|
2955
|
-
| `qna.ts` | Q&A with custom UI | `registerCommand`, `ui.custom`, `setEditorText` |
|
|
2956
|
-
| `send-user-message.ts` | Inject user messages | `registerCommand`, `sendUserMessage` |
|
|
2957
|
-
| `reload-runtime.ts` | Reload command and LLM tool handoff | `registerCommand`, `ctx.reload()`, `sendUserMessage` |
|
|
2958
|
-
| `shutdown-command.ts` | Graceful shutdown command | `registerCommand`, `shutdown()` |
|
|
2959
|
-
| **Events & Gates** |||
|
|
2960
|
-
| `permission-gate.ts` | Block dangerous commands | `on("tool_call")`, `ui.confirm` |
|
|
2961
|
-
| `project-trust.ts` | Decide or defer project trust from a user/global or CLI extension | `on("project_trust")`, trust UI, required trust result |
|
|
2962
|
-
| `protected-paths.ts` | Block writes to specific paths | `on("tool_call")` |
|
|
2963
|
-
| `confirm-destructive.ts` | Confirm session changes | `on("session_before_switch")`, `on("session_before_fork")` |
|
|
2964
|
-
| `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
|
|
2965
|
-
| `input-transform.ts` | Transform user input | `on("input")` |
|
|
2966
|
-
| `input-transform-streaming.ts` | Streaming-aware input transform | `on("input")`, `streamingBehavior` |
|
|
2967
|
-
| `model-status.ts` | React to model changes | `on("model_select")`, `setStatus` |
|
|
2968
|
-
| `provider-payload.ts` | Inspect payloads and provider response headers | `on("before_provider_request")`, `on("after_provider_response")` |
|
|
2969
|
-
| `system-prompt-header.ts` | Display system prompt info | `on("agent_start")`, `getSystemPrompt` |
|
|
2970
|
-
| `claude-rules.ts` | Load rules from files | `on("session_start")`, `on("before_agent_start")` |
|
|
2971
|
-
| `prompt-customizer.ts` | Add context-aware tool guidance using `systemPromptOptions` | `on("before_agent_start")`, `BuildSystemPromptOptions` |
|
|
2972
|
-
| `file-trigger.ts` | File watcher triggers messages | `sendMessage` |
|
|
2973
|
-
| **Compaction & Sessions** |||
|
|
2974
|
-
| `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
|
|
2975
|
-
| `trigger-compact.ts` | Trigger compaction manually | `compact()` |
|
|
2976
|
-
| `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
|
|
2977
|
-
| `git-merge-and-resolve.ts` | Fetch, merge, and resolve conflicts | `on("agent_end")`, `exec`, `sendUserMessage` |
|
|
2978
|
-
| `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
|
|
2979
|
-
| **UI Components** |||
|
|
2980
|
-
| `status-line.ts` | Footer status indicator | `setStatus`, session events |
|
|
2981
|
-
| `working-indicator.ts` | Customize the streaming working indicator | `setWorkingIndicator`, `registerCommand` |
|
|
2982
|
-
| `github-issue-autocomplete.ts` | Add `#1234` issue completions on top of built-in autocomplete by preloading recent open issues from `gh issue list` | `addAutocompleteProvider`, `on("session_start")`, `exec` |
|
|
2983
|
-
| `custom-footer.ts` | Replace footer entirely | `registerCommand`, `setFooter` |
|
|
2984
|
-
| `custom-header.ts` | Replace startup header | `on("session_start")`, `setHeader` |
|
|
2985
|
-
| `modal-editor.ts` | Vim-style modal editor | `setEditorComponent`, `CustomEditor` |
|
|
2986
|
-
| `rainbow-editor.ts` | Custom editor styling | `setEditorComponent` |
|
|
2987
|
-
| `widget-placement.ts` | Widget above/below editor | `setWidget` |
|
|
2988
|
-
| `overlay-test.ts` | Overlay components | `ui.custom` with overlay options |
|
|
2989
|
-
| `overlay-qa-tests.ts` | Comprehensive overlay tests | `ui.custom`, all overlay options |
|
|
2990
|
-
| `notify.ts` | Simple notifications | `ui.notify` |
|
|
2991
|
-
| `timed-confirm.ts` | Dialogs with timeout | `ui.confirm` with timeout/signal |
|
|
2992
|
-
| `mac-system-theme.ts` | Auto-switch theme | `setTheme`, `exec` |
|
|
2993
|
-
| **Complex Extensions** |||
|
|
2994
|
-
| `plan-mode/` | Full plan mode implementation | All event types, `registerCommand`, `registerShortcut`, `registerFlag`, `setStatus`, `setWidget`, `sendMessage`, `setActiveTools` |
|
|
2995
|
-
| `preset.ts` | Saveable presets (model, tools, thinking) | `registerCommand`, `registerShortcut`, `registerFlag`, `setModel`, `setActiveTools`, `setThinkingLevel`, `appendEntry` |
|
|
2996
|
-
| `tools.ts` | Toggle tools on/off UI | `registerCommand`, `setActiveTools`, `SettingsList`, session events |
|
|
2997
|
-
| **Remote & Sandbox** |||
|
|
2998
|
-
| `ssh.ts` | SSH remote execution | `registerFlag`, `on("user_bash")`, `on("before_agent_start")`, tool operations |
|
|
2999
|
-
| `interactive-shell.ts` | Persistent shell session | `on("user_bash")` |
|
|
3000
|
-
| `sandbox/` | Sandboxed tool execution | Tool operations |
|
|
3001
|
-
| `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM | Tool operations, built-in tool overrides, `on("user_bash")` |
|
|
3002
|
-
| `subagent/` | Spawn sub-agents | `registerTool`, `exec` |
|
|
3003
|
-
| **Games** |||
|
|
3004
|
-
| `snake.ts` | Snake game | `registerCommand`, `ui.custom`, keyboard handling |
|
|
3005
|
-
| `space-invaders.ts` | Space Invaders game | `registerCommand`, `ui.custom` |
|
|
3006
|
-
| `doom-overlay/` | Doom in overlay | `ui.custom` with overlay |
|
|
3007
|
-
| **Providers** |||
|
|
3008
|
-
| `custom-provider-anthropic/` | Custom Anthropic proxy | `registerProvider` |
|
|
3009
|
-
| `custom-provider-gitlab-duo/` | GitLab Duo integration | `registerProvider` with OAuth |
|
|
3010
|
-
| **Messages & Communication** |||
|
|
3011
|
-
| `message-renderer.ts` | Custom message rendering | `registerMessageRenderer`, `sendMessage` |
|
|
3012
|
-
| `entry-renderer.ts` | TUI-only custom entry rendering | `registerEntryRenderer`, `appendEntry` |
|
|
3013
|
-
| `event-bus.ts` | Inter-extension events | `pi.events` |
|
|
3014
|
-
| **Session Metadata** |||
|
|
3015
|
-
| `session-name.ts` | Name sessions for selector | `setSessionName`, `getSessionName` |
|
|
3016
|
-
| `bookmark.ts` | Bookmark entries for /tree | `setLabel` |
|
|
3017
|
-
| **Misc** |||
|
|
3018
|
-
| `inline-bash.ts` | Inline bash in tool calls | `on("tool_call")` |
|
|
3019
|
-
| `bash-spawn-hook.ts` | Adjust bash command, cwd, and env before execution | `createBashTool`, `spawnHook` |
|
|
3020
|
-
| `with-deps/` | Extension with npm dependencies | Package structure with `package.json` |
|
|
2866
|
+
Extensions load in interactive, RPC, JSON, and print modes.
|
|
2867
|
+
Interactive mode provides the complete terminal UI.
|
|
2868
|
+
RPC can forward supported dialogs and notifications through the [RPC Extension UI protocol](rpc-extension-ui.md), but not custom terminal components; JSON and print modes have no UI.
|
|
2869
|
+
Guard terminal-only behavior with `ctx.mode === "tui"` and use `ctx.hasUI` for interactions supported by interactive and RPC clients.
|
|
2870
|
+
|
|
2871
|
+
Keep tool and event behavior independent from rendering so non-interactive modes remain functional.
|
|
2872
|
+
|
|
2873
|
+
<a id="error-handling"></a>
|
|
2874
|
+
<a id="handle-errors-and-shutdown"></a>
|
|
2875
|
+
|
|
2876
|
+
### Errors and cleanup
|
|
2877
|
+
|
|
2878
|
+
Pi reports handler errors and continues where possible. A `tool_call` handler failure blocks the tool as a fail-safe; a tool execution failure becomes an error result for the model.
|
|
2879
|
+
|
|
2880
|
+
Release resources in `session_shutdown` even when normal operation attempted cleanup.
|
|
2881
|
+
Keep cleanup idempotent because cancellation, reload, session replacement, and process exit can converge on the same path.
|
|
2882
|
+
Use `ctx.shutdown()` to request an orderly process shutdown.
|
|
2883
|
+
|
|
2884
|
+
<a id="examples-reference"></a>
|
|
2885
|
+
<a id="use-examples-as-the-implementation-reference"></a>
|
|
2886
|
+
|
|
2887
|
+
## Examples and reference
|
|
2888
|
+
|
|
2889
|
+
The checked [extension examples](../examples/extensions/) cover tools, lifecycle events, commands, flags, shortcuts, state, rendering, providers, OAuth, remote execution, and terminal components.
|
|
2890
|
+
Start with the smallest example matching your integration point.
|
|
2891
|
+
|
|
2892
|
+
Use [Custom Providers](custom-provider.md) for model-service integrations, [Terminal UI](tui.md) for custom components, and [Pi Packages](packages.md) to install or distribute extensions with other resources.
|