@code-yeongyu/senpi 2026.5.29 → 2026.6.3
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 +131 -1
- package/README.md +12 -2
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +28 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +9 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +36 -13
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +3 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +9 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -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/runner.d.ts +5 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +21 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +14 -6
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +2 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +29 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +82 -21
- 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 +2 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +73 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +9 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +134 -11
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +18 -40
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -7
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +167 -96
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +15 -11
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/thinking-levels.d.ts.map +1 -1
- package/dist/core/thinking-levels.js +6 -2
- package/dist/core/thinking-levels.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +7 -10
- 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.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- 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 +5 -7
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +6 -7
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +5 -2
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +17 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +5 -6
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +76 -16
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +118 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +1 -3
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +2 -4
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +25 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +64 -6
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- 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 +1 -0
- 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 +4 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/docs/custom-provider.md +13 -10
- package/docs/extensions.md +47 -17
- package/docs/models.md +25 -12
- package/docs/providers.md +15 -5
- package/docs/quickstart.md +1 -0
- package/docs/rpc.md +3 -2
- package/docs/sdk.md +6 -0
- package/docs/session-format.md +1 -1
- package/docs/sessions.md +8 -0
- package/docs/settings.md +4 -2
- package/docs/terminal-setup.md +2 -0
- package/docs/tui.md +12 -3
- package/docs/usage.md +10 -1
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/custom-header.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
- 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 +54 -3
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/index.ts +1 -1
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/handoff.ts +1 -1
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/interactive-shell.ts +1 -1
- package/examples/extensions/overlay-qa-tests.ts +152 -81
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/summarize.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tools.ts +5 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +15 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/cli.js +0 -0
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +1294 -412
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +1278 -652
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +9 -4
- package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +89 -21
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +27 -14
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +118 -52
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +27 -17
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +5 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.d.ts +7 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.js +8 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +18 -4
- package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +21 -5
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-tui/README.md +15 -3
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +9 -53
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +6 -54
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +173 -39
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +18 -3
- package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +166 -22
- package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +11 -3
- package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/npm-shrinkwrap.json +56 -56
- package/package.json +5 -5
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */
|
|
2
|
+
export function stripJsonComments(input) {
|
|
3
|
+
return input
|
|
4
|
+
.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (m) => (m[0] === '"' ? m : ""))
|
|
5
|
+
.replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (m, tail) => tail ?? (m[0] === '"' ? m : ""));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/utils/json.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAU;IACxD,OAAO,KAAK;SACV,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACxE,OAAO,CAAC,gCAAgC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAAA,CAC1F","sourcesContent":["/** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */\nexport function stripJsonComments(input: string): string {\n\treturn input\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\])*\"|\\/\\/[^\\n]*/g, (m) => (m[0] === '\"' ? m : \"\"))\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\])*\"|,(\\s*[}\\]])/g, (m, tail) => tail ?? (m[0] === '\"' ? m : \"\"));\n}\n"]}
|
package/docs/custom-provider.md
CHANGED
|
@@ -43,7 +43,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
43
43
|
pi.registerProvider("my-provider", {
|
|
44
44
|
name: "My Provider",
|
|
45
45
|
baseUrl: "https://api.example.com",
|
|
46
|
-
apiKey: "MY_API_KEY",
|
|
46
|
+
apiKey: "$MY_API_KEY",
|
|
47
47
|
api: "openai-completions",
|
|
48
48
|
models: [
|
|
49
49
|
{
|
|
@@ -83,7 +83,7 @@ pi.registerProvider("openai", {
|
|
|
83
83
|
pi.registerProvider("google", {
|
|
84
84
|
baseUrl: "https://ai-gateway.corp.com/google",
|
|
85
85
|
headers: {
|
|
86
|
-
"X-Corp-Auth": "CORP_AUTH_TOKEN" // env var or literal
|
|
86
|
+
"X-Corp-Auth": "$CORP_AUTH_TOKEN" // env var or literal
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
89
|
```
|
|
@@ -112,7 +112,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
112
112
|
|
|
113
113
|
pi.registerProvider("local-openai", {
|
|
114
114
|
baseUrl: "http://localhost:1234/v1",
|
|
115
|
-
apiKey: "LOCAL_OPENAI_API_KEY",
|
|
115
|
+
apiKey: "$LOCAL_OPENAI_API_KEY",
|
|
116
116
|
api: "openai-completions",
|
|
117
117
|
models: payload.data.map((model) => ({
|
|
118
118
|
id: model.id,
|
|
@@ -132,7 +132,7 @@ This registers the fetched models before startup finishes.
|
|
|
132
132
|
```typescript
|
|
133
133
|
pi.registerProvider("my-llm", {
|
|
134
134
|
baseUrl: "https://api.my-llm.com/v1",
|
|
135
|
-
apiKey: "MY_LLM_API_KEY", // env var
|
|
135
|
+
apiKey: "$MY_LLM_API_KEY", // env var reference
|
|
136
136
|
api: "openai-completions", // which streaming API to use
|
|
137
137
|
models: [
|
|
138
138
|
{
|
|
@@ -155,6 +155,8 @@ pi.registerProvider("my-llm", {
|
|
|
155
155
|
|
|
156
156
|
When `models` is provided, it **replaces** all existing models for that provider.
|
|
157
157
|
|
|
158
|
+
`apiKey` and custom header values use the same config value syntax as `models.json`: `!command` at the start executes a command for the whole value, `$ENV_VAR` and `${ENV_VAR}` interpolate environment variables, `$$` emits a literal `$`, and `$!` emits a literal `!`.
|
|
159
|
+
|
|
158
160
|
## Unregister Provider
|
|
159
161
|
|
|
160
162
|
Use `pi.unregisterProvider(name)` to remove a provider that was previously registered via `pi.registerProvider(name, ...)`:
|
|
@@ -163,7 +165,7 @@ Use `pi.unregisterProvider(name)` to remove a provider that was previously regis
|
|
|
163
165
|
// Register
|
|
164
166
|
pi.registerProvider("my-llm", {
|
|
165
167
|
baseUrl: "https://api.my-llm.com/v1",
|
|
166
|
-
apiKey: "MY_LLM_API_KEY",
|
|
168
|
+
apiKey: "$MY_LLM_API_KEY",
|
|
167
169
|
api: "openai-completions",
|
|
168
170
|
models: [
|
|
169
171
|
{
|
|
@@ -230,7 +232,7 @@ models: [{
|
|
|
230
232
|
Use `openrouter` for OpenRouter-style `reasoning: { effort }` controls. Use `together` for Together-style `reasoning: { enabled }` controls; with `supportsReasoningEffort`, it also sends `reasoning_effort`. Use `qwen-chat-template` instead for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking`.
|
|
231
233
|
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user/assistant text content.
|
|
232
234
|
|
|
233
|
-
For Anthropic-compatible providers using `api: "anthropic-messages"`, set `compat.forceAdaptiveThinking: true` on models or providers whose upstream model requires adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`). Built-in adaptive Claude models set this automatically.
|
|
235
|
+
For Anthropic-compatible providers using `api: "anthropic-messages"`, set `compat.forceAdaptiveThinking: true` on models or providers whose upstream model requires adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`). Built-in adaptive Claude models set this automatically. Set `compat.allowEmptySignature: true` only for providers that emit empty thinking signatures and expect `signature: ""` on replay.
|
|
234
236
|
|
|
235
237
|
> Migration note: Mistral moved from `openai-completions` to `mistral-conversations`.
|
|
236
238
|
> Use `mistral-conversations` for native Mistral models.
|
|
@@ -243,7 +245,7 @@ If your provider expects `Authorization: Bearer <key>` but doesn't use a standar
|
|
|
243
245
|
```typescript
|
|
244
246
|
pi.registerProvider("custom-api", {
|
|
245
247
|
baseUrl: "https://api.example.com",
|
|
246
|
-
apiKey: "MY_API_KEY",
|
|
248
|
+
apiKey: "$MY_API_KEY",
|
|
247
249
|
authHeader: true, // adds Authorization: Bearer header
|
|
248
250
|
api: "openai-completions",
|
|
249
251
|
models: [...]
|
|
@@ -592,7 +594,7 @@ Register your stream function:
|
|
|
592
594
|
```typescript
|
|
593
595
|
pi.registerProvider("my-provider", {
|
|
594
596
|
baseUrl: "https://api.example.com",
|
|
595
|
-
apiKey: "MY_API_KEY",
|
|
597
|
+
apiKey: "$MY_API_KEY",
|
|
596
598
|
api: "my-custom-api",
|
|
597
599
|
models: [...],
|
|
598
600
|
streamSimple: streamMyProvider
|
|
@@ -629,7 +631,7 @@ interface ProviderConfig {
|
|
|
629
631
|
/** API endpoint URL. Required when defining models. */
|
|
630
632
|
baseUrl?: string;
|
|
631
633
|
|
|
632
|
-
/** API key or
|
|
634
|
+
/** API key literal, env interpolation ($ENV_VAR or ${ENV_VAR}), or !command. Required when defining models (unless oauth). */
|
|
633
635
|
apiKey?: string;
|
|
634
636
|
|
|
635
637
|
/** API type for streaming. Required at provider or model level when defining models. */
|
|
@@ -642,7 +644,7 @@ interface ProviderConfig {
|
|
|
642
644
|
options?: SimpleStreamOptions
|
|
643
645
|
) => AssistantMessageEventStream;
|
|
644
646
|
|
|
645
|
-
/** Custom headers to include in requests. Values
|
|
647
|
+
/** Custom headers to include in requests. Values use the same resolution syntax as apiKey. */
|
|
646
648
|
headers?: Record<string, string>;
|
|
647
649
|
|
|
648
650
|
/** If true, adds Authorization: Bearer header with the resolved API key. */
|
|
@@ -725,6 +727,7 @@ interface ProviderModelConfig {
|
|
|
725
727
|
sendSessionAffinityHeaders?: boolean;
|
|
726
728
|
supportsCacheControlOnTools?: boolean;
|
|
727
729
|
forceAdaptiveThinking?: boolean;
|
|
730
|
+
allowEmptySignature?: boolean;
|
|
728
731
|
};
|
|
729
732
|
}
|
|
730
733
|
```
|
package/docs/extensions.md
CHANGED
|
@@ -199,7 +199,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
199
199
|
|
|
200
200
|
pi.registerProvider("local-openai", {
|
|
201
201
|
baseUrl: "http://localhost:1234/v1",
|
|
202
|
-
apiKey: "LOCAL_OPENAI_API_KEY",
|
|
202
|
+
apiKey: "$LOCAL_OPENAI_API_KEY",
|
|
203
203
|
api: "openai-completions",
|
|
204
204
|
models: payload.data.map((model) => ({
|
|
205
205
|
id: model.id,
|
|
@@ -819,6 +819,9 @@ pi.on("input", async (event, ctx) => {
|
|
|
819
819
|
// event.text - raw input (before skill/template expansion)
|
|
820
820
|
// event.images - attached images, if any
|
|
821
821
|
// event.source - "interactive" (typed), "rpc" (API), or "extension" (via sendUserMessage)
|
|
822
|
+
// event.streamingBehavior - "steer" | "followUp" | undefined
|
|
823
|
+
// undefined when idle, "steer" for mid-stream interrupts,
|
|
824
|
+
// "followUp" for messages queued until the agent finishes
|
|
822
825
|
|
|
823
826
|
// Transform: rewrite input before expansion
|
|
824
827
|
if (event.text.startsWith("?quick "))
|
|
@@ -847,7 +850,7 @@ pi.on("input", async (event, ctx) => {
|
|
|
847
850
|
- `transform` - modify text/images, then continue to expansion
|
|
848
851
|
- `handled` - skip agent entirely (first handler to return this wins)
|
|
849
852
|
|
|
850
|
-
Transforms chain across handlers. See [input-transform.ts](../examples/extensions/input-transform.ts).
|
|
853
|
+
Transforms chain across handlers. See [input-transform.ts](../examples/extensions/input-transform.ts) and [input-transform-streaming.ts](../examples/extensions/input-transform-streaming.ts) for `streamingBehavior`-aware routing.
|
|
851
854
|
|
|
852
855
|
## ExtensionContext
|
|
853
856
|
|
|
@@ -857,9 +860,13 @@ All handlers receive `ctx: ExtensionContext`.
|
|
|
857
860
|
|
|
858
861
|
UI methods for user interaction. See [Custom UI](#custom-ui) for full details.
|
|
859
862
|
|
|
863
|
+
### ctx.mode
|
|
864
|
+
|
|
865
|
+
Current run mode: `"tui"`, `"rpc"`, `"json"`, or `"print"`. Use `ctx.mode === "tui"` to guard terminal-only features such as `custom()`, component factories, terminal input, and direct TUI rendering.
|
|
866
|
+
|
|
860
867
|
### ctx.hasUI
|
|
861
868
|
|
|
862
|
-
`false` in print mode (`-p`) and JSON mode.
|
|
869
|
+
`true` in TUI and RPC modes. `false` in print mode (`-p`) and JSON mode. Use this to guard dialog methods (`select`, `confirm`, `input`, `editor`) and fire-and-forget methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `setEditorText`) that work in both TUI and RPC modes. In RPC mode, some TUI-specific methods are no-ops or return defaults (see [rpc.md](rpc.md#extension-ui-protocol)).
|
|
863
870
|
|
|
864
871
|
### ctx.cwd
|
|
865
872
|
|
|
@@ -975,6 +982,19 @@ pi.on("before_agent_start", (event, ctx) => {
|
|
|
975
982
|
|
|
976
983
|
Command handlers receive `ExtensionCommandContext`, which extends `ExtensionContext` with session control methods. These are only available in commands because they can deadlock if called from event handlers.
|
|
977
984
|
|
|
985
|
+
### ctx.getSystemPromptOptions()
|
|
986
|
+
|
|
987
|
+
Returns the base inputs Pi currently uses to build the system prompt.
|
|
988
|
+
|
|
989
|
+
```typescript
|
|
990
|
+
const options = ctx.getSystemPromptOptions();
|
|
991
|
+
const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets, prompt guidelines, appended system 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.
|
|
995
|
+
|
|
996
|
+
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.
|
|
997
|
+
|
|
978
998
|
### ctx.waitForIdle()
|
|
979
999
|
|
|
980
1000
|
Wait for the agent to finish streaming:
|
|
@@ -1490,7 +1510,8 @@ const all = pi.getAllTools();
|
|
|
1490
1510
|
// [{
|
|
1491
1511
|
// name: "read",
|
|
1492
1512
|
// description: "Read file contents...",
|
|
1493
|
-
// parameters: ...,
|
|
1513
|
+
// parameters: ...,
|
|
1514
|
+
// promptGuidelines: ["Use read to examine files instead of cat or sed."],
|
|
1494
1515
|
// sourceInfo: { path: "<builtin:read>", source: "builtin", scope: "temporary", origin: "top-level" }
|
|
1495
1516
|
// }, ...]
|
|
1496
1517
|
const names = all.map(t => t.name);
|
|
@@ -1499,7 +1520,7 @@ const extensionTools = all.filter((t) => t.sourceInfo.source !== "builtin" && t.
|
|
|
1499
1520
|
pi.setActiveTools(["read", "bash"]); // Switch to read-only
|
|
1500
1521
|
```
|
|
1501
1522
|
|
|
1502
|
-
`pi.getAllTools()` returns `name`, `description`, `parameters`, and `sourceInfo`.
|
|
1523
|
+
`pi.getAllTools()` returns `name`, `description`, `parameters`, `promptGuidelines`, and `sourceInfo`.
|
|
1503
1524
|
|
|
1504
1525
|
Typical `sourceInfo.source` values:
|
|
1505
1526
|
- `builtin` for built-in tools
|
|
@@ -1551,7 +1572,7 @@ If you need to discover models from a remote endpoint, prefer an async extension
|
|
|
1551
1572
|
pi.registerProvider("my-proxy", {
|
|
1552
1573
|
name: "My Proxy",
|
|
1553
1574
|
baseUrl: "https://proxy.example.com",
|
|
1554
|
-
apiKey: "PROXY_API_KEY", // env var
|
|
1575
|
+
apiKey: "$PROXY_API_KEY", // env var reference
|
|
1555
1576
|
api: "anthropic-messages",
|
|
1556
1577
|
models: [
|
|
1557
1578
|
{
|
|
@@ -1598,7 +1619,7 @@ pi.registerProvider("corporate-ai", {
|
|
|
1598
1619
|
**Config options:**
|
|
1599
1620
|
- `name` - Display name for the provider in UI such as `/login`.
|
|
1600
1621
|
- `baseUrl` - API endpoint URL. Required when defining models.
|
|
1601
|
-
- `apiKey` - API key
|
|
1622
|
+
- `apiKey` - API key literal, environment interpolation (`$ENV_VAR` or `${ENV_VAR}`), or leading `!command`. Required when defining models (unless `oauth` provided). `$$` escapes `$`, and `$!` escapes a literal `!` without triggering command execution.
|
|
1602
1623
|
- `api` - API type: `"anthropic-messages"`, `"openai-completions"`, `"openai-responses"`, etc.
|
|
1603
1624
|
- `headers` - Custom headers to include in requests.
|
|
1604
1625
|
- `authHeader` - If true, adds `Authorization: Bearer` header automatically.
|
|
@@ -2367,7 +2388,7 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
2367
2388
|
);
|
|
2368
2389
|
```
|
|
2369
2390
|
|
|
2370
|
-
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control visibility programmatically:
|
|
2391
|
+
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control focus or visibility programmatically:
|
|
2371
2392
|
|
|
2372
2393
|
```typescript
|
|
2373
2394
|
const result = await ctx.ui.custom<string | null>(
|
|
@@ -2375,12 +2396,19 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
2375
2396
|
{
|
|
2376
2397
|
overlay: true,
|
|
2377
2398
|
overlayOptions: { anchor: "top-right", width: "50%", margin: 2 },
|
|
2378
|
-
onHandle: (handle) => {
|
|
2399
|
+
onHandle: (handle) => {
|
|
2400
|
+
handle.focus(); // focus this overlay and bring it to the visual front
|
|
2401
|
+
// handle.unfocus({ target: editorComponent }); // release input to a specific component
|
|
2402
|
+
// handle.setHidden(true/false); // toggle visibility
|
|
2403
|
+
// handle.hide(); // permanently remove
|
|
2404
|
+
}
|
|
2379
2405
|
}
|
|
2380
2406
|
);
|
|
2381
2407
|
```
|
|
2382
2408
|
|
|
2383
|
-
|
|
2409
|
+
A focused visible overlay can reclaim input after temporary non-overlay custom UI closes. If you intentionally want another component to keep input while the overlay stays visible, call `handle.unfocus({ target })`. Passing `{ target: null }` releases the overlay without focusing another component.
|
|
2410
|
+
|
|
2411
|
+
See [tui.md](tui.md) for the full `OverlayOptions` and `OverlayHandle` API and [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for examples.
|
|
2384
2412
|
|
|
2385
2413
|
### Custom Editor
|
|
2386
2414
|
|
|
@@ -2505,14 +2533,14 @@ const highlighted = highlightCode(code, lang, theme);
|
|
|
2505
2533
|
|
|
2506
2534
|
## Mode Behavior
|
|
2507
2535
|
|
|
2508
|
-
| Mode |
|
|
2509
|
-
|
|
2510
|
-
| Interactive | Full TUI
|
|
2511
|
-
| RPC (`--mode rpc`) | JSON protocol
|
|
2512
|
-
| JSON (`--mode json`) |
|
|
2513
|
-
| Print (`-p`) |
|
|
2536
|
+
| Mode | `ctx.mode` | `ctx.hasUI` | Notes |
|
|
2537
|
+
|------|------------|-------------|-------|
|
|
2538
|
+
| Interactive | `"tui"` | `true` | Full TUI with terminal rendering |
|
|
2539
|
+
| RPC (`--mode rpc`) | `"rpc"` | `true` | Dialogs and notifications via JSON protocol; `custom()` returns `undefined`. See [rpc.md](rpc.md) |
|
|
2540
|
+
| JSON (`--mode json`) | `"json"` | `false` | Event stream to stdout; UI methods are no-ops |
|
|
2541
|
+
| Print (`-p`) | `"print"` | `false` | Extensions run but can't prompt |
|
|
2514
2542
|
|
|
2515
|
-
|
|
2543
|
+
Use `ctx.mode === "tui"` before TUI-specific features (`custom()`, component factories, terminal input). Use `ctx.hasUI` before dialog and notification methods that work in both TUI and RPC modes.
|
|
2516
2544
|
|
|
2517
2545
|
## Examples Reference
|
|
2518
2546
|
|
|
@@ -2543,6 +2571,7 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2543
2571
|
| `confirm-destructive.ts` | Confirm session changes | `on("session_before_switch")`, `on("session_before_fork")` |
|
|
2544
2572
|
| `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
|
|
2545
2573
|
| `input-transform.ts` | Transform user input | `on("input")` |
|
|
2574
|
+
| `input-transform-streaming.ts` | Streaming-aware input transform | `on("input")`, `streamingBehavior` |
|
|
2546
2575
|
| `model-status.ts` | React to model changes | `on("model_select")`, `setStatus` |
|
|
2547
2576
|
| `provider-payload.ts` | Inspect payloads and provider response headers | `on("before_provider_request")`, `on("after_provider_response")` |
|
|
2548
2577
|
| `system-prompt-header.ts` | Display system prompt info | `on("agent_start")`, `getSystemPrompt` |
|
|
@@ -2553,6 +2582,7 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2553
2582
|
| `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
|
|
2554
2583
|
| `trigger-compact.ts` | Trigger compaction manually | `compact()` |
|
|
2555
2584
|
| `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
|
|
2585
|
+
| `git-merge-and-resolve.ts` | Fetch, merge, and resolve conflicts | `on("agent_end")`, `exec`, `sendUserMessage` |
|
|
2556
2586
|
| `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
|
|
2557
2587
|
| **UI Components** |||
|
|
2558
2588
|
| `status-line.ts` | Footer status indicator | `setStatus`, session events |
|
package/docs/models.md
CHANGED
|
@@ -101,7 +101,7 @@ Use `google-generative-ai` with a `baseUrl` to add models from Google AI Studio,
|
|
|
101
101
|
"my-google": {
|
|
102
102
|
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
|
|
103
103
|
"api": "google-generative-ai",
|
|
104
|
-
"apiKey": "GEMINI_API_KEY",
|
|
104
|
+
"apiKey": "$GEMINI_API_KEY",
|
|
105
105
|
"models": [
|
|
106
106
|
{
|
|
107
107
|
"id": "gemma-4-31b-it",
|
|
@@ -143,22 +143,31 @@ Set `api` at provider level (default for all models) or model level (override pe
|
|
|
143
143
|
|
|
144
144
|
### Value Resolution
|
|
145
145
|
|
|
146
|
-
The `apiKey` and `headers` fields support
|
|
146
|
+
The `apiKey` and `headers` fields support command execution, environment interpolation, and literals:
|
|
147
147
|
|
|
148
|
-
- **Shell command:** `"!command"` executes and uses stdout
|
|
148
|
+
- **Shell command:** `"!command"` at the start executes the whole value as a command and uses stdout
|
|
149
149
|
```json
|
|
150
150
|
"apiKey": "!security find-generic-password -ws 'anthropic'"
|
|
151
151
|
"apiKey": "!op read 'op://vault/item/credential'"
|
|
152
152
|
```
|
|
153
|
-
- **Environment
|
|
153
|
+
- **Environment interpolation:** `"$ENV_VAR"` or `"${ENV_VAR}"` uses the value of the named variable. Interpolation works inside larger literals.
|
|
154
154
|
```json
|
|
155
|
-
"apiKey": "MY_API_KEY"
|
|
155
|
+
"apiKey": "$MY_API_KEY"
|
|
156
|
+
"apiKey": "${KEY_PREFIX}_${KEY_SUFFIX}"
|
|
157
|
+
```
|
|
158
|
+
`$FOO_BAR` is the variable `FOO_BAR`; use `${FOO}_BAR` when `BAR` is literal text. Missing environment variables make the value unresolved.
|
|
159
|
+
- **Escapes:** `"$$"` emits a literal `"$"`; `"$!"` emits a literal `"!"` without triggering command execution.
|
|
160
|
+
```json
|
|
161
|
+
"apiKey": "$$literal-dollar-prefix"
|
|
162
|
+
"apiKey": "$!literal-bang-prefix"
|
|
156
163
|
```
|
|
157
164
|
- **Literal value:** Used directly
|
|
158
165
|
```json
|
|
159
166
|
"apiKey": "sk-..."
|
|
160
167
|
```
|
|
161
168
|
|
|
169
|
+
Legacy uppercase env-var-like values such as `MY_API_KEY` are migrated to `$MY_API_KEY` on startup.
|
|
170
|
+
|
|
162
171
|
For `models.json`, shell commands are resolved at request time. pi intentionally does not apply built-in TTL, stale reuse, or recovery logic for arbitrary commands. Different commands need different caching and failure strategies, and pi cannot infer the right one.
|
|
163
172
|
|
|
164
173
|
If your command is slow, expensive, rate-limited, or should keep using a previous value on transient failures, wrap it in your own script or command that implements the caching or TTL behavior you want.
|
|
@@ -172,10 +181,10 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
|
|
|
172
181
|
"providers": {
|
|
173
182
|
"custom-proxy": {
|
|
174
183
|
"baseUrl": "https://proxy.example.com/v1",
|
|
175
|
-
"apiKey": "MY_API_KEY",
|
|
184
|
+
"apiKey": "$MY_API_KEY",
|
|
176
185
|
"api": "anthropic-messages",
|
|
177
186
|
"headers": {
|
|
178
|
-
"x-portkey-api-key": "PORTKEY_API_KEY",
|
|
187
|
+
"x-portkey-api-key": "$PORTKEY_API_KEY",
|
|
179
188
|
"x-secret": "!op read 'op://vault/item/secret'"
|
|
180
189
|
},
|
|
181
190
|
"models": [...]
|
|
@@ -293,7 +302,7 @@ To merge custom models into a built-in provider, include the `models` array:
|
|
|
293
302
|
"providers": {
|
|
294
303
|
"anthropic": {
|
|
295
304
|
"baseUrl": "https://my-proxy.example.com/v1",
|
|
296
|
-
"apiKey": "ANTHROPIC_API_KEY",
|
|
305
|
+
"apiKey": "$ANTHROPIC_API_KEY",
|
|
297
306
|
"api": "anthropic-messages",
|
|
298
307
|
"models": [...]
|
|
299
308
|
}
|
|
@@ -346,17 +355,20 @@ By default pi sends per-tool `eager_input_streaming: true`. If a proxy or Anthro
|
|
|
346
355
|
|
|
347
356
|
Some Anthropic models require adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) instead of the legacy budget-based thinking payload. Built-in models set this automatically. For custom providers or aliases that route to those models, set `forceAdaptiveThinking` to `true`.
|
|
348
357
|
|
|
358
|
+
Some Anthropic-compatible providers emit thinking blocks with empty signatures and still expect them on replay. Set `allowEmptySignature` to `true` only for those providers; real Anthropic rejects empty thinking signatures.
|
|
359
|
+
|
|
349
360
|
```json
|
|
350
361
|
{
|
|
351
362
|
"providers": {
|
|
352
363
|
"anthropic-proxy": {
|
|
353
364
|
"baseUrl": "https://proxy.example.com",
|
|
354
365
|
"api": "anthropic-messages",
|
|
355
|
-
"apiKey": "ANTHROPIC_PROXY_KEY",
|
|
366
|
+
"apiKey": "$ANTHROPIC_PROXY_KEY",
|
|
356
367
|
"compat": {
|
|
357
368
|
"supportsEagerToolInputStreaming": false,
|
|
358
369
|
"supportsLongCacheRetention": true,
|
|
359
|
-
"forceAdaptiveThinking": true
|
|
370
|
+
"forceAdaptiveThinking": true,
|
|
371
|
+
"allowEmptySignature": true
|
|
360
372
|
},
|
|
361
373
|
"models": [
|
|
362
374
|
{
|
|
@@ -377,6 +389,7 @@ Some Anthropic models require adaptive thinking (`thinking.type: "adaptive"` plu
|
|
|
377
389
|
| `sendSessionAffinityHeaders` | Whether to send `x-session-affinity` from the session id when caching is enabled. Default: auto-detected for known providers. |
|
|
378
390
|
| `supportsCacheControlOnTools` | Whether the provider accepts Anthropic-style `cache_control` markers on tool definitions. Default: `true`. |
|
|
379
391
|
| `forceAdaptiveThinking` | Whether to send adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) for this model. Built-in adaptive models set this automatically. Default: `false`. |
|
|
392
|
+
| `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
|
|
380
393
|
|
|
381
394
|
## OpenAI Compatibility
|
|
382
395
|
|
|
@@ -439,7 +452,7 @@ Example:
|
|
|
439
452
|
"providers": {
|
|
440
453
|
"openrouter": {
|
|
441
454
|
"baseUrl": "https://openrouter.ai/api/v1",
|
|
442
|
-
"apiKey": "OPENROUTER_API_KEY",
|
|
455
|
+
"apiKey": "$OPENROUTER_API_KEY",
|
|
443
456
|
"api": "openai-completions",
|
|
444
457
|
"models": [
|
|
445
458
|
{
|
|
@@ -489,7 +502,7 @@ Vercel AI Gateway example:
|
|
|
489
502
|
"providers": {
|
|
490
503
|
"vercel-ai-gateway": {
|
|
491
504
|
"baseUrl": "https://ai-gateway.vercel.sh/v1",
|
|
492
|
-
"apiKey": "AI_GATEWAY_API_KEY",
|
|
505
|
+
"apiKey": "$AI_GATEWAY_API_KEY",
|
|
493
506
|
"api": "openai-completions",
|
|
494
507
|
"models": [
|
|
495
508
|
{
|
package/docs/providers.md
CHANGED
|
@@ -52,6 +52,7 @@ pi
|
|
|
52
52
|
| Azure OpenAI Responses | `AZURE_OPENAI_API_KEY` | `azure-openai-responses` |
|
|
53
53
|
| OpenAI | `OPENAI_API_KEY` | `openai` |
|
|
54
54
|
| DeepSeek | `DEEPSEEK_API_KEY` | `deepseek` |
|
|
55
|
+
| NVIDIA NIM | `NVIDIA_API_KEY` | `nvidia` |
|
|
55
56
|
| Google Gemini | `GEMINI_API_KEY` | `google` |
|
|
56
57
|
| Mistral | `MISTRAL_API_KEY` | `mistral` |
|
|
57
58
|
| Groq | `GROQ_API_KEY` | `groq` |
|
|
@@ -86,6 +87,7 @@ Store credentials in `~/.senpi/agent/auth.json`:
|
|
|
86
87
|
"anthropic": { "type": "api_key", "key": "sk-ant-..." },
|
|
87
88
|
"openai": { "type": "api_key", "key": "sk-..." },
|
|
88
89
|
"deepseek": { "type": "api_key", "key": "sk-..." },
|
|
90
|
+
"nvidia": { "type": "api_key", "key": "nvapi-..." },
|
|
89
91
|
"google": { "type": "api_key", "key": "..." },
|
|
90
92
|
"opencode": { "type": "api_key", "key": "..." },
|
|
91
93
|
"opencode-go": { "type": "api_key", "key": "..." },
|
|
@@ -101,23 +103,31 @@ The file is created with `0600` permissions (user read/write only). Auth file cr
|
|
|
101
103
|
|
|
102
104
|
### Key Resolution
|
|
103
105
|
|
|
104
|
-
The `key` field supports
|
|
106
|
+
The `key` field supports command execution, environment interpolation, and literals:
|
|
105
107
|
|
|
106
|
-
- **Shell command:** `"!command"` executes and uses stdout (cached for process lifetime)
|
|
108
|
+
- **Shell command:** `"!command"` at the start executes the whole value as a command and uses stdout (cached for process lifetime)
|
|
107
109
|
```json
|
|
108
110
|
{ "type": "api_key", "key": "!security find-generic-password -ws 'anthropic'" }
|
|
109
111
|
{ "type": "api_key", "key": "!op read 'op://vault/item/credential'" }
|
|
110
112
|
```
|
|
111
|
-
- **Environment
|
|
113
|
+
- **Environment interpolation:** `"$ENV_VAR"` or `"${ENV_VAR}"` uses the value of the named variable. Interpolation works inside larger literals.
|
|
112
114
|
```json
|
|
113
|
-
{ "type": "api_key", "key": "MY_ANTHROPIC_KEY" }
|
|
115
|
+
{ "type": "api_key", "key": "$MY_ANTHROPIC_KEY" }
|
|
116
|
+
{ "type": "api_key", "key": "${KEY_PREFIX}_${KEY_SUFFIX}" }
|
|
117
|
+
```
|
|
118
|
+
`$FOO_BAR` is the variable `FOO_BAR`; use `${FOO}_BAR` when `BAR` is literal text. Missing environment variables make the value unresolved.
|
|
119
|
+
- **Escapes:** `"$$"` emits a literal `"$"`; `"$!"` emits a literal `"!"` without triggering command execution.
|
|
120
|
+
```json
|
|
121
|
+
{ "type": "api_key", "key": "$$literal-dollar-prefix" }
|
|
122
|
+
{ "type": "api_key", "key": "$!literal-bang-prefix" }
|
|
114
123
|
```
|
|
115
124
|
- **Literal value:** Used directly
|
|
116
125
|
```json
|
|
117
126
|
{ "type": "api_key", "key": "sk-ant-..." }
|
|
127
|
+
{ "type": "api_key", "key": "public" }
|
|
118
128
|
```
|
|
119
129
|
|
|
120
|
-
OAuth credentials are also stored here after `/login` and managed automatically.
|
|
130
|
+
Legacy uppercase env-var-like values such as `MY_API_KEY` are migrated to `$MY_API_KEY` on startup. OAuth credentials are also stored here after `/login` and managed automatically.
|
|
121
131
|
|
|
122
132
|
## Cloud Providers
|
|
123
133
|
|
package/docs/quickstart.md
CHANGED
|
@@ -134,6 +134,7 @@ Sessions are saved automatically:
|
|
|
134
134
|
```bash
|
|
135
135
|
senpi -c # Continue most recent session
|
|
136
136
|
senpi -r # Browse previous sessions
|
|
137
|
+
senpi --name "my task" # Set session display name at startup
|
|
137
138
|
senpi --session <path|id> # Open a specific session
|
|
138
139
|
```
|
|
139
140
|
|
package/docs/rpc.md
CHANGED
|
@@ -13,6 +13,7 @@ pi --mode rpc [options]
|
|
|
13
13
|
Common options:
|
|
14
14
|
- `--provider <name>`: Set the LLM provider (anthropic, openai, google, etc.)
|
|
15
15
|
- `--model <pattern>`: Model pattern or ID (supports `provider/id` and optional `:<thinking>`)
|
|
16
|
+
- `--name <name>` / `-n <name>`: Set the session display name at startup
|
|
16
17
|
- `--no-session`: Disable session persistence
|
|
17
18
|
- `--session-dir <path>`: Custom session storage directory
|
|
18
19
|
|
|
@@ -694,7 +695,7 @@ Response:
|
|
|
694
695
|
}
|
|
695
696
|
```
|
|
696
697
|
|
|
697
|
-
The current session name is available via `get_state` in the `sessionName` field.
|
|
698
|
+
The current session name is available via `get_state` in the `sessionName` field. To set the initial name when starting RPC mode, pass `--name <name>` or `-n <name>` to the `pi --mode rpc` process.
|
|
698
699
|
|
|
699
700
|
### Commands
|
|
700
701
|
|
|
@@ -1002,7 +1003,7 @@ Some `ExtensionUIContext` methods are not supported or degraded in RPC mode beca
|
|
|
1002
1003
|
- `getTheme()` returns `undefined`
|
|
1003
1004
|
- `setTheme()` returns `{ success: false, error: "..." }`
|
|
1004
1005
|
|
|
1005
|
-
Note: `ctx.hasUI` is `true` in RPC mode because the dialog and fire-and-forget methods are functional via the extension UI sub-protocol.
|
|
1006
|
+
Note: `ctx.mode` is `"rpc"` and `ctx.hasUI` is `true` in RPC mode because the dialog and fire-and-forget methods are functional via the extension UI sub-protocol. Use `ctx.mode === "tui"` to guard TUI-specific features like `custom()` that require a real terminal.
|
|
1006
1007
|
|
|
1007
1008
|
### Extension UI Requests (stdout)
|
|
1008
1009
|
|
package/docs/sdk.md
CHANGED
|
@@ -471,6 +471,7 @@ Specify which built-in tools to enable:
|
|
|
471
471
|
- Default built-ins: `read`, `bash`, `edit`, `write`
|
|
472
472
|
- `noTools: "all"` disables all tools
|
|
473
473
|
- `noTools: "builtin"` disables default built-ins while keeping extension and custom tools enabled
|
|
474
|
+
- `excludeTools` disables specific built-in, extension, or custom tool names after any `tools` allowlist is applied
|
|
474
475
|
|
|
475
476
|
The `edit` tool returns `details.diff` for Pi's TUI display and `details.patch` as a standard unified patch for SDK consumers.
|
|
476
477
|
|
|
@@ -486,6 +487,11 @@ const { session } = await createAgentSession({
|
|
|
486
487
|
const { session } = await createAgentSession({
|
|
487
488
|
tools: ["read", "bash", "grep"],
|
|
488
489
|
});
|
|
490
|
+
|
|
491
|
+
// Disable one tool while keeping the rest available
|
|
492
|
+
const { session } = await createAgentSession({
|
|
493
|
+
excludeTools: ["ask_question"],
|
|
494
|
+
});
|
|
489
495
|
```
|
|
490
496
|
|
|
491
497
|
#### Tools with Custom cwd
|
package/docs/session-format.md
CHANGED
|
@@ -282,7 +282,7 @@ Set `label` to `undefined` to clear a label.
|
|
|
282
282
|
|
|
283
283
|
### SessionInfoEntry
|
|
284
284
|
|
|
285
|
-
Session metadata (e.g., user-defined display name). Set via `/name`
|
|
285
|
+
Session metadata (e.g., user-defined display name). Set via `/name`, `--name` / `-n`, or `pi.setSessionName()` in extensions.
|
|
286
286
|
|
|
287
287
|
```json
|
|
288
288
|
{"type":"session_info","id":"k1l2m3n4","parentId":"j0k1l2m3","timestamp":"2024-12-03T14:35:00.000Z","name":"Refactor auth module"}
|
package/docs/sessions.md
CHANGED
|
@@ -10,6 +10,7 @@ Sessions auto-save to `~/.pi/agent/sessions/`, organized by working directory. E
|
|
|
10
10
|
pi -c # Continue most recent session
|
|
11
11
|
pi -r # Browse and select from past sessions
|
|
12
12
|
pi --no-session # Ephemeral mode; do not save
|
|
13
|
+
pi --name "my task" # Set session display name at startup
|
|
13
14
|
pi --session <path|id> # Use a specific session file or partial session ID
|
|
14
15
|
pi --fork <path|id> # Fork a session file or partial session ID into a new session
|
|
15
16
|
```
|
|
@@ -56,6 +57,13 @@ Use `/name <name>` to set a human-readable session name:
|
|
|
56
57
|
/name Refactor auth module
|
|
57
58
|
```
|
|
58
59
|
|
|
60
|
+
Set the name at startup with `--name` or `-n`:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pi --name "Refactor auth module"
|
|
64
|
+
pi --name "CI audit" -p "Review this build failure"
|
|
65
|
+
```
|
|
66
|
+
|
|
59
67
|
Named sessions are easier to find in `/resume` and `pi -r`.
|
|
60
68
|
|
|
61
69
|
## Branching with `/tree`
|
package/docs/settings.md
CHANGED
|
@@ -60,7 +60,7 @@ When this value is anything other than `"auto"`, it overrides any model-level `p
|
|
|
60
60
|
| `treeFilterMode` | string | `"default"` | Default filter for `/tree`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, `"all"` |
|
|
61
61
|
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
|
62
62
|
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
|
63
|
-
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
|
63
|
+
| `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
|
|
64
64
|
|
|
65
65
|
### Telemetry and update checks
|
|
66
66
|
|
|
@@ -143,7 +143,9 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
|
|
|
143
143
|
|---------|------|---------|-------------|
|
|
144
144
|
| `steeringMode` | string | `"one-at-a-time"` | How steering messages are sent: `"all"` or `"one-at-a-time"` |
|
|
145
145
|
| `followUpMode` | string | `"one-at-a-time"` | How follow-up messages are sent: `"all"` or `"one-at-a-time"` |
|
|
146
|
-
| `transport` | string | `"
|
|
146
|
+
| `transport` | string | `"auto"` | Preferred transport for providers that support multiple transports: `"sse"`, `"websocket"`, `"websocket-cached"`, or `"auto"` |
|
|
147
|
+
| `httpIdleTimeoutMs` | number | `300000` | HTTP header/body idle timeout in milliseconds, also used by providers with explicit stream idle timeouts. Set to `0` to disable. |
|
|
148
|
+
| `websocketConnectTimeoutMs` | number | `15000` | WebSocket connect/open handshake timeout in milliseconds for providers that support WebSocket transports. Set to `0` to disable. |
|
|
147
149
|
|
|
148
150
|
### OpenAI
|
|
149
151
|
|
package/docs/terminal-setup.md
CHANGED
|
@@ -49,6 +49,8 @@ config.enable_kitty_keyboard = true
|
|
|
49
49
|
return config
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
On WSL, WezTerm may require a visible hardware cursor for IME candidate window positioning. If CJK IME candidates do not follow the text cursor, set `PI_HARDWARE_CURSOR=1` before running pi or set `showHardwareCursor` to `true` in settings.
|
|
53
|
+
|
|
52
54
|
## VS Code (Integrated Terminal)
|
|
53
55
|
|
|
54
56
|
`keybindings.json` locations:
|
package/docs/tui.md
CHANGED
|
@@ -50,9 +50,9 @@ When a `Focusable` component has focus, TUI:
|
|
|
50
50
|
1. Sets `focused = true` on the component
|
|
51
51
|
2. Scans rendered output for `CURSOR_MARKER` (a zero-width APC escape sequence)
|
|
52
52
|
3. Positions the hardware terminal cursor at that location
|
|
53
|
-
4. Shows the hardware cursor
|
|
53
|
+
4. Shows the hardware cursor only when `showHardwareCursor` is enabled
|
|
54
54
|
|
|
55
|
-
This
|
|
55
|
+
The cursor remains hidden by default. This keeps the fake cursor rendering, while still positioning the hardware cursor for terminals that track IME candidate windows with hidden cursors. Some terminals require a visible hardware cursor for IME positioning; enable it with `showHardwareCursor`, `setShowHardwareCursor(true)`, or `PI_HARDWARE_CURSOR=1`. The `Editor` and `Input` built-in components already implement this interface.
|
|
56
56
|
|
|
57
57
|
### Container Components with Embedded Inputs
|
|
58
58
|
|
|
@@ -145,8 +145,11 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
145
145
|
// Responsive: hide on narrow terminals
|
|
146
146
|
visible: (termWidth, termHeight) => termWidth >= 80,
|
|
147
147
|
},
|
|
148
|
-
// Get handle for programmatic visibility control
|
|
148
|
+
// Get handle for programmatic focus and visibility control
|
|
149
149
|
onHandle: (handle) => {
|
|
150
|
+
// handle.focus() - focus this overlay and bring it to the visual front
|
|
151
|
+
// handle.unfocus() - release input to normal fallback
|
|
152
|
+
// handle.unfocus({ target }) - release input to a specific component or null
|
|
150
153
|
// handle.setHidden(true/false) - toggle visibility
|
|
151
154
|
// handle.hide() - permanently remove
|
|
152
155
|
},
|
|
@@ -154,6 +157,12 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
154
157
|
);
|
|
155
158
|
```
|
|
156
159
|
|
|
160
|
+
### Overlay Focus
|
|
161
|
+
|
|
162
|
+
A focused visible overlay keeps input ownership across temporary non-overlay UI. If an overlay opens another `ctx.ui.custom()` component without `{ overlay: true }`, that replacement UI receives input while it is active; when it closes, the focused overlay can reclaim input.
|
|
163
|
+
|
|
164
|
+
Use `handle.unfocus()` when a visible overlay should stop owning input and let TUI fall back to another visible capturing overlay or the previous focus target. Use `handle.unfocus({ target })` when a specific component should receive input while the overlay stays visible. Passing `{ target: null }` intentionally leaves no focused component until focus is set again.
|
|
165
|
+
|
|
157
166
|
### Overlay Lifecycle
|
|
158
167
|
|
|
159
168
|
Overlay components are disposed when closed. Don't reuse references - create fresh instances:
|