@astralyn/pi 0.82.7 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -5099
- package/README.md +12 -111
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.js.map +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +28 -2
- 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 -2
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +23 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +117 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/experimental/auth.d.ts +16 -0
- package/dist/cli/experimental/auth.d.ts.map +1 -0
- package/dist/cli/experimental/auth.js +13 -0
- package/dist/cli/experimental/auth.js.map +1 -0
- package/dist/cli/experimental/cli.d.ts +6 -0
- package/dist/cli/experimental/cli.d.ts.map +1 -0
- package/dist/cli/experimental/cli.js +5 -0
- package/dist/cli/experimental/cli.js.map +1 -0
- package/dist/cli/experimental/command-options.d.ts +17 -0
- package/dist/cli/experimental/command-options.d.ts.map +1 -0
- package/dist/cli/experimental/command-options.js +35 -0
- package/dist/cli/experimental/command-options.js.map +1 -0
- package/dist/cli/experimental/command.d.ts +63 -0
- package/dist/cli/experimental/command.d.ts.map +1 -0
- package/dist/cli/experimental/command.js +127 -0
- package/dist/cli/experimental/command.js.map +1 -0
- package/dist/cli/experimental/commands/client.d.ts +13 -0
- package/dist/cli/experimental/commands/client.d.ts.map +1 -0
- package/dist/cli/experimental/commands/client.js +25 -0
- package/dist/cli/experimental/commands/client.js.map +1 -0
- package/dist/cli/experimental/commands/pi.d.ts +15 -0
- package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
- package/dist/cli/experimental/commands/pi.js +28 -0
- package/dist/cli/experimental/commands/pi.js.map +1 -0
- package/dist/cli/experimental/commands/server.d.ts +13 -0
- package/dist/cli/experimental/commands/server.d.ts.map +1 -0
- package/dist/cli/experimental/commands/server.js +25 -0
- package/dist/cli/experimental/commands/server.js.map +1 -0
- package/dist/cli/experimental/transport-address.d.ts +10 -0
- package/dist/cli/experimental/transport-address.d.ts.map +1 -0
- package/dist/cli/experimental/transport-address.js +38 -0
- package/dist/cli/experimental/transport-address.js.map +1 -0
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +1 -1
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.d.ts +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +2 -2
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/project-trust.d.ts.map +1 -1
- package/dist/cli/project-trust.js.map +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +2 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/remote-session.d.ts +53 -0
- package/dist/client/remote-session.d.ts.map +1 -0
- package/dist/client/remote-session.js +340 -0
- package/dist/client/remote-session.js.map +1 -0
- package/dist/client/transcript.d.ts +12 -0
- package/dist/client/transcript.d.ts.map +1 -0
- package/dist/client/transcript.js +98 -0
- package/dist/client/transcript.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- 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 +3 -8
- package/dist/core/agent-session-runtime.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 +31 -11
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +189 -192
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts +15 -9
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +159 -41
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/cache-stats.d.ts.map +1 -1
- package/dist/core/cache-stats.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.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/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +43 -20
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +31 -28
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +28 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +10 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +18 -19
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -0
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/keybindings.d.ts +157 -125
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +0 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +37 -13
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +4 -2
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +13 -11
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +4 -3
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +41 -10
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +30 -13
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +239 -91
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/models-store.d.ts +12 -7
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +84 -16
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +4 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +76 -48
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts +8 -0
- package/dist/core/pi-manifest.d.ts.map +1 -0
- package/dist/core/pi-manifest.js +25 -0
- package/dist/core/pi-manifest.js.map +1 -0
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-attribution.js.map +1 -1
- package/dist/core/provider-composer.d.ts +4 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +36 -15
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +73 -67
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +15 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +68 -51
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +5 -5
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +12 -10
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-cwd.js +0 -1
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +10 -12
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +47 -33
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/source-info.d.ts.map +1 -1
- package/dist/core/source-info.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +12 -10
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +4 -3
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts +3 -0
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +47 -20
- 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/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +12 -18
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +0 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +48 -10
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/usage-totals.d.ts.map +1 -1
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/extensions/biu/index.d.ts +19 -0
- package/dist/extensions/biu/index.d.ts.map +1 -0
- package/dist/extensions/biu/index.js +350 -0
- package/dist/extensions/biu/index.js.map +1 -0
- package/dist/extensions/biu/prompts.d.ts +26 -0
- package/dist/extensions/biu/prompts.d.ts.map +1 -0
- package/dist/extensions/biu/prompts.js +260 -0
- package/dist/extensions/biu/prompts.js.map +1 -0
- package/dist/extensions/biu/workspace.d.ts +122 -0
- package/dist/extensions/biu/workspace.d.ts.map +1 -0
- package/dist/extensions/biu/workspace.js +404 -0
- package/dist/extensions/biu/workspace.js.map +1 -0
- package/dist/extensions/deepwiki/client.d.ts.map +1 -1
- package/dist/extensions/deepwiki/client.js.map +1 -1
- package/dist/extensions/deepwiki/constants.d.ts.map +1 -1
- package/dist/extensions/deepwiki/constants.js.map +1 -1
- package/dist/extensions/deepwiki/contents.d.ts.map +1 -1
- package/dist/extensions/deepwiki/contents.js.map +1 -1
- package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
- package/dist/extensions/deepwiki/execute.js.map +1 -1
- package/dist/extensions/deepwiki/http.d.ts.map +1 -1
- package/dist/extensions/deepwiki/http.js.map +1 -1
- package/dist/extensions/deepwiki/index.d.ts.map +1 -1
- package/dist/extensions/deepwiki/index.js.map +1 -1
- package/dist/extensions/deepwiki/render.d.ts.map +1 -1
- package/dist/extensions/deepwiki/render.js.map +1 -1
- package/dist/extensions/deepwiki/schema.d.ts +1 -1
- package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
- package/dist/extensions/deepwiki/schema.js.map +1 -1
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +2 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/llama/client.d.ts.map +1 -1
- package/dist/extensions/llama/client.js +0 -2
- package/dist/extensions/llama/client.js.map +1 -1
- package/dist/extensions/llama/huggingface.d.ts.map +1 -1
- package/dist/extensions/llama/huggingface.js +0 -2
- package/dist/extensions/llama/huggingface.js.map +1 -1
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +11 -2
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +22 -8
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/extensions/llama/ui.d.ts.map +1 -1
- package/dist/extensions/llama/ui.js +12 -28
- package/dist/extensions/llama/ui.js.map +1 -1
- package/dist/extensions/question/constants.d.ts.map +1 -1
- package/dist/extensions/question/constants.js.map +1 -1
- package/dist/extensions/question/dialog-primitives.d.ts.map +1 -1
- package/dist/extensions/question/dialog-primitives.js.map +1 -1
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/index.d.ts.map +1 -1
- package/dist/extensions/question/index.js.map +1 -1
- package/dist/extensions/question/limits.d.ts.map +1 -1
- package/dist/extensions/question/render-cache.d.ts.map +1 -1
- package/dist/extensions/question/render-cache.js +3 -4
- package/dist/extensions/question/render-cache.js.map +1 -1
- package/dist/extensions/question/render.d.ts.map +1 -1
- package/dist/extensions/question/render.js.map +1 -1
- package/dist/extensions/question/results.d.ts.map +1 -1
- package/dist/extensions/question/results.js.map +1 -1
- package/dist/extensions/question/schema.d.ts.map +1 -1
- package/dist/extensions/question/schema.js.map +1 -1
- package/dist/extensions/question/state.d.ts.map +1 -1
- package/dist/extensions/question/state.js.map +1 -1
- package/dist/extensions/question/types.d.ts.map +1 -1
- package/dist/extensions/rewind/anchor.d.ts.map +1 -1
- package/dist/extensions/rewind/anchor.js.map +1 -1
- package/dist/extensions/rewind/config.d.ts.map +1 -1
- package/dist/extensions/rewind/config.js.map +1 -1
- package/dist/extensions/rewind/engine.d.ts.map +1 -1
- package/dist/extensions/rewind/engine.js.map +1 -1
- package/dist/extensions/rewind/gc.d.ts.map +1 -1
- package/dist/extensions/rewind/gc.js.map +1 -1
- package/dist/extensions/rewind/index.d.ts.map +1 -1
- package/dist/extensions/rewind/index.js.map +1 -1
- package/dist/extensions/rewind/menu.d.ts.map +1 -1
- package/dist/extensions/rewind/menu.js.map +1 -1
- package/dist/extensions/rewind/paths.d.ts.map +1 -1
- package/dist/extensions/rewind/paths.js.map +1 -1
- package/dist/extensions/rewind/restore.d.ts.map +1 -1
- package/dist/extensions/rewind/restore.js.map +1 -1
- package/dist/extensions/rewind/snapshot.d.ts.map +1 -1
- package/dist/extensions/rewind/snapshot.js.map +1 -1
- package/dist/extensions/rewind/storage.d.ts.map +1 -1
- package/dist/extensions/rewind/storage.js.map +1 -1
- package/dist/extensions/rewind/text.d.ts.map +1 -1
- package/dist/extensions/rewind/text.js.map +1 -1
- package/dist/extensions/rewind/tool-path.d.ts.map +1 -1
- package/dist/extensions/rewind/tool-path.js.map +1 -1
- package/dist/extensions/router/constants.d.ts +3 -0
- package/dist/extensions/router/constants.d.ts.map +1 -1
- package/dist/extensions/router/constants.js +3 -0
- package/dist/extensions/router/constants.js.map +1 -1
- package/dist/extensions/router/dialog.d.ts +14 -7
- package/dist/extensions/router/dialog.d.ts.map +1 -1
- package/dist/extensions/router/dialog.js +70 -132
- package/dist/extensions/router/dialog.js.map +1 -1
- package/dist/extensions/router/index.d.ts.map +1 -1
- package/dist/extensions/router/index.js.map +1 -1
- package/dist/extensions/router/presets.d.ts +8 -3
- package/dist/extensions/router/presets.d.ts.map +1 -1
- package/dist/extensions/router/presets.js +33 -17
- package/dist/extensions/router/presets.js.map +1 -1
- package/dist/extensions/router/probe.d.ts.map +1 -1
- package/dist/extensions/router/probe.js.map +1 -1
- package/dist/extensions/router/register.d.ts +3 -3
- package/dist/extensions/router/register.d.ts.map +1 -1
- package/dist/extensions/router/register.js.map +1 -1
- package/dist/extensions/router/store.d.ts.map +1 -1
- package/dist/extensions/router/store.js.map +1 -1
- package/dist/extensions/router/stream.d.ts.map +1 -1
- package/dist/extensions/router/stream.js.map +1 -1
- package/dist/extensions/router/types.d.ts.map +1 -1
- package/dist/extensions/router/ui.d.ts +11 -2
- package/dist/extensions/router/ui.d.ts.map +1 -1
- package/dist/extensions/router/ui.js +316 -171
- package/dist/extensions/router/ui.js.map +1 -1
- package/dist/extensions/statusline/index.d.ts.map +1 -1
- package/dist/extensions/statusline/index.js +17 -9
- package/dist/extensions/statusline/index.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/index.d.ts +3 -0
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +83 -12
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/picker.d.ts.map +1 -1
- package/dist/extensions/subagent/picker.js +2 -9
- package/dist/extensions/subagent/picker.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +33 -9
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/retry.d.ts.map +1 -1
- package/dist/extensions/subagent/retry.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +2 -1
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +10 -12
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +41 -1
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/settings.d.ts.map +1 -1
- package/dist/extensions/subagent/settings.js +46 -36
- package/dist/extensions/subagent/settings.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +0 -1
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/todo/constants.d.ts.map +1 -1
- package/dist/extensions/todo/constants.js.map +1 -1
- package/dist/extensions/todo/index.d.ts.map +1 -1
- package/dist/extensions/todo/index.js.map +1 -1
- package/dist/extensions/todo/overlay.d.ts.map +1 -1
- package/dist/extensions/todo/overlay.js +6 -10
- package/dist/extensions/todo/overlay.js.map +1 -1
- package/dist/extensions/todo/schema.d.ts +2 -2
- package/dist/extensions/todo/schema.d.ts.map +1 -1
- package/dist/extensions/todo/state.d.ts.map +1 -1
- package/dist/extensions/todo/state.js.map +1 -1
- package/dist/extensions/todo/view.d.ts.map +1 -1
- package/dist/extensions/todo/view.js.map +1 -1
- package/dist/index.d.ts +4 -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 +57 -5
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/index.d.ts +1 -0
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +6 -10
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -11
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -10
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +0 -3
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -3
- 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 +1 -3
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +5 -22
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +1 -7
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +8 -8
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +1 -4
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -7
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +6 -8
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
- package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +1 -7
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +2 -8
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +1 -9
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +2 -4
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -4
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -9
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
- package/dist/modes/interactive/components/markdown-transform.js +19 -0
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
- package/dist/modes/interactive/components/mermaid.d.ts +11 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +75 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +32 -30
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +3 -11
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +34 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +35 -60
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +30 -14
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +0 -2
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -2
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +18 -36
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-group.js +2 -3
- package/dist/modes/interactive/components/tool-group.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +19 -39
- 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 +0 -6
- package/dist/modes/interactive/components/trust-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +3 -6
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +3 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +8 -5
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +40 -3
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +46 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +538 -275
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-search.d.ts.map +1 -1
- package/dist/modes/interactive/model-search.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -0
- package/dist/modes/interactive/theme/light.json +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +11 -8
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +5 -1
- package/dist/modes/interactive/theme/theme.d.ts +4 -4
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +13 -9
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +28 -0
- package/dist/modes/json-event.d.ts.map +1 -0
- package/dist/modes/json-event.js +12 -0
- package/dist/modes/json-event.js.map +1 -0
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +12 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/dist/modes/rpc/jsonl.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +5 -4
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -8
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +17 -3
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +11 -9
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/rpc-entry.js +1 -0
- package/dist/rpc-entry.js.map +1 -1
- package/dist/utils/abort.d.ts +5 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +48 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js.map +1 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +22 -2
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/coalescing-terminal.d.ts +1 -0
- package/dist/utils/coalescing-terminal.d.ts.map +1 -1
- package/dist/utils/coalescing-terminal.js +16 -8
- package/dist/utils/coalescing-terminal.js.map +1 -1
- package/dist/utils/deprecation.d.ts.map +1 -1
- package/dist/utils/deprecation.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/html.d.ts.map +1 -1
- package/dist/utils/html.js.map +1 -1
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts.map +1 -1
- package/dist/utils/image-process.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/image-resize-worker.d.ts.map +1 -1
- package/dist/utils/image-resize-worker.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/management-http.d.ts +23 -0
- package/dist/utils/management-http.d.ts.map +1 -0
- package/dist/utils/management-http.js +50 -0
- package/dist/utils/management-http.js.map +1 -0
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/open-browser.d.ts.map +1 -1
- package/dist/utils/open-browser.js.map +1 -1
- package/dist/utils/paths.d.ts +5 -3
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +25 -4
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/photon.js.map +1 -1
- package/dist/utils/pi-user-agent.d.ts.map +1 -1
- package/dist/utils/pi-user-agent.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tool-result-images.d.ts +19 -0
- package/dist/utils/tool-result-images.d.ts.map +1 -0
- package/dist/utils/tool-result-images.js +45 -0
- package/dist/utils/tool-result-images.js.map +1 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +4 -6
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +4 -0
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +20 -2
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/windows-self-update.d.ts.map +1 -1
- package/dist/utils/windows-self-update.js.map +1 -1
- package/docs/bundled/README.md +14 -16
- package/docs/bundled/extensions/biu.md +63 -0
- package/docs/bundled/extensions/router.md +20 -14
- package/docs/bundled/extensions/statusline.md +7 -5
- package/docs/bundled/themes.md +1 -1
- package/docs/compaction.md +25 -30
- package/docs/custom-provider.md +303 -467
- package/docs/development.md +83 -0
- package/docs/docs.json +6 -10
- package/docs/extensions.md +139 -119
- package/docs/index.md +18 -74
- package/docs/json.md +40 -15
- package/docs/keybindings.md +38 -10
- package/docs/models.md +210 -150
- package/docs/providers.md +3 -1
- package/docs/quickstart.md +5 -3
- package/docs/rpc.md +177 -134
- package/docs/sdk.md +165 -178
- package/docs/security.md +2 -2
- package/docs/session-format.md +139 -119
- package/docs/settings.md +4 -1
- package/docs/skills.md +0 -1
- package/docs/themes.md +5 -3
- package/docs/tui.md +411 -549
- package/docs/usage.md +11 -11
- package/examples/README.md +6 -1
- package/examples/extensions/README.md +13 -33
- package/examples/extensions/custom-compaction.ts +1 -16
- package/examples/extensions/custom-provider-anthropic/index.ts +11 -4
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -1
- package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
- package/examples/extensions/handoff.ts +2 -11
- package/examples/extensions/qna.ts +3 -7
- package/examples/extensions/summarize.ts +8 -18
- package/examples/extensions/truncated-tool.ts +2 -2
- package/examples/rpc-extension-ui.ts +11 -2
- package/examples/sdk/02-custom-model.ts +1 -2
- package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
- package/examples/sdk/12-full-control.ts +3 -1
- package/examples/sdk/README.md +1 -0
- package/npm-shrinkwrap.json +199 -270
- package/package.json +16 -9
- package/dist/extensions/plan/constants.d.ts +0 -68
- package/dist/extensions/plan/constants.d.ts.map +0 -1
- package/dist/extensions/plan/constants.js +0 -100
- package/dist/extensions/plan/constants.js.map +0 -1
- package/dist/extensions/plan/index.d.ts +0 -30
- package/dist/extensions/plan/index.d.ts.map +0 -1
- package/dist/extensions/plan/index.js +0 -429
- package/dist/extensions/plan/index.js.map +0 -1
- package/dist/extensions/plan/schema.d.ts +0 -20
- package/dist/extensions/plan/schema.d.ts.map +0 -1
- package/dist/extensions/plan/schema.js +0 -13
- package/dist/extensions/plan/schema.js.map +0 -1
- package/dist/extensions/plan/state.d.ts +0 -38
- package/dist/extensions/plan/state.d.ts.map +0 -1
- package/dist/extensions/plan/state.js +0 -96
- package/dist/extensions/plan/state.js.map +0 -1
- package/dist/extensions/plan/storage.d.ts +0 -26
- package/dist/extensions/plan/storage.d.ts.map +0 -1
- package/dist/extensions/plan/storage.js +0 -83
- package/dist/extensions/plan/storage.js.map +0 -1
- package/dist/extensions/plan/view.d.ts +0 -44
- package/dist/extensions/plan/view.d.ts.map +0 -1
- package/dist/extensions/plan/view.js +0 -149
- package/dist/extensions/plan/view.js.map +0 -1
- package/docs/bundled/extensions/README.md +0 -19
- package/docs/bundled/extensions/plan.md +0 -34
- package/examples/extensions/plan-mode/README.md +0 -66
- package/examples/extensions/plan-mode/index.ts +0 -390
- package/examples/extensions/plan-mode/utils.ts +0 -168
package/docs/custom-provider.md
CHANGED
|
@@ -1,433 +1,328 @@
|
|
|
1
1
|
# Custom Providers
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
- **Proxies** - Route requests through corporate proxies or API gateways
|
|
6
|
-
- **Custom endpoints** - Use self-hosted or private model deployments
|
|
7
|
-
- **OAuth/SSO** - Add authentication flows for enterprise providers
|
|
8
|
-
- **Custom APIs** - Implement streaming for non-standard LLM APIs
|
|
3
|
+
Use an extension when a provider needs runtime behavior: an OAuth flow, dynamic catalog, proxy-specific headers, payload rewriting, or a streaming protocol that Pi does not already support. For built-in provider setup, see [Providers](providers.md); for a static OpenAI-compatible endpoint, `models.json` is usually simpler; see [Custom Models](models.md).
|
|
9
4
|
|
|
10
5
|
## Example Extensions
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
These published extensions are the maintained end-to-end references:
|
|
13
8
|
|
|
14
|
-
- [`
|
|
15
|
-
- [`
|
|
9
|
+
- [`custom-provider-anthropic`](../examples/extensions/custom-provider-anthropic/) implements OAuth and a custom event stream.
|
|
10
|
+
- [`custom-provider-gitlab-duo`](../examples/extensions/custom-provider-gitlab-duo/) obtains provider-specific credentials, then delegates to Pi AI's public Anthropic and OpenAI stream APIs.
|
|
16
11
|
|
|
17
12
|
## Table of Contents
|
|
18
13
|
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
14
|
+
- [Provider Registration](#provider-registration)
|
|
15
|
+
- [Configuration Form](#configuration-form)
|
|
16
|
+
- [Complete pi-ai Provider](#complete-pi-ai-provider)
|
|
17
|
+
- [Composition, Updates, and Removal](#composition-updates-and-removal)
|
|
18
|
+
- [Dynamic Model Catalogs](#dynamic-model-catalogs)
|
|
19
|
+
- [API and Model Configuration](#api-and-model-configuration)
|
|
20
|
+
- [Authentication, Headers, and Request Hooks](#authentication-headers-and-request-hooks)
|
|
21
|
+
- [API Keys and Registered Headers](#api-keys-and-registered-headers)
|
|
22
|
+
- [OAuth](#oauth)
|
|
23
|
+
- [Payload and Header Hooks](#payload-and-header-hooks)
|
|
24
|
+
- [Custom Streaming APIs](#custom-streaming-apis)
|
|
25
|
+
- [Stream Contract](#stream-contract)
|
|
26
|
+
- [Forwarding Hooks from a Custom Stream](#forwarding-hooks-from-a-custom-stream)
|
|
27
|
+
- [Context Overflow Recovery](#context-overflow-recovery)
|
|
28
|
+
- [Testing](#testing)
|
|
29
|
+
|
|
30
|
+
## Provider Registration
|
|
31
|
+
|
|
32
|
+
`pi.registerProvider()` has two forms:
|
|
33
|
+
|
|
34
|
+
1. `pi.registerProvider(name, config)` configures a provider, models, optional OAuth, and an optional custom `streamSimple` handler.
|
|
35
|
+
2. `pi.registerProvider(provider)` registers a complete public pi-ai `Provider` when the extension owns native auth, catalog, filtering, or both stream methods.
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
An extension factory may be `async`; Pi waits for it before startup continues. Register during the factory when models must be present in `/model` and `pi --list-models`. See [Writing an Extension](extensions.md#writing-an-extension).
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
### Configuration Form
|
|
40
|
+
|
|
41
|
+
Use the configuration form for a standard supported API or to override a built-in provider:
|
|
34
42
|
|
|
35
43
|
```typescript
|
|
36
|
-
import { createProvider, openAICompletionsApi } from "@earendil-works/pi-ai";
|
|
37
44
|
import type { ExtensionAPI } from "@astralyn/pi";
|
|
38
45
|
|
|
39
46
|
export default function (pi: ExtensionAPI) {
|
|
40
|
-
|
|
41
|
-
id: "native-local",
|
|
42
|
-
name: "Native Local",
|
|
43
|
-
baseUrl: "http://localhost:8080/v1",
|
|
44
|
-
auth: {
|
|
45
|
-
apiKey: {
|
|
46
|
-
name: "Local server API key",
|
|
47
|
-
async login(interaction) {
|
|
48
|
-
return {
|
|
49
|
-
type: "api_key",
|
|
50
|
-
key: await interaction.prompt({ type: "secret", message: "API key" })
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
async resolve({ credential }) {
|
|
54
|
-
return credential?.key
|
|
55
|
-
? { auth: { apiKey: credential.key }, source: "stored API key" }
|
|
56
|
-
: undefined;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
models: [],
|
|
61
|
-
api: openAICompletionsApi()
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
// Legacy provider-config form:
|
|
65
|
-
// Override baseUrl for existing provider
|
|
47
|
+
// Keeps Anthropic's existing models and auth; only the endpoint changes.
|
|
66
48
|
pi.registerProvider("anthropic", {
|
|
67
|
-
baseUrl: "https://proxy.example.com"
|
|
49
|
+
baseUrl: "https://proxy.example.com/anthropic",
|
|
50
|
+
headers: { "X-Proxy-Tenant": "$PROXY_TENANT" },
|
|
68
51
|
});
|
|
69
52
|
|
|
70
|
-
//
|
|
71
|
-
pi.registerProvider("
|
|
72
|
-
name: "
|
|
73
|
-
baseUrl: "
|
|
74
|
-
apiKey: "
|
|
53
|
+
// A new OpenAI-compatible provider.
|
|
54
|
+
pi.registerProvider("local-openai", {
|
|
55
|
+
name: "Local OpenAI",
|
|
56
|
+
baseUrl: "http://127.0.0.1:8080/v1",
|
|
57
|
+
apiKey: "local", // A literal placeholder for a server that ignores keys.
|
|
75
58
|
api: "openai-completions",
|
|
76
59
|
models: [
|
|
77
60
|
{
|
|
78
|
-
id: "
|
|
79
|
-
name: "
|
|
61
|
+
id: "local-model",
|
|
62
|
+
name: "Local Model",
|
|
80
63
|
reasoning: false,
|
|
81
|
-
input: ["text"
|
|
64
|
+
input: ["text"],
|
|
82
65
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
83
66
|
contextWindow: 128000,
|
|
84
|
-
maxTokens: 4096
|
|
85
|
-
}
|
|
86
|
-
]
|
|
67
|
+
maxTokens: 4096,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
87
70
|
});
|
|
88
71
|
}
|
|
89
72
|
```
|
|
90
73
|
|
|
91
|
-
|
|
74
|
+
When `models` is omitted, existing models are retained. When it is supplied, it replaces the models supplied by the built-in/native provider and earlier extension registration for that provider. A model can set its own `api` or `baseUrl` to override the provider default.
|
|
92
75
|
|
|
93
|
-
|
|
76
|
+
A `streamSimple` registration must also set the provider-level `api`. Pi invokes that handler only for models whose effective `api` matches the registered API tag. A custom tag such as `"my-company-api"` is valid; do **not** call the compatibility API registry's `registerApiProvider()` merely to use it with `pi.registerProvider()`.
|
|
94
77
|
|
|
95
|
-
|
|
78
|
+
### Complete pi-ai Provider
|
|
79
|
+
|
|
80
|
+
For a provider with native behavior, construct a public pi-ai `Provider` and register it directly. `createProvider`, `envApiKeyAuth`, and the `Provider`/`Model` types are public root exports. The lazy built-in API factories, including `openAICompletionsApi`, are public from `@earendil-works/pi-ai/compat`.
|
|
96
81
|
|
|
97
82
|
```typescript
|
|
98
|
-
|
|
99
|
-
pi
|
|
100
|
-
|
|
101
|
-
});
|
|
83
|
+
import type { ExtensionAPI } from "@astralyn/pi";
|
|
84
|
+
import { createProvider, envApiKeyAuth, type Model } from "@earendil-works/pi-ai";
|
|
85
|
+
import { openAICompletionsApi } from "@earendil-works/pi-ai/compat";
|
|
102
86
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
87
|
+
const model: Model<"openai-completions"> = {
|
|
88
|
+
id: "local-model",
|
|
89
|
+
name: "Local Model",
|
|
90
|
+
api: "openai-completions",
|
|
91
|
+
provider: "native-local",
|
|
92
|
+
baseUrl: "http://127.0.0.1:8080/v1",
|
|
93
|
+
reasoning: false,
|
|
94
|
+
input: ["text"],
|
|
95
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
96
|
+
contextWindow: 128000,
|
|
97
|
+
maxTokens: 4096,
|
|
98
|
+
};
|
|
109
99
|
|
|
110
|
-
|
|
111
|
-
pi.registerProvider(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
100
|
+
export default function (pi: ExtensionAPI) {
|
|
101
|
+
pi.registerProvider(
|
|
102
|
+
createProvider({
|
|
103
|
+
id: "native-local",
|
|
104
|
+
name: "Native Local",
|
|
105
|
+
baseUrl: model.baseUrl,
|
|
106
|
+
auth: {
|
|
107
|
+
apiKey: envApiKeyAuth("Local server API key", ["LOCAL_OPENAI_API_KEY"]),
|
|
108
|
+
},
|
|
109
|
+
models: [model],
|
|
110
|
+
api: openAICompletionsApi(),
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
117
114
|
```
|
|
118
115
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
## Register New Provider
|
|
116
|
+
A complete `Provider` must have auth, `getModels()`, `stream()`, and `streamSimple()` behavior. `createProvider()` supplies the model/catalog plumbing and both stream methods from the public `ProviderStreams` value passed as `api`; use a hand-written `Provider` only when that helper does not fit. For hand-written API-key auth, `login(interaction)` returns an `ApiKeyCredential` and `resolve({ ctx, credential })` returns an `AuthResult` or `undefined`; `envApiKeyAuth()` implements that standard pattern.
|
|
122
117
|
|
|
123
|
-
|
|
118
|
+
### Composition, Updates, and Removal
|
|
124
119
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
import type { ExtensionAPI } from "@astralyn/pi";
|
|
129
|
-
|
|
130
|
-
export default async function (pi: ExtensionAPI) {
|
|
131
|
-
const response = await fetch("http://localhost:1234/v1/models");
|
|
132
|
-
const payload = (await response.json()) as {
|
|
133
|
-
data: Array<{
|
|
134
|
-
id: string;
|
|
135
|
-
name?: string;
|
|
136
|
-
context_window?: number;
|
|
137
|
-
max_tokens?: number;
|
|
138
|
-
}>;
|
|
139
|
-
};
|
|
120
|
+
A complete registered `Provider` is the base provider for its ID. Pi applies `models.json` configuration above that base, including final `modelOverrides`; see [Per-model Overrides](models.md#per-model-overrides). A named configuration registration is instead applied over the native/built-in provider and `models.json` layers.
|
|
140
121
|
|
|
141
|
-
|
|
142
|
-
baseUrl: "http://localhost:1234/v1",
|
|
143
|
-
apiKey: "$LOCAL_OPENAI_API_KEY",
|
|
144
|
-
api: "openai-completions",
|
|
145
|
-
models: payload.data.map((model) => ({
|
|
146
|
-
id: model.id,
|
|
147
|
-
name: model.name ?? model.id,
|
|
148
|
-
reasoning: false,
|
|
149
|
-
input: ["text"],
|
|
150
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
151
|
-
contextWindow: model.context_window ?? 128000,
|
|
152
|
-
maxTokens: model.max_tokens ?? 4096,
|
|
153
|
-
})),
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
```
|
|
122
|
+
A later named registration for the same ID merges its defined configuration values with the prior named registration. Registering a complete `Provider` for that ID replaces the named registration; registering by name replaces a complete extension provider for that ID.
|
|
157
123
|
|
|
158
|
-
|
|
124
|
+
Provider calls made from the factory are queued until the extension runner is ready. Calls made later, such as from a command, take effect immediately; no `/reload` is needed.
|
|
159
125
|
|
|
160
126
|
```typescript
|
|
161
|
-
pi.
|
|
162
|
-
baseUrl: "https://api.my-llm.com/v1",
|
|
163
|
-
apiKey: "$MY_LLM_API_KEY", // env var reference
|
|
164
|
-
api: "openai-completions", // which streaming API to use
|
|
165
|
-
models: [
|
|
166
|
-
{
|
|
167
|
-
id: "my-llm-large",
|
|
168
|
-
name: "My LLM Large",
|
|
169
|
-
reasoning: true, // supports extended thinking
|
|
170
|
-
input: ["text", "image"],
|
|
171
|
-
cost: {
|
|
172
|
-
input: 3.0, // $/million tokens
|
|
173
|
-
output: 15.0,
|
|
174
|
-
cacheRead: 0.3,
|
|
175
|
-
cacheWrite: 3.75
|
|
176
|
-
},
|
|
177
|
-
contextWindow: 200000,
|
|
178
|
-
maxTokens: 16384
|
|
179
|
-
}
|
|
180
|
-
]
|
|
181
|
-
});
|
|
127
|
+
pi.unregisterProvider("local-openai");
|
|
182
128
|
```
|
|
183
129
|
|
|
184
|
-
|
|
130
|
+
`unregisterProvider()` removes either form registered by the extension and recomposes the remaining layers. A built-in provider is restored when one exists; `models.json` configuration remains, while a provider defined only by the extension disappears.
|
|
185
131
|
|
|
186
|
-
|
|
132
|
+
### Dynamic Model Catalogs
|
|
187
133
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Use `pi.unregisterProvider(name)` to remove a provider that was previously registered via `pi.registerProvider(name, ...)`:
|
|
134
|
+
The configuration form can refresh an extension-owned model list. Pi calls `refreshModels` during model refresh. Its returned list replaces the extension-provided models. Use `context.signal` for requests and `context.store` only when the catalog should persist across sessions.
|
|
191
135
|
|
|
192
136
|
```typescript
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
apiKey: "$MY_LLM_API_KEY",
|
|
137
|
+
pi.registerProvider("local-openai", {
|
|
138
|
+
baseUrl: "http://127.0.0.1:8080/v1",
|
|
139
|
+
apiKey: "local",
|
|
197
140
|
api: "openai-completions",
|
|
198
|
-
|
|
199
|
-
{
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
141
|
+
async refreshModels({ signal }) {
|
|
142
|
+
const response = await fetch("http://127.0.0.1:8080/v1/models", { signal });
|
|
143
|
+
if (!response.ok) throw new Error(`Model discovery failed: ${response.status}`);
|
|
144
|
+
|
|
145
|
+
const payload = (await response.json()) as { data: Array<{ id: string }> };
|
|
146
|
+
return payload.data.map((entry) => ({
|
|
147
|
+
id: entry.id,
|
|
148
|
+
name: entry.id,
|
|
149
|
+
reasoning: false,
|
|
150
|
+
input: ["text"],
|
|
151
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
152
|
+
contextWindow: 128000,
|
|
153
|
+
maxTokens: 4096,
|
|
154
|
+
}));
|
|
155
|
+
},
|
|
209
156
|
});
|
|
210
|
-
|
|
211
|
-
// Later, remove it
|
|
212
|
-
pi.unregisterProvider("my-llm");
|
|
213
157
|
```
|
|
214
158
|
|
|
215
|
-
|
|
159
|
+
For one-time discovery that must finish before model selection, make the extension factory `async`, fetch the catalog there, and then call `registerProvider()` with `models`.
|
|
216
160
|
|
|
217
|
-
|
|
161
|
+
## API and Model Configuration
|
|
218
162
|
|
|
219
|
-
|
|
163
|
+
Set `api` on the provider as the default, or on a model when one provider has models served by different APIs. The built-in API tags are:
|
|
220
164
|
|
|
221
|
-
|
|
165
|
+
| API | Use |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| `anthropic-messages` | Anthropic Messages-compatible APIs |
|
|
168
|
+
| `openai-completions` | OpenAI Chat Completions-compatible APIs |
|
|
169
|
+
| `openai-responses` | OpenAI Responses APIs |
|
|
170
|
+
| `azure-openai-responses` | Azure OpenAI Responses APIs |
|
|
171
|
+
| `openai-codex-responses` | OpenAI Codex Responses APIs |
|
|
172
|
+
| `mistral-conversations` | Mistral Conversations APIs |
|
|
173
|
+
| `google-generative-ai` | Google Generative AI APIs |
|
|
174
|
+
| `google-vertex` | Google Vertex AI APIs |
|
|
175
|
+
| `bedrock-converse-stream` | Amazon Bedrock Converse Stream APIs |
|
|
176
|
+
| `pi-messages` | Pi Messages APIs |
|
|
222
177
|
|
|
223
|
-
|
|
224
|
-
|-----|---------|
|
|
225
|
-
| `anthropic-messages` | Anthropic Claude API and compatibles |
|
|
226
|
-
| `openai-completions` | OpenAI Chat Completions API and compatibles |
|
|
227
|
-
| `openai-responses` | OpenAI Responses API |
|
|
228
|
-
| `azure-openai-responses` | Azure OpenAI Responses API |
|
|
229
|
-
| `openai-codex-responses` | OpenAI Codex Responses API |
|
|
230
|
-
| `mistral-conversations` | Mistral SDK Conversations/Chat streaming |
|
|
231
|
-
| `google-generative-ai` | Google Generative AI API |
|
|
232
|
-
| `google-vertex` | Google Vertex AI API |
|
|
233
|
-
| `bedrock-converse-stream` | Amazon Bedrock Converse API |
|
|
178
|
+
A configuration-form model requires `id`, `name`, `reasoning`, `input`, `cost`, `contextWindow`, and `maxTokens`. It may also set `api`, `baseUrl`, `headers`, `thinkingLevelMap`, and `compat`. `cost` rates are per million tokens. `thinkingLevelMap` maps Pi's `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max` levels; `null` hides an unsupported level.
|
|
234
179
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
models: [{
|
|
239
|
-
id: "custom-model",
|
|
240
|
-
// ...
|
|
241
|
-
reasoning: true,
|
|
242
|
-
thinkingLevelMap: { // map pi levels to provider values; null hides unsupported levels
|
|
243
|
-
minimal: null,
|
|
244
|
-
low: null,
|
|
245
|
-
medium: null,
|
|
246
|
-
high: "default",
|
|
247
|
-
xhigh: null,
|
|
248
|
-
max: "max"
|
|
249
|
-
},
|
|
250
|
-
compat: {
|
|
251
|
-
supportsDeveloperRole: false, // use "system" instead of "developer"
|
|
252
|
-
supportsReasoningEffort: true,
|
|
253
|
-
maxTokensField: "max_tokens", // instead of "max_completion_tokens"
|
|
254
|
-
requiresToolResultName: true, // tool results need name field
|
|
255
|
-
thinkingFormat: "qwen", // top-level enable_thinking: true
|
|
256
|
-
cacheControlFormat: "anthropic" // Anthropic-style cache_control markers
|
|
257
|
-
}
|
|
258
|
-
}]
|
|
259
|
-
```
|
|
180
|
+
Keep endpoint-specific compatibility settings in `compat` rather than reimplementing a standard protocol. The full model fields, thinking maps, cost tiers, and Anthropic/OpenAI compatibility options are documented in [Custom Models](models.md#model-configuration), [Anthropic Messages Compatibility](models.md#anthropic-messages-compatibility), and [OpenAI Compatibility](models.md#openai-compatibility).
|
|
260
181
|
|
|
261
|
-
|
|
262
|
-
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|
|
182
|
+
## Authentication, Headers, and Request Hooks
|
|
263
183
|
|
|
264
|
-
|
|
184
|
+
### API Keys and Registered Headers
|
|
265
185
|
|
|
266
|
-
|
|
267
|
-
> Use `mistral-conversations` for native Mistral models.
|
|
268
|
-
> If you intentionally route Mistral-compatible/custom endpoints through `openai-completions`, set `compat` flags explicitly as needed.
|
|
186
|
+
For a new config-form provider, supply `apiKey` unless it has OAuth or a complete native provider supplies auth. `apiKey`, provider `headers`, and model `headers` use the same value syntax as `models.json`:
|
|
269
187
|
|
|
270
|
-
|
|
188
|
+
- `$NAME` and `${NAME}` interpolate environment variables.
|
|
189
|
+
- A value beginning with `!` runs a command for the whole value.
|
|
190
|
+
- `$$` and `$!` emit literal `$` and `!`.
|
|
191
|
+
- Other text, including uppercase text, is literal.
|
|
271
192
|
|
|
272
|
-
|
|
193
|
+
Values are resolved at request time. See [Value Resolution](models.md#value-resolution) for command behavior and security considerations.
|
|
273
194
|
|
|
274
195
|
```typescript
|
|
275
|
-
pi.registerProvider("
|
|
276
|
-
baseUrl: "https://api.example.com",
|
|
277
|
-
apiKey: "$
|
|
278
|
-
authHeader: true, // adds Authorization: Bearer header
|
|
196
|
+
pi.registerProvider("company-api", {
|
|
197
|
+
baseUrl: "https://api.example.com/v1",
|
|
198
|
+
apiKey: "$COMPANY_API_KEY",
|
|
279
199
|
api: "openai-completions",
|
|
280
|
-
|
|
200
|
+
headers: {
|
|
201
|
+
"X-Tenant": "$COMPANY_TENANT",
|
|
202
|
+
"X-Proxy-Token": "!company-token print",
|
|
203
|
+
},
|
|
204
|
+
authHeader: true, // Adds Authorization: Bearer <resolved API key>.
|
|
205
|
+
models: [/* ... */],
|
|
281
206
|
});
|
|
282
207
|
```
|
|
283
208
|
|
|
284
|
-
|
|
209
|
+
`authHeader` is useful for a custom API that expects a bearer token but does not create that header itself. Standard Pi AI API implementations already apply their own authentication. A custom stream receives the resolved key as `options.apiKey` and the final headers as `options.headers`; forward both as appropriate for its protocol.
|
|
285
210
|
|
|
286
|
-
|
|
211
|
+
### OAuth
|
|
287
212
|
|
|
288
|
-
|
|
213
|
+
The configuration form adapts the extension OAuth callbacks to Pi AI's provider auth and exposes the provider through `/login`. This callback shape is specific to `ProviderConfig.oauth`: a complete native `Provider` instead supplies `auth.oauth.login(interaction)`, `refresh(credential, signal?)`, and `toAuth(credential)`. Do not use the configuration form's `refreshToken` or `getApiKey` names on native `auth.oauth`.
|
|
289
214
|
|
|
290
215
|
```typescript
|
|
216
|
+
import type { ExtensionAPI } from "@astralyn/pi";
|
|
291
217
|
import type { OAuthCredentials, OAuthLoginCallbacks } from "@earendil-works/pi-ai";
|
|
292
218
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
async login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {
|
|
301
|
-
const method = await callbacks.onSelect({
|
|
302
|
-
message: "Select login method:",
|
|
303
|
-
options: [
|
|
304
|
-
{ id: "browser", label: "Browser OAuth" },
|
|
305
|
-
{ id: "device", label: "Device code" }
|
|
306
|
-
]
|
|
307
|
-
});
|
|
308
|
-
if (!method) throw new Error("Login cancelled");
|
|
309
|
-
|
|
310
|
-
let code: string;
|
|
311
|
-
if (method === "device") {
|
|
312
|
-
callbacks.onDeviceCode({
|
|
313
|
-
userCode: "ABCD-1234",
|
|
314
|
-
verificationUri: "https://sso.corp.com/device",
|
|
315
|
-
intervalSeconds: 5,
|
|
316
|
-
expiresInSeconds: 900
|
|
317
|
-
});
|
|
318
|
-
code = await pollDeviceCodeUntilComplete();
|
|
319
|
-
} else {
|
|
320
|
-
callbacks.onAuth({ url: "https://sso.corp.com/authorize?..." });
|
|
321
|
-
code = await callbacks.onPrompt({ message: "Enter SSO code:" });
|
|
322
|
-
}
|
|
219
|
+
async function login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {
|
|
220
|
+
callbacks.onAuth({
|
|
221
|
+
url: "https://sso.example.com/authorize?...",
|
|
222
|
+
instructions: "Sign in, then paste the authorization code.",
|
|
223
|
+
});
|
|
224
|
+
const code = await callbacks.onPrompt({ message: "Authorization code" });
|
|
323
225
|
|
|
324
|
-
|
|
325
|
-
|
|
226
|
+
// Exchange the code with this provider's OAuth server. Pass callbacks.signal
|
|
227
|
+
// to provider requests when supported.
|
|
228
|
+
return exchangeAuthorizationCode(code, callbacks.signal);
|
|
229
|
+
}
|
|
326
230
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
expires: Date.now() + tokens.expiresIn * 1000
|
|
331
|
-
};
|
|
332
|
-
},
|
|
231
|
+
async function refreshToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials> {
|
|
232
|
+
return refreshAuthorization(credentials.refresh, signal);
|
|
233
|
+
}
|
|
333
234
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
235
|
+
export default function (pi: ExtensionAPI) {
|
|
236
|
+
pi.registerProvider("company-api", {
|
|
237
|
+
baseUrl: "https://api.example.com/v1",
|
|
238
|
+
api: "openai-responses",
|
|
239
|
+
models: [/* ... */],
|
|
240
|
+
oauth: {
|
|
241
|
+
name: "Company AI",
|
|
242
|
+
login,
|
|
243
|
+
refreshToken,
|
|
244
|
+
getApiKey: (credentials) => credentials.access,
|
|
341
245
|
},
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return credentials.access;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
});
|
|
246
|
+
});
|
|
247
|
+
}
|
|
348
248
|
```
|
|
349
249
|
|
|
350
|
-
|
|
250
|
+
Return credentials with `refresh`, `access`, and `expires` (a millisecond timestamp). Pi adds the stored OAuth credential's internal type tag; extension callbacks return `OAuthCredentials`, not a credential with `type: "oauth"`.
|
|
351
251
|
|
|
352
|
-
|
|
252
|
+
`OAuthLoginCallbacks` provides these UI-neutral operations:
|
|
353
253
|
|
|
354
|
-
|
|
254
|
+
- `onAuth({ url, instructions? })` opens/displays an authorization URL.
|
|
255
|
+
- `onDeviceCode({ userCode, verificationUri, intervalSeconds?, expiresInSeconds? })` displays a device flow code.
|
|
256
|
+
- `onPrompt({ message, placeholder?, allowEmpty? })` asks for text and resolves to the entered string.
|
|
257
|
+
- `onSelect({ message, options: [{ id, label }] })` resolves to an option ID or `undefined`.
|
|
258
|
+
- `onManualCodeInput?.()` optionally requests a manually pasted code.
|
|
259
|
+
- `onProgress?.(message)` reports transient progress, and `signal` is an optional `AbortSignal` for the login flow.
|
|
355
260
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
// Show device code (for device authorization flow)
|
|
362
|
-
onDeviceCode(params: {
|
|
363
|
-
userCode: string;
|
|
364
|
-
verificationUri: string;
|
|
365
|
-
intervalSeconds?: number;
|
|
366
|
-
expiresInSeconds?: number;
|
|
367
|
-
}): void;
|
|
368
|
-
|
|
369
|
-
// Show transient progress
|
|
370
|
-
onProgress?(message: string): void;
|
|
371
|
-
|
|
372
|
-
// Prompt user for input (for manual token entry)
|
|
373
|
-
onPrompt(params: { message: string }): Promise<string>;
|
|
374
|
-
|
|
375
|
-
// Show an interactive selector, e.g. to choose browser OAuth vs device code
|
|
376
|
-
onSelect(params: {
|
|
377
|
-
message: string;
|
|
378
|
-
options: { id: string; label: string }[];
|
|
379
|
-
}): Promise<string | undefined>;
|
|
380
|
-
}
|
|
381
|
-
```
|
|
261
|
+
Do not use `usesCallbackServer`; it is deprecated and ignored by the canonical OAuth flow. Keep OAuth tokens out of logs and error messages.
|
|
262
|
+
|
|
263
|
+
### Payload and Header Hooks
|
|
264
|
+
|
|
265
|
+
For a standard Pi AI API stream, Pi's extension hooks work automatically:
|
|
382
266
|
|
|
383
|
-
|
|
267
|
+
- `before_provider_headers` mutates the fully assembled headers. A `null` header value removes that header.
|
|
268
|
+
- `before_provider_request` inspects or replaces the serialized payload.
|
|
269
|
+
- `after_provider_response` sees the status and normalized headers before the response body is consumed.
|
|
384
270
|
|
|
385
|
-
|
|
271
|
+
See [provider request events](extensions.md#before_provider_headers) for ordering and examples. `onPayload`, `onResponse`, and `transformHeaders` are **not** `ProviderConfig` fields. Pi passes the first two to a stream as `SimpleStreamOptions`; header transformation has already happened before a custom `streamSimple` is called.
|
|
272
|
+
|
|
273
|
+
A custom stream that sends HTTP itself must call `options.onPayload` and `options.onResponse` to preserve the payload/response hooks. It must also use the supplied headers. For example, immediately before consuming a custom HTTP response:
|
|
386
274
|
|
|
387
275
|
```typescript
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
276
|
+
const payload = { model: model.id, stream: true };
|
|
277
|
+
const replacement = await options?.onPayload?.(payload, model);
|
|
278
|
+
const requestPayload = replacement === undefined ? payload : replacement;
|
|
279
|
+
|
|
280
|
+
const headers = Object.fromEntries(
|
|
281
|
+
Object.entries(options?.headers ?? {}).filter((entry): entry is [string, string] => entry[1] !== null),
|
|
282
|
+
);
|
|
283
|
+
const response = await fetch(`${model.baseUrl}/stream`, {
|
|
284
|
+
method: "POST",
|
|
285
|
+
headers: { "content-type": "application/json", ...headers },
|
|
286
|
+
body: JSON.stringify(requestPayload),
|
|
287
|
+
signal: options?.signal,
|
|
288
|
+
});
|
|
289
|
+
await options?.onResponse?.(
|
|
290
|
+
{ status: response.status, headers: Object.fromEntries(response.headers.entries()) },
|
|
291
|
+
model,
|
|
292
|
+
);
|
|
293
|
+
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
|
|
393
294
|
```
|
|
394
295
|
|
|
395
|
-
|
|
296
|
+
When a custom stream delegates to a public Pi AI API stream, pass through `options` (and merge rather than discard `options.headers`) so those hooks continue to run. The GitLab Duo example follows this pattern.
|
|
396
297
|
|
|
397
|
-
|
|
298
|
+
## Custom Streaming APIs
|
|
398
299
|
|
|
399
|
-
|
|
400
|
-
- [anthropic.ts](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/providers/anthropic.ts) - Anthropic Messages API
|
|
401
|
-
- [mistral.ts](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/providers/mistral.ts) - Mistral Conversations API
|
|
402
|
-
- [openai-completions.ts](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/providers/openai-completions.ts) - OpenAI Chat Completions
|
|
403
|
-
- [openai-responses.ts](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/providers/openai-responses.ts) - OpenAI Responses API
|
|
404
|
-
- [google.ts](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/providers/google.ts) - Google Generative AI
|
|
405
|
-
- [amazon-bedrock.ts](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/providers/amazon-bedrock.ts) - AWS Bedrock
|
|
300
|
+
Implement `streamSimple` only for a protocol that cannot use a built-in API tag or a public Pi AI API stream. The custom Anthropic example implements the event protocol directly; the GitLab Duo example shows the preferred delegation approach when an endpoint is still Anthropic- or OpenAI-compatible.
|
|
406
301
|
|
|
407
|
-
### Stream
|
|
302
|
+
### Stream Contract
|
|
408
303
|
|
|
409
|
-
|
|
304
|
+
The configuration-form handler signature is exactly:
|
|
410
305
|
|
|
411
306
|
```typescript
|
|
412
307
|
import {
|
|
308
|
+
type Api,
|
|
413
309
|
type AssistantMessage,
|
|
414
310
|
type AssistantMessageEventStream,
|
|
311
|
+
calculateCost,
|
|
415
312
|
type Context,
|
|
313
|
+
createAssistantMessageEventStream,
|
|
416
314
|
type Model,
|
|
417
315
|
type SimpleStreamOptions,
|
|
418
|
-
calculateCost,
|
|
419
|
-
createAssistantMessageEventStream,
|
|
420
316
|
} from "@earendil-works/pi-ai";
|
|
421
317
|
|
|
422
318
|
function streamMyProvider(
|
|
423
|
-
model: Model<
|
|
319
|
+
model: Model<Api>,
|
|
424
320
|
context: Context,
|
|
425
|
-
options?: SimpleStreamOptions
|
|
321
|
+
options?: SimpleStreamOptions,
|
|
426
322
|
): AssistantMessageEventStream {
|
|
427
323
|
const stream = createAssistantMessageEventStream();
|
|
428
324
|
|
|
429
|
-
(async () => {
|
|
430
|
-
// Initialize output message
|
|
325
|
+
void (async () => {
|
|
431
326
|
const output: AssistantMessage = {
|
|
432
327
|
role: "assistant",
|
|
433
328
|
content: [],
|
|
@@ -442,28 +337,51 @@ function streamMyProvider(
|
|
|
442
337
|
totalTokens: 0,
|
|
443
338
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
444
339
|
},
|
|
445
|
-
stopReason: "
|
|
340
|
+
stopReason: "pending",
|
|
446
341
|
timestamp: Date.now(),
|
|
447
342
|
};
|
|
448
343
|
|
|
449
344
|
try {
|
|
450
|
-
// Push start event
|
|
451
345
|
stream.push({ type: "start", partial: output });
|
|
452
346
|
|
|
453
|
-
//
|
|
454
|
-
|
|
347
|
+
// Send the request, consume the provider stream, and update output.
|
|
348
|
+
const contentIndex = output.content.length;
|
|
349
|
+
output.content.push({ type: "text", text: "" });
|
|
350
|
+
stream.push({ type: "text_start", contentIndex, partial: output });
|
|
351
|
+
|
|
352
|
+
// For each provider text delta:
|
|
353
|
+
const delta = "...";
|
|
354
|
+
const block = output.content[contentIndex];
|
|
355
|
+
if (block.type === "text") {
|
|
356
|
+
block.text += delta;
|
|
357
|
+
stream.push({ type: "text_delta", contentIndex, delta, partial: output });
|
|
358
|
+
}
|
|
455
359
|
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
type: "
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
360
|
+
// After the provider completes this block:
|
|
361
|
+
if (block.type === "text") {
|
|
362
|
+
stream.push({ type: "text_end", contentIndex, content: block.text, partial: output });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Update usage whenever the provider reports it, then recalculate cost.
|
|
366
|
+
output.usage.totalTokens =
|
|
367
|
+
output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
368
|
+
calculateCost(model, output.usage);
|
|
369
|
+
|
|
370
|
+
// The omitted provider loop must map its terminal event by replacing
|
|
371
|
+
// "pending" with "stop", "length", "toolUse", "error", or "aborted".
|
|
372
|
+
if (output.stopReason === "pending") {
|
|
373
|
+
throw new Error("Provider stream ended without a stop reason");
|
|
374
|
+
}
|
|
375
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
376
|
+
throw new Error(output.errorMessage || "An unknown error occurred");
|
|
377
|
+
}
|
|
378
|
+
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
463
379
|
} catch (error) {
|
|
464
|
-
|
|
380
|
+
const reason = options?.signal?.aborted ? "aborted" : "error";
|
|
381
|
+
output.stopReason = reason;
|
|
465
382
|
output.errorMessage = error instanceof Error ? error.message : String(error);
|
|
466
|
-
stream.push({ type: "error", reason
|
|
383
|
+
stream.push({ type: "error", reason, error: output });
|
|
384
|
+
} finally {
|
|
467
385
|
stream.end();
|
|
468
386
|
}
|
|
469
387
|
})();
|
|
@@ -472,122 +390,68 @@ function streamMyProvider(
|
|
|
472
390
|
}
|
|
473
391
|
```
|
|
474
392
|
|
|
475
|
-
|
|
393
|
+
Emit `start` before partial content events, update `output.content` before each event's `partial`, and end exactly once after either terminal event. The terminal event shapes are deliberately narrow: `done.reason` is `"stop" | "length" | "toolUse"`; `error.reason` is `"error" | "aborted"`. Map the upstream stop reason to one of those values and keep it equal to `output.stopReason`.
|
|
476
394
|
|
|
477
|
-
|
|
395
|
+
Use the index of each block in `output.content` as `contentIndex` and emit matching start, delta, and end events:
|
|
478
396
|
|
|
479
|
-
|
|
397
|
+
| Block | Events | Final content field |
|
|
398
|
+
| --- | --- | --- |
|
|
399
|
+
| Text | `text_start`, `text_delta`, `text_end` | `text` |
|
|
400
|
+
| Thinking | `thinking_start`, `thinking_delta`, `thinking_end` | `thinking` |
|
|
401
|
+
| Tool call | `toolcall_start`, `toolcall_delta`, `toolcall_end` | `ToolCall` |
|
|
480
402
|
|
|
481
|
-
|
|
482
|
-
- `{ type: "text_start", contentIndex, partial }` - Text block started
|
|
483
|
-
- `{ type: "text_delta", contentIndex, delta, partial }` - Text chunk
|
|
484
|
-
- `{ type: "text_end", contentIndex, content, partial }` - Text block ended
|
|
485
|
-
- `{ type: "thinking_start", contentIndex, partial }` - Thinking started
|
|
486
|
-
- `{ type: "thinking_delta", contentIndex, delta, partial }` - Thinking chunk
|
|
487
|
-
- `{ type: "thinking_end", contentIndex, content, partial }` - Thinking ended
|
|
488
|
-
- `{ type: "toolcall_start", contentIndex, partial }` - Tool call started
|
|
489
|
-
- `{ type: "toolcall_delta", contentIndex, delta, partial }` - Tool call JSON chunk
|
|
490
|
-
- `{ type: "toolcall_end", contentIndex, toolCall, partial }` - Tool call ended
|
|
403
|
+
Tool calls need an `id`, `name`, and parsed `arguments` object in the final `toolcall_end`. Accumulate streamed JSON before parsing it. For replayable thinking, preserve any provider signature in the block's `thinkingSignature` field. Populate `usage` with provider-reported values (`input`, `output`, `cacheRead`, `cacheWrite`, and optional `cacheWrite1h`/`reasoning`) before calling `calculateCost()`.
|
|
491
404
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
The `partial` field in each event contains the current `AssistantMessage` state. Update `output.content` as you receive data, then include `output` as the `partial`.
|
|
495
|
-
|
|
496
|
-
### Content Blocks
|
|
497
|
-
|
|
498
|
-
Add content blocks to `output.content` as they arrive:
|
|
405
|
+
Register the handler with a matching custom API tag:
|
|
499
406
|
|
|
500
407
|
```typescript
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
block.text += delta;
|
|
509
|
-
stream.push({ type: "text_delta", contentIndex, delta, partial: output });
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// When block completes
|
|
513
|
-
stream.push({ type: "text_end", contentIndex, content: block.text, partial: output });
|
|
408
|
+
pi.registerProvider("my-provider", {
|
|
409
|
+
baseUrl: "https://api.example.com",
|
|
410
|
+
apiKey: "$MY_PROVIDER_API_KEY",
|
|
411
|
+
api: "my-provider-stream",
|
|
412
|
+
models: [/* models whose effective api is my-provider-stream */],
|
|
413
|
+
streamSimple: streamMyProvider,
|
|
414
|
+
});
|
|
514
415
|
```
|
|
515
416
|
|
|
516
|
-
###
|
|
417
|
+
### Forwarding Hooks from a Custom Stream
|
|
517
418
|
|
|
518
|
-
|
|
419
|
+
`SimpleStreamOptions` also carries cancellation, the resolved API key, reasoning level, thinking budgets, cache/session settings, retry/timeout options, headers, and the payload/response callbacks. Honor the options your protocol supports, especially `signal`, `apiKey`, and `headers`. Do not silently replace the supplied options when delegating:
|
|
519
420
|
|
|
520
421
|
```typescript
|
|
521
|
-
|
|
522
|
-
output.content.push({
|
|
523
|
-
type: "toolCall",
|
|
524
|
-
id: toolCallId,
|
|
525
|
-
name: toolName,
|
|
526
|
-
arguments: {}
|
|
527
|
-
});
|
|
528
|
-
stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
|
|
529
|
-
|
|
530
|
-
// Accumulate JSON
|
|
531
|
-
let partialJson = "";
|
|
532
|
-
partialJson += jsonDelta;
|
|
533
|
-
try {
|
|
534
|
-
block.arguments = JSON.parse(partialJson);
|
|
535
|
-
} catch {}
|
|
536
|
-
stream.push({ type: "toolcall_delta", contentIndex, delta: jsonDelta, partial: output });
|
|
537
|
-
|
|
538
|
-
// Complete
|
|
539
|
-
stream.push({
|
|
540
|
-
type: "toolcall_end",
|
|
541
|
-
contentIndex,
|
|
542
|
-
toolCall: { type: "toolCall", id, name, arguments: block.arguments },
|
|
543
|
-
partial: output
|
|
544
|
-
});
|
|
545
|
-
```
|
|
422
|
+
import { openAIResponsesApi } from "@earendil-works/pi-ai/compat";
|
|
546
423
|
|
|
547
|
-
|
|
424
|
+
const responsesApi = openAIResponsesApi();
|
|
548
425
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
output.usage.cacheRead = response.usage.cache_read_tokens ?? 0;
|
|
555
|
-
output.usage.cacheWrite = response.usage.cache_write_tokens ?? 0;
|
|
556
|
-
output.usage.totalTokens = output.usage.input + output.usage.output +
|
|
557
|
-
output.usage.cacheRead + output.usage.cacheWrite;
|
|
558
|
-
calculateCost(model, output.usage);
|
|
426
|
+
// Inside a custom handler, after adapting the model/API as necessary:
|
|
427
|
+
return responsesApi.streamSimple(adaptedModel, context, {
|
|
428
|
+
...options,
|
|
429
|
+
headers: { ...options?.headers, "X-Relay": "company" },
|
|
430
|
+
});
|
|
559
431
|
```
|
|
560
432
|
|
|
561
|
-
|
|
433
|
+
This is a public API. It avoids depending on pi-ai implementation files and preserves Pi's request hooks.
|
|
562
434
|
|
|
563
|
-
|
|
435
|
+
## Context Overflow Recovery
|
|
564
436
|
|
|
565
|
-
|
|
437
|
+
Pi uses the public `isContextOverflow(message, contextWindow)` helper when deciding whether to auto-compact. It recognizes its built-in error patterns and also detects a few silent-overflow usage shapes. A custom stream should emit `stopReason: "error"` with the provider's real error in `errorMessage`.
|
|
566
438
|
|
|
567
|
-
|
|
568
|
-
- `errorMessage` matches one of pi's known overflow patterns (see [`packages/ai/src/utils/overflow.ts`](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/utils/overflow.ts))
|
|
569
|
-
|
|
570
|
-
If your provider returns overflow errors with a message pi does not recognize, normalize the error from the same extension that registers the provider. Use a `message_end` handler to rewrite the assistant message so its `errorMessage` starts with a phrase pi recognizes. The generic fallback `context_length_exceeded` is the safest choice.
|
|
439
|
+
If an upstream uses an unrecognized overflow message, normalize only that provider's known overflow error. The generic `context_length_exceeded` prefix is recognized. A `message_end` replacement occurs before Pi's overflow recovery check:
|
|
571
440
|
|
|
572
441
|
```typescript
|
|
573
|
-
|
|
442
|
+
import type { ExtensionAPI } from "@astralyn/pi";
|
|
574
443
|
|
|
575
|
-
|
|
576
|
-
pi.registerProvider("my-provider", { /* ... */ });
|
|
444
|
+
const PROVIDER_OVERFLOW = /request exceeds the acme input limit/i;
|
|
577
445
|
|
|
578
|
-
|
|
446
|
+
export default function (pi: ExtensionAPI) {
|
|
447
|
+
pi.on("message_end", (event) => {
|
|
579
448
|
const message = event.message;
|
|
580
|
-
if (message.role !== "assistant") return;
|
|
449
|
+
if (message.role !== "assistant" || message.provider !== "my-provider") return;
|
|
581
450
|
if (message.stopReason !== "error") return;
|
|
582
|
-
if (
|
|
583
|
-
message.provider !== "my-provider" &&
|
|
584
|
-
ctx.model?.provider !== "my-provider"
|
|
585
|
-
)
|
|
586
|
-
return;
|
|
587
451
|
|
|
588
452
|
const errorMessage = message.errorMessage ?? "";
|
|
589
453
|
if (errorMessage.includes("context_length_exceeded")) return;
|
|
590
|
-
if (!
|
|
454
|
+
if (!PROVIDER_OVERFLOW.test(errorMessage)) return;
|
|
591
455
|
|
|
592
456
|
return {
|
|
593
457
|
message: {
|
|
@@ -599,52 +463,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
599
463
|
}
|
|
600
464
|
```
|
|
601
465
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
1. Detect the overflow from `errorMessage`.
|
|
605
|
-
2. Drop the failed assistant message from live context.
|
|
606
|
-
3. Run compaction.
|
|
607
|
-
4. Retry the request once.
|
|
608
|
-
|
|
609
|
-
Guard the rewrite carefully:
|
|
610
|
-
|
|
611
|
-
- Scope it to your provider (`message.provider` and `ctx.model?.provider`) so unrelated errors from other providers are untouched.
|
|
612
|
-
- Match a provider-specific pattern, not pi's generic overflow patterns. Rewriting rate-limit or throttling errors (`rate limit`, `too many requests`) would falsely trigger compaction instead of pi's normal retry-with-backoff path.
|
|
613
|
-
- Skip when `errorMessage` already includes `context_length_exceeded` so the handler is idempotent.
|
|
466
|
+
Do not rewrite rate limits, authentication failures, or generic server errors as overflows. With auto-compaction enabled, Pi removes the failed assistant message from live context, compacts, and retries once. Test the normalized message with the public `isContextOverflow()` helper and the model's configured `contextWindow`.
|
|
614
467
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
Register your stream function:
|
|
618
|
-
|
|
619
|
-
```typescript
|
|
620
|
-
pi.registerProvider("my-provider", {
|
|
621
|
-
baseUrl: "https://api.example.com",
|
|
622
|
-
apiKey: "$MY_API_KEY",
|
|
623
|
-
api: "my-custom-api",
|
|
624
|
-
models: [...],
|
|
625
|
-
streamSimple: streamMyProvider
|
|
626
|
-
});
|
|
627
|
-
```
|
|
468
|
+
## Testing
|
|
628
469
|
|
|
629
|
-
|
|
470
|
+
Use the local examples as references rather than copying pi-ai's private implementation or test sources. Test a custom stream directly by iterating its public `AssistantMessageEventStream`, then awaiting `stream.result()` for the final message.
|
|
630
471
|
|
|
631
|
-
|
|
472
|
+
At minimum, cover:
|
|
632
473
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
| `context-overflow.test.ts` | Context window limits |
|
|
640
|
-
| `image-limits.test.ts` | Image input handling |
|
|
641
|
-
| `unicode-surrogate.test.ts` | Unicode edge cases |
|
|
642
|
-
| `tool-call-without-result.test.ts` | Tool call edge cases |
|
|
643
|
-
| `image-tool-result.test.ts` | Images in tool results |
|
|
644
|
-
| `total-tokens.test.ts` | Total token calculation |
|
|
645
|
-
| `cross-provider-handoff.test.ts` | Context handoff between providers |
|
|
474
|
+
- registration and discovery with `pi -e path/to/extension --list-models`;
|
|
475
|
+
- normal text, thinking, and tool-call event ordering, including fragmented tool JSON;
|
|
476
|
+
- final usage/cost values, empty responses, provider errors, and aborts;
|
|
477
|
+
- resolved API keys and headers, plus payload/response hook forwarding for a stream that makes HTTP itself;
|
|
478
|
+
- the configured context window and overflow normalization with `isContextOverflow(message, model.contextWindow)`;
|
|
479
|
+
- one interactive request with the selected provider, including a tool call if the provider claims tool support.
|
|
646
480
|
|
|
647
|
-
|
|
481
|
+
The two example extensions above cover the two main test seams: direct custom event production and delegation to Pi AI's public streaming APIs.
|
|
648
482
|
|
|
649
483
|
## Config Reference
|
|
650
484
|
|
|
@@ -682,7 +516,7 @@ interface ProviderConfig {
|
|
|
682
516
|
oauth?: {
|
|
683
517
|
name: string;
|
|
684
518
|
login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
685
|
-
refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials>;
|
|
519
|
+
refreshToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials>;
|
|
686
520
|
getApiKey(credentials: OAuthCredentials): string;
|
|
687
521
|
};
|
|
688
522
|
}
|
|
@@ -737,6 +571,7 @@ interface ProviderModelConfig {
|
|
|
737
571
|
supportsDeveloperRole?: boolean;
|
|
738
572
|
supportsReasoningEffort?: boolean;
|
|
739
573
|
supportsUsageInStreaming?: boolean;
|
|
574
|
+
supportsFinishReason?: boolean;
|
|
740
575
|
supportsStrictMode?: boolean;
|
|
741
576
|
supportsOpenAIGrammarTools?: boolean; // openai-completions/openai-responses; false falls back to normal function tools
|
|
742
577
|
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
@@ -744,8 +579,9 @@ interface ProviderModelConfig {
|
|
|
744
579
|
requiresAssistantAfterToolResult?: boolean;
|
|
745
580
|
requiresThinkingAsText?: boolean;
|
|
746
581
|
requiresReasoningContentOnAssistantMessages?: boolean;
|
|
747
|
-
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "chat-template" | "qwen-chat-template" | "string-thinking" | "ant-ling";
|
|
582
|
+
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "baseten" | "zai" | "qwen" | "chat-template" | "qwen-chat-template" | "string-thinking" | "ant-ling";
|
|
748
583
|
chatTemplateKwargs?: Record<string, string | number | boolean | null | { "$var": "thinking.enabled" | "thinking.effort"; omitWhenOff?: boolean }>;
|
|
584
|
+
chatTemplateArgs?: Record<string, string | number | boolean | null | { "$var": "thinking.enabled" | "thinking.effort"; omitWhenOff?: boolean }>;
|
|
749
585
|
cacheControlFormat?: "anthropic";
|
|
750
586
|
sessionAffinityFormat?: "openai" | "openai-nosession" | "openrouter";
|
|
751
587
|
sendSessionAffinityHeaders?: boolean;
|
|
@@ -762,5 +598,5 @@ interface ProviderModelConfig {
|
|
|
762
598
|
}
|
|
763
599
|
```
|
|
764
600
|
|
|
765
|
-
`openrouter` sends `reasoning: { effort }`. `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when enabled. `together` sends `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` is for DashScope-style top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`. Use `chat-template` for configurable `chat_template_kwargs`, for example DeepSeek V3.x behind vLLM with `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }`.
|
|
601
|
+
`openrouter` sends `reasoning: { effort }`. `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when enabled. `together` sends `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` is for DashScope-style top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`. Use `chat-template` for configurable `chat_template_kwargs`, for example DeepSeek V3.x behind vLLM with `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }`. Use `thinkingFormat: "baseten"` with `chatTemplateArgs` when the provider expects toggle values under `chat_template_args` and optionally supports top-level `reasoning_effort`.
|
|
766
602
|
`cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|