@astralyn/pi 0.99.0 → 1.0.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 +39 -3
- package/dist/bundle/chunks/anthropic-messages-CG2BSDQS.js +6 -0
- package/dist/bundle/chunks/anthropic.js +2 -2
- package/dist/bundle/chunks/{azure-openai-responses-RPBERDXD.js → azure-openai-responses-PBA4QKCM.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
- package/dist/bundle/chunks/{chunk-ABVRAYXT.js → chunk-6UFFVA7M.js} +2 -2
- package/dist/bundle/chunks/chunk-GIG5IHES.js +2 -0
- package/dist/bundle/chunks/{chunk-VW2P3X6P.js → chunk-HESRDUKO.js} +414 -666
- package/dist/bundle/chunks/{chunk-A576H74Y.js → chunk-PFZKRUMO.js} +1 -1
- package/dist/bundle/chunks/chunk-SGLYRVQL.js +2 -0
- package/dist/bundle/chunks/chunk-TRHTWM3C.js +2 -0
- package/dist/bundle/chunks/{chunk-DEWXBB6W.js → chunk-V66VGGOM.js} +1 -1
- package/dist/bundle/chunks/chunk-Z2RKSI3O.js +2 -0
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-ZYSAFXXL.js → cloudflare-workers-ai-system-one-YB7XPPP4.js} +1 -1
- package/dist/bundle/chunks/codemode-worker.js +67 -8
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-SDNQVVXA.js → google-generative-ai-V5ZM5MCL.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-LZXOLBIO.js → google-vertex-22THOFP5.js} +1 -1
- package/dist/bundle/chunks/{llama-cpp-classify-7IYGGPND.js → llama-cpp-classify-R7DQLTQN.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-VYKPSSAM.js → mistral-conversations-WHSCJJWP.js} +1 -1
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-HZ4VUDXD.js → openai-codex-responses-N7GDPBPP.js} +1 -1
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-SKDGF6OE.js → openai-completions-RGGQK5UW.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-FPML4SSG.js → openai-responses-3ZLD5JYI.js} +1 -1
- package/dist/bundle/chunks/{openrouter-images-5524IQHX.js → openrouter-images-YP3YVB54.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +1 -1
- package/dist/bundle/chunks/radius.js +1 -1
- package/dist/bundle/chunks/{typesafe-system-one-Z2CDLKEY.js → typesafe-system-one-RREJAKWB.js} +1 -1
- package/dist/bundle/chunks/virtual-modules-4RQ2L6W4.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +5 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -13
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +21 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +64 -11
- package/dist/core/agent-session.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 +13 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +51 -11
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +11 -3
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/mcp-servers.d.ts +34 -7
- package/dist/core/mcp-servers.d.ts.map +1 -1
- package/dist/core/mcp-servers.js +52 -11
- package/dist/core/mcp-servers.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +4 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts +6 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +22 -18
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/radius.d.ts +2 -0
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +2 -0
- package/dist/core/radius.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +4 -9
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +2 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/format.d.ts +7 -0
- package/dist/core/tasks/format.d.ts.map +1 -0
- package/dist/core/tasks/format.js +14 -0
- package/dist/core/tasks/format.js.map +1 -0
- package/dist/core/tasks/history.d.ts.map +1 -1
- package/dist/core/tasks/history.js +0 -19
- package/dist/core/tasks/history.js.map +1 -1
- package/dist/core/tasks/output.d.ts +8 -0
- package/dist/core/tasks/output.d.ts.map +1 -1
- package/dist/core/tasks/output.js +19 -0
- package/dist/core/tasks/output.js.map +1 -1
- package/dist/core/tasks/presentation.d.ts +1 -3
- package/dist/core/tasks/presentation.d.ts.map +1 -1
- package/dist/core/tasks/presentation.js +79 -166
- package/dist/core/tasks/presentation.js.map +1 -1
- package/dist/core/tasks/runtime.d.ts +16 -9
- package/dist/core/tasks/runtime.d.ts.map +1 -1
- package/dist/core/tasks/runtime.js +89 -106
- package/dist/core/tasks/runtime.js.map +1 -1
- package/dist/core/tasks/session.d.ts.map +1 -1
- package/dist/core/tasks/session.js +13 -4
- package/dist/core/tasks/session.js.map +1 -1
- package/dist/core/tasks/store.d.ts +20 -6
- package/dist/core/tasks/store.d.ts.map +1 -1
- package/dist/core/tasks/store.js +45 -18
- package/dist/core/tasks/store.js.map +1 -1
- package/dist/core/tasks/types.d.ts +14 -54
- package/dist/core/tasks/types.d.ts.map +1 -1
- package/dist/core/tasks/types.js +1 -5
- package/dist/core/tasks/types.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +11 -34
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/tools/shell-execution.d.ts +0 -1
- package/dist/core/tools/shell-execution.d.ts.map +1 -1
- package/dist/core/tools/shell-execution.js +3 -10
- package/dist/core/tools/shell-execution.js.map +1 -1
- package/dist/core/tools/shell-tool.d.ts.map +1 -1
- package/dist/core/tools/shell-tool.js +2 -4
- package/dist/core/tools/shell-tool.js.map +1 -1
- package/dist/core/tools/tasks/actions.d.ts +1 -1
- package/dist/core/tools/tasks/actions.d.ts.map +1 -1
- package/dist/core/tools/tasks/actions.js +26 -12
- package/dist/core/tools/tasks/actions.js.map +1 -1
- package/dist/core/tools/tasks/constants.d.ts +2 -6
- package/dist/core/tools/tasks/constants.d.ts.map +1 -1
- package/dist/core/tools/tasks/constants.js +2 -6
- package/dist/core/tools/tasks/constants.js.map +1 -1
- package/dist/core/tools/tasks/schema.d.ts +1 -1
- package/dist/core/tools/tasks/schema.d.ts.map +1 -1
- package/dist/core/tools/tasks/schema.js +8 -7
- package/dist/core/tools/tasks/schema.js.map +1 -1
- package/dist/core/tools/tasks/types.d.ts +8 -38
- package/dist/core/tools/tasks/types.d.ts.map +1 -1
- package/dist/core/tools/tasks/types.js +6 -11
- package/dist/core/tools/tasks/types.js.map +1 -1
- package/dist/core/virtual-models.d.ts +2 -0
- package/dist/core/virtual-models.d.ts.map +1 -1
- package/dist/core/virtual-models.js +19 -12
- package/dist/core/virtual-models.js.map +1 -1
- package/dist/extensions/btw/agent.d.ts +17 -8
- package/dist/extensions/btw/agent.d.ts.map +1 -1
- package/dist/extensions/btw/agent.js +74 -76
- package/dist/extensions/btw/agent.js.map +1 -1
- package/dist/extensions/btw/controller.d.ts +0 -1
- package/dist/extensions/btw/controller.d.ts.map +1 -1
- package/dist/extensions/btw/controller.js +26 -33
- package/dist/extensions/btw/controller.js.map +1 -1
- package/dist/extensions/btw/panel.d.ts +13 -14
- package/dist/extensions/btw/panel.d.ts.map +1 -1
- package/dist/extensions/btw/panel.js +38 -29
- package/dist/extensions/btw/panel.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +197 -51
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/renderer.d.ts.map +1 -1
- package/dist/extensions/codemode/renderer.js +43 -25
- package/dist/extensions/codemode/renderer.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +12 -11
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +73 -129
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/codemode/worker.d.ts +1 -1
- package/dist/extensions/codemode/worker.js +1 -1
- package/dist/extensions/codemode/worker.js.map +1 -1
- package/dist/extensions/deepwiki/schema.d.ts +1 -1
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +0 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/mcp/cli.d.ts.map +1 -1
- package/dist/extensions/mcp/cli.js +20 -5
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/config.d.ts +4 -2
- package/dist/extensions/mcp/config.d.ts.map +1 -1
- package/dist/extensions/mcp/config.js +14 -2
- package/dist/extensions/mcp/config.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts +32 -8
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +235 -61
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +10 -7
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +56 -31
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts +2 -0
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +16 -9
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +5 -4
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +33 -15
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/extensions/mcp/ui.d.ts.map +1 -1
- package/dist/extensions/mcp/ui.js +4 -2
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/extensions/provider/catalog.d.ts +8 -1
- package/dist/extensions/provider/catalog.d.ts.map +1 -1
- package/dist/extensions/provider/catalog.js +31 -0
- package/dist/extensions/provider/catalog.js.map +1 -1
- package/dist/extensions/provider/connection.d.ts +4 -1
- package/dist/extensions/provider/connection.d.ts.map +1 -1
- package/dist/extensions/provider/connection.js +1 -5
- package/dist/extensions/provider/connection.js.map +1 -1
- package/dist/extensions/provider/editing.d.ts +36 -0
- package/dist/extensions/provider/editing.d.ts.map +1 -0
- package/dist/extensions/provider/editing.js +99 -0
- package/dist/extensions/provider/editing.js.map +1 -0
- package/dist/extensions/provider/json-fields.d.ts +5 -0
- package/dist/extensions/provider/json-fields.d.ts.map +1 -0
- package/dist/extensions/provider/json-fields.js +31 -0
- package/dist/extensions/provider/json-fields.js.map +1 -0
- package/dist/extensions/provider/store.d.ts +1 -4
- package/dist/extensions/provider/store.d.ts.map +1 -1
- package/dist/extensions/provider/store.js +2 -30
- package/dist/extensions/provider/store.js.map +1 -1
- package/dist/extensions/provider/ui/builtin-data.d.ts +0 -2
- package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
- package/dist/extensions/provider/ui/builtin-data.js +14 -79
- package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
- package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
- package/dist/extensions/provider/ui/compat.js +6 -9
- package/dist/extensions/provider/ui/compat.js.map +1 -1
- package/dist/extensions/provider/ui/controls.d.ts +48 -0
- package/dist/extensions/provider/ui/controls.d.ts.map +1 -0
- package/dist/extensions/provider/ui/controls.js +108 -0
- package/dist/extensions/provider/ui/controls.js.map +1 -0
- package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
- package/dist/extensions/provider/ui/dictionary.js +6 -9
- package/dist/extensions/provider/ui/dictionary.js.map +1 -1
- package/dist/extensions/provider/ui/editor.d.ts +3 -3
- package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
- package/dist/extensions/provider/ui/editor.js +35 -140
- package/dist/extensions/provider/ui/editor.js.map +1 -1
- package/dist/extensions/provider/ui/fetch-models.d.ts +0 -3
- package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
- package/dist/extensions/provider/ui/fetch-models.js +49 -44
- package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
- package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
- package/dist/extensions/provider/ui/model-fields.js +11 -14
- package/dist/extensions/provider/ui/model-fields.js.map +1 -1
- package/dist/extensions/provider/ui/model-options.d.ts +4 -34
- package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
- package/dist/extensions/provider/ui/model-options.js +90 -271
- package/dist/extensions/provider/ui/model-options.js.map +1 -1
- package/dist/extensions/provider/ui/pane.d.ts +4 -18
- package/dist/extensions/provider/ui/pane.d.ts.map +1 -1
- package/dist/extensions/provider/ui/pane.js.map +1 -1
- package/dist/extensions/provider/ui/provider-fields.d.ts +2 -19
- package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
- package/dist/extensions/provider/ui/provider-fields.js +58 -171
- package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
- package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -1
- package/dist/extensions/provider/ui/thinking-map.js +6 -9
- package/dist/extensions/provider/ui/thinking-map.js.map +1 -1
- package/dist/extensions/question/detail-pane.d.ts +7 -2
- package/dist/extensions/question/detail-pane.d.ts.map +1 -1
- package/dist/extensions/question/detail-pane.js +16 -5
- package/dist/extensions/question/detail-pane.js.map +1 -1
- package/dist/extensions/question/dialog-view.d.ts +41 -0
- package/dist/extensions/question/dialog-view.d.ts.map +1 -0
- package/dist/extensions/question/dialog-view.js +329 -0
- package/dist/extensions/question/dialog-view.js.map +1 -0
- package/dist/extensions/question/dialog.d.ts +3 -3
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +220 -634
- 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 +2 -3
- package/dist/extensions/question/index.js.map +1 -1
- package/dist/extensions/question/render.d.ts.map +1 -1
- package/dist/extensions/question/render.js +22 -32
- 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 +56 -12
- package/dist/extensions/question/results.js.map +1 -1
- package/dist/extensions/question/schema.d.ts +21 -6
- 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 +9 -7
- package/dist/extensions/question/state.d.ts.map +1 -1
- package/dist/extensions/question/state.js +63 -54
- package/dist/extensions/question/state.js.map +1 -1
- package/dist/extensions/question/types.d.ts +41 -18
- package/dist/extensions/question/types.d.ts.map +1 -1
- package/dist/extensions/question/types.js.map +1 -1
- package/dist/extensions/statusline/index.d.ts +4 -0
- package/dist/extensions/statusline/index.d.ts.map +1 -1
- package/dist/extensions/statusline/index.js +18 -355
- package/dist/extensions/statusline/index.js.map +1 -1
- package/dist/extensions/statusline/render.d.ts +19 -0
- package/dist/extensions/statusline/render.d.ts.map +1 -0
- package/dist/extensions/statusline/render.js +163 -0
- package/dist/extensions/statusline/render.js.map +1 -0
- package/dist/extensions/statusline/usage.d.ts +12 -0
- package/dist/extensions/statusline/usage.d.ts.map +1 -0
- package/dist/extensions/statusline/usage.js +36 -0
- package/dist/extensions/statusline/usage.js.map +1 -0
- package/dist/extensions/tool-search/tool.d.ts +5 -4
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +7 -28
- package/dist/extensions/tool-search/tool.js.map +1 -1
- package/dist/extensions/web-search/execute.d.ts +1 -5
- package/dist/extensions/web-search/execute.d.ts.map +1 -1
- package/dist/extensions/web-search/execute.js +4 -9
- package/dist/extensions/web-search/execute.js.map +1 -1
- package/dist/extensions/web-search/format.d.ts +12 -3
- package/dist/extensions/web-search/format.d.ts.map +1 -1
- package/dist/extensions/web-search/format.js +33 -25
- package/dist/extensions/web-search/format.js.map +1 -1
- package/dist/extensions/web-search/index.d.ts.map +1 -1
- package/dist/extensions/web-search/index.js +6 -29
- package/dist/extensions/web-search/index.js.map +1 -1
- package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/deepseek.js +0 -1
- package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
- package/dist/extensions/web-search/providers/http.d.ts +1 -1
- package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/http.js.map +1 -1
- package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/minimax.js +0 -1
- package/dist/extensions/web-search/providers/minimax.js.map +1 -1
- package/dist/extensions/web-search/render.d.ts +7 -2
- package/dist/extensions/web-search/render.d.ts.map +1 -1
- package/dist/extensions/web-search/render.js +32 -4
- package/dist/extensions/web-search/render.js.map +1 -1
- package/dist/extensions/web-search/results.d.ts.map +1 -1
- package/dist/extensions/web-search/results.js +3 -8
- package/dist/extensions/web-search/results.js.map +1 -1
- package/dist/extensions/web-search/types.d.ts +4 -2
- package/dist/extensions/web-search/types.d.ts.map +1 -1
- package/dist/extensions/web-search/types.js.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +24 -21
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/pi-logo-animation.d.ts +68 -0
- package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.js +1076 -0
- package/dist/modes/interactive/components/pi-logo-animation.js.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +7 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +1 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js +12 -0
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +1 -0
- package/dist/modes/interactive/components/pi-logo.d.ts +7 -0
- package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -1
- package/dist/modes/interactive/components/pi-logo.js +13 -1
- package/dist/modes/interactive/components/pi-logo.js.map +1 -1
- package/dist/modes/interactive/components/radius-login-selector.d.ts +15 -0
- package/dist/modes/interactive/components/radius-login-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/radius-login-selector.js +83 -0
- package/dist/modes/interactive/components/radius-login-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -3
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -5
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-marker.d.ts +0 -2
- package/dist/modes/interactive/components/status-marker.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-marker.js +0 -4
- package/dist/modes/interactive/components/status-marker.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +5 -4
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +36 -6
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +167 -40
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tasks/completion-render.d.ts +1 -1
- package/dist/modes/interactive/tasks/completion-render.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/completion-render.js +28 -82
- package/dist/modes/interactive/tasks/completion-render.js.map +1 -1
- package/dist/modes/interactive/tasks/index.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/index.js +18 -13
- package/dist/modes/interactive/tasks/index.js.map +1 -1
- package/dist/modes/interactive/tasks/inspector.d.ts +35 -0
- package/dist/modes/interactive/tasks/inspector.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/inspector.js +93 -0
- package/dist/modes/interactive/tasks/inspector.js.map +1 -0
- package/dist/modes/interactive/tasks/layout.d.ts +40 -0
- package/dist/modes/interactive/tasks/layout.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/layout.js +212 -0
- package/dist/modes/interactive/tasks/layout.js.map +1 -0
- package/dist/modes/interactive/tasks/list.d.ts +21 -0
- package/dist/modes/interactive/tasks/list.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/list.js +96 -0
- package/dist/modes/interactive/tasks/list.js.map +1 -0
- package/dist/modes/interactive/tasks/manager.d.ts +29 -36
- package/dist/modes/interactive/tasks/manager.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/manager.js +315 -315
- package/dist/modes/interactive/tasks/manager.js.map +1 -1
- package/dist/modes/interactive/tasks/model.d.ts +21 -0
- package/dist/modes/interactive/tasks/model.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/model.js +41 -0
- package/dist/modes/interactive/tasks/model.js.map +1 -0
- package/dist/modes/interactive/tasks/render.d.ts +5 -19
- package/dist/modes/interactive/tasks/render.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/render.js +18 -102
- package/dist/modes/interactive/tasks/render.js.map +1 -1
- package/dist/modes/interactive/tasks/task-view.d.ts +8 -48
- package/dist/modes/interactive/tasks/task-view.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/task-view.js +11 -51
- package/dist/modes/interactive/tasks/task-view.js.map +1 -1
- package/dist/modes/interactive/tasks/text.d.ts +1 -7
- package/dist/modes/interactive/tasks/text.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/text.js +6 -29
- package/dist/modes/interactive/tasks/text.js.map +1 -1
- package/dist/modes/interactive/tasks/viewport.d.ts +2 -0
- package/dist/modes/interactive/tasks/viewport.d.ts.map +1 -1
- package/dist/modes/interactive/tasks/viewport.js +17 -7
- package/dist/modes/interactive/tasks/viewport.js.map +1 -1
- package/dist/modes/interactive/tasks/views.d.ts +9 -0
- package/dist/modes/interactive/tasks/views.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/views.js +42 -0
- package/dist/modes/interactive/tasks/views.js.map +1 -0
- package/dist/modes/interactive/theme/system-theme.d.ts +2 -1
- package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/system-theme.js +16 -5
- package/dist/modes/interactive/theme/system-theme.js.map +1 -1
- package/docs/bundled/README.md +0 -1
- package/docs/bundled/extensions/question.md +2 -2
- package/docs/bundled/extensions/statusline.md +24 -15
- package/docs/bundled/tasks.md +34 -48
- package/docs/codemode.md +207 -0
- package/docs/docs.json +4 -4
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +7 -9
- package/docs/keybindings.md +13 -6
- package/docs/mcp.md +142 -82
- package/docs/models.md +21 -0
- package/docs/providers.md +8 -0
- package/docs/sdk.md +2 -2
- package/docs/session-format.md +12 -22
- package/docs/settings.md +4 -2
- package/docs/tui.md +1 -1
- package/docs/usage.md +6 -16
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +1 -2
- package/examples/extensions/built-in-tool-renderer.ts +16 -40
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/minimal-mode.ts +24 -96
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/14-codemode-mcp.ts +2 -2
- package/npm-shrinkwrap.json +69 -58
- package/package.json +11 -10
- package/dist/bundle/chunks/anthropic-messages-KIXY7EDT.js +0 -6
- package/dist/bundle/chunks/chunk-CLLDCO64.js +0 -2
- package/dist/bundle/chunks/chunk-UUSTLCVC.js +0 -2
- package/dist/bundle/chunks/chunk-VWCWZD6E.js +0 -2
- package/dist/bundle/chunks/virtual-modules-TQRORWJQ.js +0 -2
- package/dist/core/tasks/view-data.d.ts +0 -8
- package/dist/core/tasks/view-data.d.ts.map +0 -1
- package/dist/core/tasks/view-data.js +0 -61
- package/dist/core/tasks/view-data.js.map +0 -1
- package/dist/core/tasks/view.d.ts +0 -30
- package/dist/core/tasks/view.d.ts.map +0 -1
- package/dist/core/tasks/view.js +0 -50
- package/dist/core/tasks/view.js.map +0 -1
- package/dist/core/tools/renderers/shell-task.d.ts +0 -4
- package/dist/core/tools/renderers/shell-task.d.ts.map +0 -1
- package/dist/core/tools/renderers/shell-task.js +0 -35
- package/dist/core/tools/renderers/shell-task.js.map +0 -1
- package/dist/extensions/todo/constants.d.ts +0 -16
- package/dist/extensions/todo/constants.d.ts.map +0 -1
- package/dist/extensions/todo/constants.js +0 -30
- package/dist/extensions/todo/constants.js.map +0 -1
- package/dist/extensions/todo/index.d.ts +0 -3
- package/dist/extensions/todo/index.d.ts.map +0 -1
- package/dist/extensions/todo/index.js +0 -98
- package/dist/extensions/todo/index.js.map +0 -1
- package/dist/extensions/todo/schema.d.ts +0 -60
- package/dist/extensions/todo/schema.d.ts.map +0 -1
- package/dist/extensions/todo/schema.js +0 -56
- package/dist/extensions/todo/schema.js.map +0 -1
- package/dist/extensions/todo/state.d.ts +0 -34
- package/dist/extensions/todo/state.d.ts.map +0 -1
- package/dist/extensions/todo/state.js +0 -425
- package/dist/extensions/todo/state.js.map +0 -1
- package/dist/extensions/todo/view.d.ts +0 -36
- package/dist/extensions/todo/view.d.ts.map +0 -1
- package/dist/extensions/todo/view.js +0 -580
- package/dist/extensions/todo/view.js.map +0 -1
- package/dist/extensions/todo/widget.d.ts +0 -15
- package/dist/extensions/todo/widget.d.ts.map +0 -1
- package/dist/extensions/todo/widget.js +0 -50
- package/dist/extensions/todo/widget.js.map +0 -1
- package/dist/modes/interactive/tasks/fallback-view.d.ts +0 -4
- package/dist/modes/interactive/tasks/fallback-view.d.ts.map +0 -1
- package/dist/modes/interactive/tasks/fallback-view.js +0 -27
- package/dist/modes/interactive/tasks/fallback-view.js.map +0 -1
- package/docs/bundled/extensions/todo.md +0 -104
- package/examples/extensions/todo.ts +0 -297
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtual-models.d.ts","sourceRoot":"","sources":["../../src/core/virtual-models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAEN,KAAK,GAAG,EACR,KAAK,gBAAgB,EAIrB,KAAK,OAAO,EACZ,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EAEb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAE9C,wEAAwE;AACxE,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAElE,uDAAuD;AACvD,MAAM,WAAW,qBAAqB,CAAC,MAAM,GAAG,OAAO;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACd;AAID;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5E,MAAM,WAAW,iBAAiB,CAAC,MAAM,GAAG,OAAO;IAClD,kCAAkC;IAClC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,oEAAoE;IACpE,aAAa,EAAE,kBAAkB,CAAC;IAClC,MAAM,EAAE,gBAAgB,CAAC;IACzB,yFAAyF;IACzF,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,aAAa,CAAC,EAAE,kBAAkB,CAAA;KAAE,CAAC;IACrE;;;OAGG;IACH,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,aAAa,CAAC,EAAE,kBAAkB,CAAC;QAAC,OAAO,EAAE,gBAAgB,CAAA;KAAE,CAAC;IAC9F,qHAAqH;IACrH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,yDAAyD;AACzD,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,OAAO;IAC3C,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,kBAAkB,CAAC;IAClC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB,CAAC,MAAM,GAAG,OAAO;IACvD,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,cAAc,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC/C;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6HAA6H;IAC7H,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC7B,gGAAgG;IAChG,KAAK,CAAC,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;CAC5F;AAED,gHAAgH;AAChH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAE9D;AAED,4HAA4H;AAC5H,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,gBAAgB,GAAG,SAAS,CAQlG;AAED
|
|
1
|
+
{"version":3,"file":"virtual-models.d.ts","sourceRoot":"","sources":["../../src/core/virtual-models.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,24 +23,31 @@ export function findLatestResponse(messages) {
|
|
|
23
23
|
* `model_change`, because responses name the physical models it routed to. Otherwise the latest
|
|
24
24
|
* physical response wins, as in sessions without virtual models. A virtual model that is no longer
|
|
25
25
|
* registered does not hold, so the selection falls back to the physical model that answered last.
|
|
26
|
+
*
|
|
27
|
+
* Only the last `model_change` can hold, so this looks up at most one model in the catalog.
|
|
26
28
|
*/
|
|
27
29
|
export function getBranchSelection(branch, getModel) {
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
return model !== undefined && isVirtualModel(model);
|
|
31
|
-
};
|
|
32
|
-
let selection;
|
|
33
|
-
for (const entry of branch) {
|
|
30
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
31
|
+
const entry = branch[i];
|
|
34
32
|
if (entry.type === "model_change") {
|
|
35
|
-
|
|
33
|
+
return { provider: entry.provider, modelId: entry.modelId };
|
|
36
34
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
if (entry.type === "message" && entry.message.role === "assistant" && !isVirtualModel(entry.message)) {
|
|
36
|
+
const response = { provider: entry.message.provider, modelId: entry.message.model };
|
|
37
|
+
const change = findLastModelChange(branch, i);
|
|
38
|
+
const model = change && getModel(change.provider, change.modelId);
|
|
39
|
+
return change && model && isVirtualModel(model) ? change : response;
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
|
-
return
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
function findLastModelChange(branch, before) {
|
|
45
|
+
for (let i = before - 1; i >= 0; i--) {
|
|
46
|
+
const entry = branch[i];
|
|
47
|
+
if (entry.type === "model_change")
|
|
48
|
+
return { provider: entry.provider, modelId: entry.modelId };
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
44
51
|
}
|
|
45
52
|
/** Latest router state a session branch stores for a virtual model. */
|
|
46
53
|
export function getVirtualModelState(branch, provider, modelId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtual-models.js","sourceRoot":"","sources":["../../src/core/virtual-models.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Virtual models are catalog entries that route each request to a physical model.\n *\n * The selection (`model_change`, `agent.state.model`, `ctx.model`) may name a virtual model.\n * Everything below the routing step only sees physical models: providers stream them and\n * assistant messages record them. A virtual model never reaches a provider.\n *\n * Virtual models belong to a provider id but are not provider models. `ModelRuntime` keeps them\n * separately and adds them to the provider's catalog with `withVirtualModels()`, so any provider,\n * including one with physical models, can list several virtual models.\n */\nimport type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AnyModel,\n\ttype Api,\n\ttype AssistantMessage,\n\ttype AssistantMessageEventStream,\n\tisModelType,\n\tlazyStream,\n\ttype Message,\n\ttype Model,\n\ttype ModelThinkingLevel,\n\ttype Provider,\n\ttype ThinkingLevelMap,\n} from \"@earendil-works/pi-ai\";\nimport type { SessionEntry } from \"./session-manager.ts\";\n\n/** API id of virtual catalog entries. Requests for it fail unless routed first. */\nexport const VIRTUAL_MODEL_API = \"pi-virtual\";\n\n/** Custom entry type that stores router state on the session branch. */\nexport const VIRTUAL_MODEL_STATE_ENTRY = \"pi.virtual-model-state\";\n\n/** Data of a `pi.virtual-model-state` custom entry. */\nexport interface VirtualModelStateData<TState = unknown> {\n\tprovider: string;\n\tmodelId: string;\n\tstate: TState;\n}\n\nconst THINKING_LEVELS: readonly ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\n/**\n * Why a request is being routed.\n * - `user`: first request after a message the user wrote (prompt, steering, or follow-up)\n * - `continuation`: any other request in the agent loop, e.g. after tool results or extension messages\n * - `retry`: automatic retry after a failed request, including after compaction for a context overflow\n * - `direct`: a request outside the agent loop, e.g. a compaction summary or an extension call\n */\nexport type ModelRouteReason = \"user\" | \"continuation\" | \"retry\" | \"direct\";\n\nexport interface ModelRouteRequest<TState = unknown> {\n\t/** The selected virtual model. */\n\tmodel: Model<Api>;\n\t/** The selected thinking level. Its meaning is up to the router. */\n\tthinkingLevel: ModelThinkingLevel;\n\treason: ModelRouteReason;\n\t/** Physical model and thinking level of the latest successful response in `messages`. */\n\tprevious?: { model: Model<Api>; thinkingLevel?: ModelThinkingLevel };\n\t/**\n\t * For `retry`: the failed request, which `messages` no longer contains. `message` carries its\n\t * `stopReason` and `errorMessage`. Absent when the router itself failed.\n\t */\n\tfailed?: { model: Model<Api>; thinkingLevel?: ModelThinkingLevel; message: AssistantMessage };\n\t/** Router state last returned on this session branch. Undefined before the first state and for `direct` requests. */\n\tstate?: TState;\n\t/** Conversation for this request, including system messages. */\n\tmessages: readonly Message[];\n\tsignal?: AbortSignal;\n}\n\n/** Physical model and thinking level for one request. */\nexport interface ModelRoute<TState = unknown> {\n\tmodel: Model<Api>;\n\tthinkingLevel: ModelThinkingLevel;\n\t/**\n\t * New router state, stored on the session branch unless it is `request.state` itself. Return\n\t * `request.state` or undefined to keep the current state. Must be JSON-serializable. Ignored for\n\t * `direct` requests.\n\t */\n\tstate?: TState;\n}\n\nexport interface VirtualModelDefinition<TState = unknown> {\n\t/** Provider the virtual model is listed under. May be a provider with physical models. */\n\tprovider: string;\n\t/** Model id. Must not be the id of a physical model of `provider`. */\n\tid: string;\n\tname: string;\n\t/** Thinking levels offered for selection. Defaults to `[\"off\"]`. */\n\tthinkingLevels?: readonly ModelThinkingLevel[];\n\t/**\n\t * Limits shown before the first response. Afterwards, Pi uses the limits of the physical model\n\t * that answered. Unset limits are unknown (0).\n\t */\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\t/** Input types accepted for selection. Defaults to text and images; routed models without image support get placeholders. */\n\tinput?: (\"text\" | \"image\")[];\n\t/** Pick the physical model, which must have credentials, and thinking level for one request. */\n\troute(request: ModelRouteRequest<TState>): ModelRoute<TState> | Promise<ModelRoute<TState>>;\n}\n\n/** Whether a model or message names a virtual model. Failed routing leaves the virtual model on its message. */\nexport function isVirtualModel(model: { api: string }): boolean {\n\treturn model.api === VIRTUAL_MODEL_API;\n}\n\n/** Latest successful response. Its model is physical: failed or aborted requests, including failed routing, are skipped. */\nexport function findLatestResponse(messages: readonly AgentMessage[]): AssistantMessage | undefined {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role === \"assistant\" && message.stopReason !== \"error\" && message.stopReason !== \"aborted\") {\n\t\t\treturn message;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * The model selection a session branch records. A virtual `model_change` holds until the next\n * `model_change`, because responses name the physical models it routed to. Otherwise the latest\n * physical response wins, as in sessions without virtual models. A virtual model that is no longer\n * registered does not hold, so the selection falls back to the physical model that answered last.\n */\nexport function getBranchSelection(\n\tbranch: readonly SessionEntry[],\n\tgetModel: (provider: string, modelId: string) => Model<Api> | undefined,\n): { provider: string; modelId: string } | undefined {\n\tconst isVirtual = (provider: string, modelId: string) => {\n\t\tconst model = getModel(provider, modelId);\n\t\treturn model !== undefined && isVirtualModel(model);\n\t};\n\tlet selection: { provider: string; modelId: string } | undefined;\n\tfor (const entry of branch) {\n\t\tif (entry.type === \"model_change\") {\n\t\t\tselection = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\" && !isVirtualModel(entry.message)) {\n\t\t\tif (!selection || !isVirtual(selection.provider, selection.modelId)) {\n\t\t\t\tselection = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t\t}\n\t\t}\n\t}\n\treturn selection;\n}\n\n/** Latest router state a session branch stores for a virtual model. */\nexport function getVirtualModelState(branch: readonly SessionEntry[], provider: string, modelId: string): unknown {\n\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\tconst entry = branch[i];\n\t\tif (entry.type !== \"custom\" || entry.customType !== VIRTUAL_MODEL_STATE_ENTRY) continue;\n\t\tconst data = entry.data as VirtualModelStateData | undefined;\n\t\tif (data?.provider === provider && data.modelId === modelId) return data.state;\n\t}\n\treturn undefined;\n}\n\n/** Build the catalog entry of a virtual model. */\nexport function createVirtualModel(definition: Omit<VirtualModelDefinition, \"route\">): Model<Api> {\n\tconst levels = definition.thinkingLevels ?? [\"off\"];\n\tconst thinkingLevelMap: ThinkingLevelMap = {};\n\tfor (const level of THINKING_LEVELS) thinkingLevelMap[level] = levels.includes(level) ? level : null;\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: VIRTUAL_MODEL_API,\n\t\tprovider: definition.provider,\n\t\tbaseUrl: \"\",\n\t\treasoning: levels.some((level) => level !== \"off\"),\n\t\tthinkingLevelMap,\n\t\tinput: definition.input ?? [\"text\", \"image\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: definition.contextWindow ?? 0,\n\t\tmaxTokens: definition.maxTokens ?? 0,\n\t};\n}\n\n/** Stream for a virtual model that was not routed, e.g. `stream()` with API-specific options. */\nfunction unroutedStream(model: Model<Api>): AssistantMessageEventStream {\n\treturn lazyStream(model, async () => {\n\t\tthrow new Error(`Virtual model ${model.provider}/${model.id} must be routed before streaming`);\n\t});\n}\n\n/**\n * Add virtual models to a provider's catalog. Without a provider, the result is a keyless provider\n * that only lists the virtual models. A virtual model hides a physical chat model with the same id,\n * which a catalog refresh can add after registration. Availability follows the provider's auth.\n */\nexport function withVirtualModels(\n\tproviderId: string,\n\tprovider: Provider | undefined,\n\tvirtualModels: readonly Model<Api>[],\n): Provider {\n\tif (!provider) {\n\t\treturn {\n\t\t\tid: providerId,\n\t\t\tname: providerId,\n\t\t\tauth: { apiKey: { name: \"Virtual model\", resolve: async () => ({ auth: {}, source: \"virtual\" }) } },\n\t\t\tgetModels: () => virtualModels,\n\t\t\tstream: unroutedStream,\n\t\t\tstreamSimple: unroutedStream,\n\t\t};\n\t}\n\tconst ids = new Set(virtualModels.map((model) => model.id));\n\tconst physical = <TModel extends AnyModel>(models: readonly TModel[]) =>\n\t\tmodels.filter((model) => !isVirtualModel(model) && !(isModelType(model, \"chat\") && ids.has(model.id)));\n\tconst virtual = <TModel extends AnyModel>(models: readonly TModel[]) =>\n\t\tmodels.filter((model) => isVirtualModel(model));\n\tconst { filterModels, filterAllModels } = provider;\n\treturn {\n\t\t...provider,\n\t\tgetModels: () => [...physical(provider.getModels()), ...virtualModels],\n\t\tgetAllModels: () => [...physical(provider.getAllModels?.() ?? provider.getModels()), ...virtualModels],\n\t\tfilterModels: (models, credential) => {\n\t\t\tconst real = physical(models);\n\t\t\treturn [...(filterModels?.(real, credential) ?? real), ...virtual(models)];\n\t\t},\n\t\tfilterAllModels:\n\t\t\tfilterAllModels &&\n\t\t\t((models, credential) => [...filterAllModels(physical(models), credential), ...virtual(models)]),\n\t\tstream: (model, context, options) =>\n\t\t\tisVirtualModel(model) ? unroutedStream(model) : provider.stream(model, context, options),\n\t\tstreamSimple: (model, context, options) =>\n\t\t\tisVirtualModel(model) ? unroutedStream(model) : provider.streamSimple(model, context, options),\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"virtual-models.js","sourceRoot":"","sources":["../../src/core/virtual-models.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Virtual models are catalog entries that route each request to a physical model.\n *\n * The selection (`model_change`, `agent.state.model`, `ctx.model`) may name a virtual model.\n * Everything below the routing step only sees physical models: providers stream them and\n * assistant messages record them. A virtual model never reaches a provider.\n *\n * Virtual models belong to a provider id but are not provider models. `ModelRuntime` keeps them\n * separately and adds them to the provider's catalog with `withVirtualModels()`, so any provider,\n * including one with physical models, can list several virtual models.\n */\nimport type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AnyModel,\n\ttype Api,\n\ttype AssistantMessage,\n\ttype AssistantMessageEventStream,\n\tisModelType,\n\tlazyStream,\n\ttype Message,\n\ttype Model,\n\ttype ModelThinkingLevel,\n\ttype Provider,\n\ttype ThinkingLevelMap,\n} from \"@earendil-works/pi-ai\";\nimport type { SessionEntry } from \"./session-manager.ts\";\n\n/** API id of virtual catalog entries. Requests for it fail unless routed first. */\nexport const VIRTUAL_MODEL_API = \"pi-virtual\";\n\n/** Custom entry type that stores router state on the session branch. */\nexport const VIRTUAL_MODEL_STATE_ENTRY = \"pi.virtual-model-state\";\n\n/** Data of a `pi.virtual-model-state` custom entry. */\nexport interface VirtualModelStateData<TState = unknown> {\n\tprovider: string;\n\tmodelId: string;\n\tstate: TState;\n}\n\nconst THINKING_LEVELS: readonly ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\n/**\n * Why a request is being routed.\n * - `user`: first request after a message the user wrote (prompt, steering, or follow-up)\n * - `continuation`: any other request in the agent loop, e.g. after tool results or extension messages\n * - `retry`: automatic retry after a failed request, including after compaction for a context overflow\n * - `direct`: a request outside the agent loop, e.g. a compaction summary or an extension call\n */\nexport type ModelRouteReason = \"user\" | \"continuation\" | \"retry\" | \"direct\";\n\nexport interface ModelRouteRequest<TState = unknown> {\n\t/** The selected virtual model. */\n\tmodel: Model<Api>;\n\t/** The selected thinking level. Its meaning is up to the router. */\n\tthinkingLevel: ModelThinkingLevel;\n\treason: ModelRouteReason;\n\t/** Physical model and thinking level of the latest successful response in `messages`. */\n\tprevious?: { model: Model<Api>; thinkingLevel?: ModelThinkingLevel };\n\t/**\n\t * For `retry`: the failed request, which `messages` no longer contains. `message` carries its\n\t * `stopReason` and `errorMessage`. Absent when the router itself failed.\n\t */\n\tfailed?: { model: Model<Api>; thinkingLevel?: ModelThinkingLevel; message: AssistantMessage };\n\t/** Router state last returned on this session branch. Undefined before the first state and for `direct` requests. */\n\tstate?: TState;\n\t/** Conversation for this request, including system messages. */\n\tmessages: readonly Message[];\n\tsignal?: AbortSignal;\n}\n\n/** Physical model and thinking level for one request. */\nexport interface ModelRoute<TState = unknown> {\n\tmodel: Model<Api>;\n\tthinkingLevel: ModelThinkingLevel;\n\t/**\n\t * New router state, stored on the session branch unless it is `request.state` itself. Return\n\t * `request.state` or undefined to keep the current state. Must be JSON-serializable. Ignored for\n\t * `direct` requests.\n\t */\n\tstate?: TState;\n}\n\nexport interface VirtualModelDefinition<TState = unknown> {\n\t/** Provider the virtual model is listed under. May be a provider with physical models. */\n\tprovider: string;\n\t/** Model id. Must not be the id of a physical model of `provider`. */\n\tid: string;\n\tname: string;\n\t/** Thinking levels offered for selection. Defaults to `[\"off\"]`. */\n\tthinkingLevels?: readonly ModelThinkingLevel[];\n\t/**\n\t * Limits shown before the first response. Afterwards, Pi uses the limits of the physical model\n\t * that answered. Unset limits are unknown (0).\n\t */\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\t/** Input types accepted for selection. Defaults to text and images; routed models without image support get placeholders. */\n\tinput?: (\"text\" | \"image\")[];\n\t/** Pick the physical model, which must have credentials, and thinking level for one request. */\n\troute(request: ModelRouteRequest<TState>): ModelRoute<TState> | Promise<ModelRoute<TState>>;\n}\n\n/** Whether a model or message names a virtual model. Failed routing leaves the virtual model on its message. */\nexport function isVirtualModel(model: { api: string }): boolean {\n\treturn model.api === VIRTUAL_MODEL_API;\n}\n\n/** Latest successful response. Its model is physical: failed or aborted requests, including failed routing, are skipped. */\nexport function findLatestResponse(messages: readonly AgentMessage[]): AssistantMessage | undefined {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role === \"assistant\" && message.stopReason !== \"error\" && message.stopReason !== \"aborted\") {\n\t\t\treturn message;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * The model selection a session branch records. A virtual `model_change` holds until the next\n * `model_change`, because responses name the physical models it routed to. Otherwise the latest\n * physical response wins, as in sessions without virtual models. A virtual model that is no longer\n * registered does not hold, so the selection falls back to the physical model that answered last.\n *\n * Only the last `model_change` can hold, so this looks up at most one model in the catalog.\n */\nexport function getBranchSelection(\n\tbranch: readonly SessionEntry[],\n\tgetModel: (provider: string, modelId: string) => Model<Api> | undefined,\n): { provider: string; modelId: string } | undefined {\n\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\tconst entry = branch[i];\n\t\tif (entry.type === \"model_change\") {\n\t\t\treturn { provider: entry.provider, modelId: entry.modelId };\n\t\t}\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\" && !isVirtualModel(entry.message)) {\n\t\t\tconst response = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t\tconst change = findLastModelChange(branch, i);\n\t\t\tconst model = change && getModel(change.provider, change.modelId);\n\t\t\treturn change && model && isVirtualModel(model) ? change : response;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction findLastModelChange(\n\tbranch: readonly SessionEntry[],\n\tbefore: number,\n): { provider: string; modelId: string } | undefined {\n\tfor (let i = before - 1; i >= 0; i--) {\n\t\tconst entry = branch[i];\n\t\tif (entry.type === \"model_change\") return { provider: entry.provider, modelId: entry.modelId };\n\t}\n\treturn undefined;\n}\n\n/** Latest router state a session branch stores for a virtual model. */\nexport function getVirtualModelState(branch: readonly SessionEntry[], provider: string, modelId: string): unknown {\n\tfor (let i = branch.length - 1; i >= 0; i--) {\n\t\tconst entry = branch[i];\n\t\tif (entry.type !== \"custom\" || entry.customType !== VIRTUAL_MODEL_STATE_ENTRY) continue;\n\t\tconst data = entry.data as VirtualModelStateData | undefined;\n\t\tif (data?.provider === provider && data.modelId === modelId) return data.state;\n\t}\n\treturn undefined;\n}\n\n/** Build the catalog entry of a virtual model. */\nexport function createVirtualModel(definition: Omit<VirtualModelDefinition, \"route\">): Model<Api> {\n\tconst levels = definition.thinkingLevels ?? [\"off\"];\n\tconst thinkingLevelMap: ThinkingLevelMap = {};\n\tfor (const level of THINKING_LEVELS) thinkingLevelMap[level] = levels.includes(level) ? level : null;\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: VIRTUAL_MODEL_API,\n\t\tprovider: definition.provider,\n\t\tbaseUrl: \"\",\n\t\treasoning: levels.some((level) => level !== \"off\"),\n\t\tthinkingLevelMap,\n\t\tinput: definition.input ?? [\"text\", \"image\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: definition.contextWindow ?? 0,\n\t\tmaxTokens: definition.maxTokens ?? 0,\n\t};\n}\n\n/** Stream for a virtual model that was not routed, e.g. `stream()` with API-specific options. */\nfunction unroutedStream(model: Model<Api>): AssistantMessageEventStream {\n\treturn lazyStream(model, async () => {\n\t\tthrow new Error(`Virtual model ${model.provider}/${model.id} must be routed before streaming`);\n\t});\n}\n\n/**\n * Add virtual models to a provider's catalog. Without a provider, the result is a keyless provider\n * that only lists the virtual models. A virtual model hides a physical chat model with the same id,\n * which a catalog refresh can add after registration. Availability follows the provider's auth.\n */\nexport function withVirtualModels(\n\tproviderId: string,\n\tprovider: Provider | undefined,\n\tvirtualModels: readonly Model<Api>[],\n): Provider {\n\tif (!provider) {\n\t\treturn {\n\t\t\tid: providerId,\n\t\t\tname: providerId,\n\t\t\tauth: { apiKey: { name: \"Virtual model\", resolve: async () => ({ auth: {}, source: \"virtual\" }) } },\n\t\t\tgetModels: () => virtualModels,\n\t\t\tstream: unroutedStream,\n\t\t\tstreamSimple: unroutedStream,\n\t\t};\n\t}\n\tconst ids = new Set(virtualModels.map((model) => model.id));\n\tconst physical = <TModel extends AnyModel>(models: readonly TModel[]) =>\n\t\tmodels.filter((model) => !isVirtualModel(model) && !(isModelType(model, \"chat\") && ids.has(model.id)));\n\tconst virtual = <TModel extends AnyModel>(models: readonly TModel[]) =>\n\t\tmodels.filter((model) => isVirtualModel(model));\n\tconst { filterModels, filterAllModels } = provider;\n\treturn {\n\t\t...provider,\n\t\tgetModels: () => [...physical(provider.getModels()), ...virtualModels],\n\t\tgetAllModels: () => [...physical(provider.getAllModels?.() ?? provider.getModels()), ...virtualModels],\n\t\tfilterModels: (models, credential) => {\n\t\t\tconst real = physical(models);\n\t\t\treturn [...(filterModels?.(real, credential) ?? real), ...virtual(models)];\n\t\t},\n\t\tfilterAllModels:\n\t\t\tfilterAllModels &&\n\t\t\t((models, credential) => [...filterAllModels(physical(models), credential), ...virtual(models)]),\n\t\tstream: (model, context, options) =>\n\t\t\tisVirtualModel(model) ? unroutedStream(model) : provider.stream(model, context, options),\n\t\tstreamSimple: (model, context, options) =>\n\t\t\tisVirtualModel(model) ? unroutedStream(model) : provider.streamSimple(model, context, options),\n\t};\n}\n"]}
|
|
@@ -10,8 +10,15 @@ export interface BtwTurn {
|
|
|
10
10
|
elapsedMs: number;
|
|
11
11
|
firstAnswerMs?: number;
|
|
12
12
|
}
|
|
13
|
+
export interface BtwConversationState {
|
|
14
|
+
busy: boolean;
|
|
15
|
+
turns: readonly BtwTurn[];
|
|
16
|
+
usage: Usage;
|
|
17
|
+
latestCacheHitPercent: number | undefined;
|
|
18
|
+
blockedTools: number;
|
|
19
|
+
}
|
|
13
20
|
/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */
|
|
14
|
-
export declare class BtwAgent {
|
|
21
|
+
export declare class BtwAgent implements BtwConversationState {
|
|
15
22
|
readonly turns: BtwTurn[];
|
|
16
23
|
readonly usage: Usage;
|
|
17
24
|
latestCacheHitPercent: number | undefined;
|
|
@@ -20,16 +27,18 @@ export declare class BtwAgent {
|
|
|
20
27
|
private readonly unsubscribe;
|
|
21
28
|
private readonly onChange;
|
|
22
29
|
private readonly inputBudget;
|
|
23
|
-
private
|
|
30
|
+
private active?;
|
|
24
31
|
private disposed;
|
|
25
|
-
private steps;
|
|
26
|
-
private completedAnswer;
|
|
27
|
-
private responseChars;
|
|
28
32
|
constructor(snapshot: ContextSnapshot, runtime: Pick<Models, "streamSimple">, onChange: () => void);
|
|
29
33
|
get busy(): boolean;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
private validate;
|
|
35
|
+
/** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */
|
|
36
|
+
startQuestion(text: string): {
|
|
37
|
+
error: string;
|
|
38
|
+
} | {
|
|
39
|
+
completion: Promise<void>;
|
|
40
|
+
};
|
|
41
|
+
private runQuestion;
|
|
33
42
|
cancel(): void;
|
|
34
43
|
dispose(): void;
|
|
35
44
|
private fits;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAYtE,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAYtE,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;CACrB;AAwBD,+FAA+F;AAC/F,qBAAa,QAAS,YAAW,oBAAoB;IACpD,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAM;IAC/B,QAAQ,CAAC,KAAK,QAAgB;IAC9B,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,SAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAC,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAyDlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,OAAO,CAAC,QAAQ;IAahB,oGAAoG;IACpG,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE;YAqBhE,WAAW;IAsBzB,MAAM,IAAI,IAAI;IAOd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,WAAW;IA8CnB,OAAO,CAAC,YAAY;CAkBpB"}
|
|
@@ -22,11 +22,7 @@ export class BtwAgent {
|
|
|
22
22
|
this.turns = [];
|
|
23
23
|
this.usage = emptyUsage();
|
|
24
24
|
this.blockedTools = 0;
|
|
25
|
-
this.running = false;
|
|
26
25
|
this.disposed = false;
|
|
27
|
-
this.steps = 0;
|
|
28
|
-
this.completedAnswer = "";
|
|
29
|
-
this.responseChars = 0;
|
|
30
26
|
this.onChange = onChange;
|
|
31
27
|
const outputReserve = Math.min(MAX_OUTPUT_RESERVE_TOKENS, snapshot.model.maxTokens, Math.max(1024, Math.floor(snapshot.model.contextWindow / 8)));
|
|
32
28
|
// Leave room for the answer and estimation error; never trim the inherited prefix.
|
|
@@ -59,21 +55,19 @@ export class BtwAgent {
|
|
|
59
55
|
runtime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),
|
|
60
56
|
beforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),
|
|
61
57
|
finishTurn: ({ message, toolResults, context }) => {
|
|
58
|
+
const question = this.active;
|
|
62
59
|
// Error and aborted responses are hard exits; the step budget only counts answered turns.
|
|
63
|
-
if (message.stopReason === "error" || message.stopReason === "aborted")
|
|
60
|
+
if (!question || this.disposed || message.stopReason === "error" || message.stopReason === "aborted")
|
|
64
61
|
return undefined;
|
|
65
|
-
|
|
62
|
+
question.steps++;
|
|
66
63
|
if (!toolResults.length)
|
|
67
64
|
return undefined;
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
? "Stopped after repeated tool requests. BTW can only answer from its snapshot."
|
|
75
|
-
: "Context limit reached. Reopen /btw for a new conversation.";
|
|
76
|
-
}
|
|
65
|
+
if (question.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {
|
|
66
|
+
question.turn.status = "error";
|
|
67
|
+
question.turn.notice =
|
|
68
|
+
question.steps >= MAX_MODEL_STEPS
|
|
69
|
+
? "Stopped after repeated tool requests. BTW can only answer from its snapshot."
|
|
70
|
+
: "Context limit reached. Reopen /btw for a new conversation.";
|
|
77
71
|
return { action: "end" };
|
|
78
72
|
}
|
|
79
73
|
return undefined;
|
|
@@ -82,9 +76,8 @@ export class BtwAgent {
|
|
|
82
76
|
this.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));
|
|
83
77
|
}
|
|
84
78
|
get busy() {
|
|
85
|
-
return this.
|
|
79
|
+
return this.active !== undefined;
|
|
86
80
|
}
|
|
87
|
-
/** A rejected submission stays in the editor and never enters either agent's queue. */
|
|
88
81
|
validate(text) {
|
|
89
82
|
if (this.disposed)
|
|
90
83
|
return "This BTW conversation is closed.";
|
|
@@ -100,26 +93,32 @@ export class BtwAgent {
|
|
|
100
93
|
}
|
|
101
94
|
return undefined;
|
|
102
95
|
}
|
|
103
|
-
|
|
96
|
+
/** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */
|
|
97
|
+
startQuestion(text) {
|
|
104
98
|
const error = this.validate(text);
|
|
105
99
|
if (error)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
100
|
+
return { error };
|
|
101
|
+
const question = {
|
|
102
|
+
turn: {
|
|
103
|
+
question: text,
|
|
104
|
+
answer: "",
|
|
105
|
+
thinking: "",
|
|
106
|
+
status: "streaming",
|
|
107
|
+
startedAt: Date.now(),
|
|
108
|
+
elapsedMs: 0,
|
|
109
|
+
},
|
|
110
|
+
steps: 0,
|
|
111
|
+
completedAnswer: "",
|
|
112
|
+
responseChars: 0,
|
|
118
113
|
};
|
|
119
|
-
this.
|
|
120
|
-
this.
|
|
114
|
+
this.active = question;
|
|
115
|
+
this.turns.push(question.turn);
|
|
116
|
+
return { completion: this.runQuestion(question) };
|
|
117
|
+
}
|
|
118
|
+
async runQuestion({ turn }) {
|
|
121
119
|
try {
|
|
122
|
-
|
|
120
|
+
this.onChange();
|
|
121
|
+
await this.agent.prompt(turn.question);
|
|
123
122
|
if (turn.status === "streaming") {
|
|
124
123
|
turn.status = "done";
|
|
125
124
|
if (!turn.answer)
|
|
@@ -134,7 +133,8 @@ export class BtwAgent {
|
|
|
134
133
|
turn.notice = displayText(error instanceof Error ? error.message : String(error));
|
|
135
134
|
}
|
|
136
135
|
finally {
|
|
137
|
-
|
|
136
|
+
// Cancellation remains busy until the native Agent has fully settled.
|
|
137
|
+
this.active = undefined;
|
|
138
138
|
turn.elapsedMs = Date.now() - turn.startedAt;
|
|
139
139
|
if (this.disposed)
|
|
140
140
|
this.agent.reset();
|
|
@@ -143,11 +143,9 @@ export class BtwAgent {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
cancel() {
|
|
146
|
-
if (!this.
|
|
146
|
+
if (!this.active || this.disposed)
|
|
147
147
|
return;
|
|
148
|
-
|
|
149
|
-
if (turn)
|
|
150
|
-
turn.status = "cancelling";
|
|
148
|
+
this.active.turn.status = "cancelling";
|
|
151
149
|
this.agent.abort();
|
|
152
150
|
this.onChange();
|
|
153
151
|
}
|
|
@@ -170,46 +168,46 @@ export class BtwAgent {
|
|
|
170
168
|
})).tokens < this.inputBudget);
|
|
171
169
|
}
|
|
172
170
|
handleEvent(event) {
|
|
173
|
-
|
|
171
|
+
const question = this.active;
|
|
172
|
+
if (this.disposed ||
|
|
173
|
+
!question ||
|
|
174
|
+
(event.type !== "message_update" && event.type !== "message_end") ||
|
|
175
|
+
event.message.role !== "assistant")
|
|
174
176
|
return;
|
|
175
|
-
const turn =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
message.stopReason === "aborted"
|
|
204
|
-
? "Stopped. You can ask another question."
|
|
205
|
-
: displayText(message.errorMessage ?? "The request failed.");
|
|
206
|
-
}
|
|
177
|
+
const { turn } = question;
|
|
178
|
+
const message = event.message;
|
|
179
|
+
this.updateAnswer(question, message);
|
|
180
|
+
if (event.type === "message_end") {
|
|
181
|
+
question.completedAnswer = turn.answer;
|
|
182
|
+
question.responseChars += message.content.reduce((sum, part) => sum +
|
|
183
|
+
(part.type === "text"
|
|
184
|
+
? part.text.length
|
|
185
|
+
: part.type === "thinking"
|
|
186
|
+
? part.thinking.length
|
|
187
|
+
: JSON.stringify(part.arguments).length), 0);
|
|
188
|
+
this.blockedTools += message.content.filter((part) => part.type === "toolCall").length;
|
|
189
|
+
const usage = message.usage;
|
|
190
|
+
const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
191
|
+
this.latestCacheHitPercent =
|
|
192
|
+
(usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0
|
|
193
|
+
? (usage.cacheRead / promptTokens) * 100
|
|
194
|
+
: undefined;
|
|
195
|
+
for (const key of ["input", "output", "cacheRead", "cacheWrite", "totalTokens"])
|
|
196
|
+
this.usage[key] += usage[key];
|
|
197
|
+
for (const key of ["input", "output", "cacheRead", "cacheWrite", "total"])
|
|
198
|
+
this.usage.cost[key] += usage.cost[key];
|
|
199
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
200
|
+
turn.status = message.stopReason === "aborted" ? "cancelled" : "error";
|
|
201
|
+
turn.notice ??=
|
|
202
|
+
message.stopReason === "aborted"
|
|
203
|
+
? "Stopped. You can ask another question."
|
|
204
|
+
: displayText(message.errorMessage ?? "The request failed.");
|
|
207
205
|
}
|
|
208
|
-
turn.elapsedMs = Date.now() - turn.startedAt;
|
|
209
|
-
this.onChange();
|
|
210
206
|
}
|
|
207
|
+
this.onChange();
|
|
211
208
|
}
|
|
212
|
-
updateAnswer(
|
|
209
|
+
updateAnswer(question, message) {
|
|
210
|
+
const { turn } = question;
|
|
213
211
|
const text = message.content
|
|
214
212
|
.filter((part) => part.type === "text")
|
|
215
213
|
.map((part) => part.text)
|
|
@@ -220,9 +218,9 @@ export class BtwAgent {
|
|
|
220
218
|
.join("");
|
|
221
219
|
if (text && turn.firstAnswerMs === undefined)
|
|
222
220
|
turn.firstAnswerMs = Date.now() - turn.startedAt;
|
|
223
|
-
turn.answer = displayText([
|
|
221
|
+
turn.answer = displayText([question.completedAnswer, text].filter(Boolean).join("\n\n"));
|
|
224
222
|
turn.thinking = thinking.slice(-2000);
|
|
225
|
-
if (
|
|
223
|
+
if (question.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {
|
|
226
224
|
turn.notice = "Stopped at the BTW response size limit. You can ask a shorter follow-up.";
|
|
227
225
|
this.agent.abort();
|
|
228
226
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAKL,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,OAAO,EACN,iBAAiB,EACjB,eAAe,EACf,yBAAyB,EACzB,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,WAAW,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAalD,SAAS,UAAU;IAClB,OAAO;QACN,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;KACpE,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,yBAAyB,CAAC;AAC/G,CAAC;AAED,+FAA+F;AAC/F,MAAM,OAAO,QAAQ;IAepB,YAAY,QAAyB,EAAE,OAAqC,EAAE,QAAoB;QAdzF,UAAK,GAAc,EAAE,CAAC;QACtB,UAAK,GAAG,UAAU,EAAE,CAAC;QAE9B,iBAAY,GAAG,CAAC,CAAC;QAKT,YAAO,GAAG,KAAK,CAAC;QAChB,aAAQ,GAAG,KAAK,CAAC;QACjB,UAAK,GAAG,CAAC,CAAC;QACV,oBAAe,GAAG,EAAE,CAAC;QACrB,kBAAa,GAAG,CAAC,CAAC;QAGzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAC7B,yBAAyB,EACzB,QAAQ,CAAC,KAAK,CAAC,SAAS,EACxB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAC5D,CAAC;QACF,mFAAmF;QACnF,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,GAAG,aAAa,GAAG,IAAI,CAAC;QACvE,MAAM,KAAK,GAAgB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACxD,GAAG,eAAe,CAAC,IAAI,CAAC;YACxB,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,IAAI,EAAE;gBACnB,8EAA8E;gBAC9E,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;YAC9B,CAAC;SACD,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC;YACtB,YAAY,EAAE;gBACb,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,aAAa,EAAE,QAAQ,CAAC,aAAa;gBACrC,YAAY,EAAE,QAAQ,CAAC,YAAY;gBACnC,KAAK;gBACL,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;aACrC;YACD,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS;YACjE,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,SAAS;YAC3C,eAAe,EAAE,QAAQ,CAAC,aAAa,CAAC,eAAe;YACvD,eAAe,EAAE,QAAQ,CAAC,aAAa,CAAC,eAAe;YACvD,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,SAAS;YAC3C,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,UAAU;YAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;YACrC,uEAAuE;YACvE,oFAAoF;YACpF,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,QAAQ,CAAC,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;YAChF,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YAClE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAiC,EAAE;gBAChF,0FAA0F;gBAC1F,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;oBAAE,OAAO,SAAS,CAAC;gBACzF,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,WAAW,CAAC,MAAM;oBAAE,OAAO,SAAS,CAAC;gBAC1C,IAAI,IAAI,CAAC,KAAK,IAAI,eAAe,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACnE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC/B,IAAI,IAAI,EAAE,CAAC;wBACV,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;wBACtB,IAAI,CAAC,MAAM;4BACV,IAAI,CAAC,KAAK,IAAI,eAAe;gCAC5B,CAAC,CAAC,8EAA8E;gCAChF,CAAC,CAAC,4DAA4D,CAAC;oBAClE,CAAC;oBACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC1B,CAAC;gBACD,OAAO,SAAS,CAAC;YAClB,CAAC;SACD,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,IAAI;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED,uFAAuF;IACvF,QAAQ,CAAC,IAAY;QACpB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,kCAAkC,CAAC;QAC7D,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,8DAA8D,CAAC;QACrF,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,aAAa;YAAE,OAAO,iEAAiE,CAAC;QACjH,IAAI,IAAI,CAAC,MAAM,GAAG,kBAAkB;YACnC,OAAO,gCAAgC,kBAAkB,CAAC,cAAc,EAAE,cAAc,CAAC;QAC1F,MAAM,QAAQ,GAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACtF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC1D,OAAO,kGAAkG,CAAC;QAC3G,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAY;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QACvB,MAAM,IAAI,GAAY;YACrB,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE,EAAE;YACZ,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS,EAAE,CAAC;SACZ,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE,IAAI,CAAC,MAAM,GAAG,oCAAoC,CAAC;YACtE,CAAC;iBAAM,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACzC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;YAC3B,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACnF,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7C,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;;gBACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;IACF,CAAC;IAED,MAAM;QACL,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,IAAI;YAAE,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC;IAED,OAAO;QACN,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnC,4FAA4F;IAC7F,CAAC;IAEO,IAAI,CAAC,QAAwB;QACpC,OAAO,CACN,qBAAqB,CACpB,gBAAgB,CAAC;YAChB,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;YAC3C,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;YAC7B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CACxB,CAAC,OAAO,EAAsB,EAAE,CAC/B,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,CACzF;SACD,CAAC,CACF,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAC3B,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,KAAiB;QACpC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC7G,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;YAC9B,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACjC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBAClC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC;gBACnC,IAAI,CAAC,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAC3C,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CACb,GAAG;oBACH,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;wBACpB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;wBAClB,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU;4BACzB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM;4BACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAC3C,CAAC,CACD,CAAC;gBACF,IAAI,CAAC,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;gBACvF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC;gBACtE,IAAI,CAAC,qBAAqB;oBACzB,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,YAAY,GAAG,CAAC;wBAChE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC,GAAG,GAAG;wBACxC,CAAC,CAAC,SAAS,CAAC;gBACd,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,CAAU;oBACvF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC/B,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAU;oBACjF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACzC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;oBACxE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;oBACvE,IAAI,CAAC,MAAM;wBACV,OAAO,CAAC,UAAU,KAAK,SAAS;4BAC/B,CAAC,CAAC,wCAAwC;4BAC1C,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC,CAAC;gBAChE,CAAC;YACF,CAAC;YACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IAEO,YAAY,CAAC,IAAa,EAAE,OAAyB;QAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;aACtC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACxB,IAAI,CAAC,EAAE,CAAC,CAAC;QACX,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO;aAC9B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC;aAC1C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;aAC5B,IAAI,CAAC,EAAE,CAAC,CAAC;QACX,IAAI,IAAI,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC/F,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YACtF,IAAI,CAAC,MAAM,GAAG,0EAA0E,CAAC;YACzF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;IACF,CAAC;CACD","sourcesContent":["import {\n\tAgent,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentTool,\n\ttype AgentTurnDecision,\n} from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, Message, Models, Usage } from \"@earendil-works/pi-ai\";\nimport { normalizeContext } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport type { ContextSnapshot } from \"../../core/extensions/index.ts\";\nimport {\n\tMAX_DISPLAY_CHARS,\n\tMAX_MODEL_STEPS,\n\tMAX_OUTPUT_RESERVE_TOKENS,\n\tMAX_QUESTION_CHARS,\n\tMAX_QUESTIONS,\n\tMAX_RESPONSE_CHARS,\n\tTOOL_DENIAL,\n} from \"./constants.ts\";\nimport { createBtwMessages } from \"./snapshot.ts\";\n\nexport interface BtwTurn {\n\tquestion: string;\n\tanswer: string;\n\tthinking: string;\n\tstatus: \"streaming\" | \"cancelling\" | \"done\" | \"cancelled\" | \"error\";\n\tnotice?: string;\n\tstartedAt: number;\n\telapsedMs: number;\n\tfirstAnswerMs?: number;\n}\n\nfunction emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction displayText(text: string): string {\n\treturn text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\\n\\n[Display truncated]`;\n}\n\n/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */\nexport class BtwAgent {\n\treadonly turns: BtwTurn[] = [];\n\treadonly usage = emptyUsage();\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools = 0;\n\tprivate readonly agent: Agent;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly onChange: () => void;\n\tprivate readonly inputBudget: number;\n\tprivate running = false;\n\tprivate disposed = false;\n\tprivate steps = 0;\n\tprivate completedAnswer = \"\";\n\tprivate responseChars = 0;\n\n\tconstructor(snapshot: ContextSnapshot, runtime: Pick<Models, \"streamSimple\">, onChange: () => void) {\n\t\tthis.onChange = onChange;\n\t\tconst outputReserve = Math.min(\n\t\t\tMAX_OUTPUT_RESERVE_TOKENS,\n\t\t\tsnapshot.model.maxTokens,\n\t\t\tMath.max(1024, Math.floor(snapshot.model.contextWindow / 8)),\n\t\t);\n\t\t// Leave room for the answer and estimation error; never trim the inherited prefix.\n\t\tthis.inputBudget = snapshot.model.contextWindow - outputReserve - 4096;\n\t\tconst tools: AgentTool[] = snapshot.tools.map((tool) => ({\n\t\t\t...structuredClone(tool),\n\t\t\tlabel: tool.name,\n\t\t\texecute: async () => {\n\t\t\t\t// Defense in depth: these objects never receive an original execute function.\n\t\t\t\tthrow new Error(TOOL_DENIAL);\n\t\t\t},\n\t\t}));\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: snapshot.model,\n\t\t\t\tthinkingLevel: snapshot.thinkingLevel,\n\t\t\t\tsystemPrompt: snapshot.systemPrompt,\n\t\t\t\ttools,\n\t\t\t\tmessages: createBtwMessages(snapshot),\n\t\t\t},\n\t\t\tsessionId: snapshot.streamOptions.sessionId ?? snapshot.sessionId,\n\t\t\ttransport: snapshot.streamOptions.transport,\n\t\t\tthinkingBudgets: snapshot.streamOptions.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: snapshot.streamOptions.maxRetryDelayMs,\n\t\t\tonPayload: snapshot.streamOptions.onPayload,\n\t\t\tonResponse: snapshot.streamOptions.onResponse,\n\t\t\tstreamFn: (model, context, options) =>\n\t\t\t\t// Keep the parent's generation settings as well as its message prefix.\n\t\t\t\t// The model's native output ceiling and our response-size guard still bound output.\n\t\t\t\truntime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),\n\t\t\tbeforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),\n\t\t\tfinishTurn: ({ message, toolResults, context }): AgentTurnDecision | undefined => {\n\t\t\t\t// Error and aborted responses are hard exits; the step budget only counts answered turns.\n\t\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") return undefined;\n\t\t\t\tthis.steps++;\n\t\t\t\tif (!toolResults.length) return undefined;\n\t\t\t\tif (this.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {\n\t\t\t\t\tconst turn = this.turns.at(-1);\n\t\t\t\t\tif (turn) {\n\t\t\t\t\t\tturn.status = \"error\";\n\t\t\t\t\t\tturn.notice =\n\t\t\t\t\t\t\tthis.steps >= MAX_MODEL_STEPS\n\t\t\t\t\t\t\t\t? \"Stopped after repeated tool requests. BTW can only answer from its snapshot.\"\n\t\t\t\t\t\t\t\t: \"Context limit reached. Reopen /btw for a new conversation.\";\n\t\t\t\t\t}\n\t\t\t\t\treturn { action: \"end\" };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t});\n\t\tthis.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.running;\n\t}\n\n\t/** A rejected submission stays in the editor and never enters either agent's queue. */\n\tvalidate(text: string): string | undefined {\n\t\tif (this.disposed) return \"This BTW conversation is closed.\";\n\t\tif (this.busy) return \"BTW is still answering. Your question is kept in the editor.\";\n\t\tif (this.turns.length >= MAX_QUESTIONS) return \"BTW conversation limit reached. Reopen /btw to start a new one.\";\n\t\tif (text.length > MAX_QUESTION_CHARS)\n\t\t\treturn `BTW questions are limited to ${MAX_QUESTION_CHARS.toLocaleString()} characters.`;\n\t\tconst question: AgentMessage = { role: \"user\", content: text, timestamp: Date.now() };\n\t\tif (!this.fits([...this.agent.state.messages, question])) {\n\t\t\treturn \"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw.\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tasync ask(text: string): Promise<void> {\n\t\tconst error = this.validate(text);\n\t\tif (error) throw new Error(error);\n\t\tthis.running = true;\n\t\tthis.steps = 0;\n\t\tthis.completedAnswer = \"\";\n\t\tthis.responseChars = 0;\n\t\tconst turn: BtwTurn = {\n\t\t\tquestion: text,\n\t\t\tanswer: \"\",\n\t\t\tthinking: \"\",\n\t\t\tstatus: \"streaming\",\n\t\t\tstartedAt: Date.now(),\n\t\t\telapsedMs: 0,\n\t\t};\n\t\tthis.turns.push(turn);\n\t\tthis.onChange();\n\t\ttry {\n\t\t\tawait this.agent.prompt(text);\n\t\t\tif (turn.status === \"streaming\") {\n\t\t\t\tturn.status = \"done\";\n\t\t\t\tif (!turn.answer) turn.notice = \"The model returned no answer text.\";\n\t\t\t} else if (turn.status === \"cancelling\") {\n\t\t\t\tturn.status = \"cancelled\";\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tturn.status = \"error\";\n\t\t\tturn.notice = displayText(error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\tthis.running = false;\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tif (this.disposed) this.agent.reset();\n\t\t\telse this.onChange();\n\t\t}\n\t}\n\n\tcancel(): void {\n\t\tif (!this.busy || this.disposed) return;\n\t\tconst turn = this.turns.at(-1);\n\t\tif (turn) turn.status = \"cancelling\";\n\t\tthis.agent.abort();\n\t\tthis.onChange();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.unsubscribe();\n\t\tthis.agent.abort();\n\t\tthis.turns.length = 0;\n\t\tif (!this.busy) this.agent.reset();\n\t\t// sessionId is cache affinity shared with main. Never clean up its provider resources here.\n\t}\n\n\tprivate fits(messages: AgentMessage[]): boolean {\n\t\treturn (\n\t\t\testimateContextTokens(\n\t\t\t\tnormalizeContext({\n\t\t\t\t\tsystemPrompt: this.agent.state.systemPrompt,\n\t\t\t\t\ttools: this.agent.state.tools,\n\t\t\t\t\tmessages: messages.filter(\n\t\t\t\t\t\t(message): message is Message =>\n\t\t\t\t\t\t\tmessage.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t).tokens < this.inputBudget\n\t\t);\n\t}\n\n\tprivate handleEvent(event: AgentEvent): void {\n\t\tif (this.disposed) return;\n\t\tconst turn = this.turns.at(-1);\n\t\tif (!turn) return;\n\t\tif ((event.type === \"message_update\" || event.type === \"message_end\") && event.message.role === \"assistant\") {\n\t\t\tconst message = event.message;\n\t\t\tthis.updateAnswer(turn, message);\n\t\t\tif (event.type === \"message_end\") {\n\t\t\t\tthis.completedAnswer = turn.answer;\n\t\t\t\tthis.responseChars += message.content.reduce(\n\t\t\t\t\t(sum, part) =>\n\t\t\t\t\t\tsum +\n\t\t\t\t\t\t(part.type === \"text\"\n\t\t\t\t\t\t\t? part.text.length\n\t\t\t\t\t\t\t: part.type === \"thinking\"\n\t\t\t\t\t\t\t\t? part.thinking.length\n\t\t\t\t\t\t\t\t: JSON.stringify(part.arguments).length),\n\t\t\t\t\t0,\n\t\t\t\t);\n\t\t\t\tthis.blockedTools += message.content.filter((part) => part.type === \"toolCall\").length;\n\t\t\t\tconst usage = message.usage;\n\t\t\t\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\t\t\t\tthis.latestCacheHitPercent =\n\t\t\t\t\t(usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0\n\t\t\t\t\t\t? (usage.cacheRead / promptTokens) * 100\n\t\t\t\t\t\t: undefined;\n\t\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"totalTokens\"] as const)\n\t\t\t\t\tthis.usage[key] += usage[key];\n\t\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const)\n\t\t\t\t\tthis.usage.cost[key] += usage.cost[key];\n\t\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\t\tturn.status = message.stopReason === \"aborted\" ? \"cancelled\" : \"error\";\n\t\t\t\t\tturn.notice ??=\n\t\t\t\t\t\tmessage.stopReason === \"aborted\"\n\t\t\t\t\t\t\t? \"Stopped. You can ask another question.\"\n\t\t\t\t\t\t\t: displayText(message.errorMessage ?? \"The request failed.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tthis.onChange();\n\t\t}\n\t}\n\n\tprivate updateAnswer(turn: BtwTurn, message: AssistantMessage): void {\n\t\tconst text = message.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\");\n\t\tconst thinking = message.content\n\t\t\t.filter((part) => part.type === \"thinking\")\n\t\t\t.map((part) => part.thinking)\n\t\t\t.join(\"\");\n\t\tif (text && turn.firstAnswerMs === undefined) turn.firstAnswerMs = Date.now() - turn.startedAt;\n\t\tturn.answer = displayText([this.completedAnswer, text].filter(Boolean).join(\"\\n\\n\"));\n\t\tturn.thinking = thinking.slice(-2000);\n\t\tif (this.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {\n\t\t\tturn.notice = \"Stopped at the BTW response size limit. You can ask a shorter follow-up.\";\n\t\t\tthis.agent.abort();\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tAgent,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentTool,\n\ttype AgentTurnDecision,\n} from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, Message, Models, Usage } from \"@earendil-works/pi-ai\";\nimport { normalizeContext } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport type { ContextSnapshot } from \"../../core/extensions/index.ts\";\nimport {\n\tMAX_DISPLAY_CHARS,\n\tMAX_MODEL_STEPS,\n\tMAX_OUTPUT_RESERVE_TOKENS,\n\tMAX_QUESTION_CHARS,\n\tMAX_QUESTIONS,\n\tMAX_RESPONSE_CHARS,\n\tTOOL_DENIAL,\n} from \"./constants.ts\";\nimport { createBtwMessages } from \"./snapshot.ts\";\n\nexport interface BtwTurn {\n\tquestion: string;\n\tanswer: string;\n\tthinking: string;\n\tstatus: \"streaming\" | \"cancelling\" | \"done\" | \"cancelled\" | \"error\";\n\tnotice?: string;\n\tstartedAt: number;\n\telapsedMs: number;\n\tfirstAnswerMs?: number;\n}\n\nexport interface BtwConversationState {\n\tbusy: boolean;\n\tturns: readonly BtwTurn[];\n\tusage: Usage;\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools: number;\n}\n\ninterface ActiveQuestion {\n\tturn: BtwTurn;\n\tsteps: number;\n\tcompletedAnswer: string;\n\tresponseChars: number;\n}\n\nfunction emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction displayText(text: string): string {\n\treturn text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\\n\\n[Display truncated]`;\n}\n\n/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */\nexport class BtwAgent implements BtwConversationState {\n\treadonly turns: BtwTurn[] = [];\n\treadonly usage = emptyUsage();\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools = 0;\n\tprivate readonly agent: Agent;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly onChange: () => void;\n\tprivate readonly inputBudget: number;\n\tprivate active?: ActiveQuestion;\n\tprivate disposed = false;\n\n\tconstructor(snapshot: ContextSnapshot, runtime: Pick<Models, \"streamSimple\">, onChange: () => void) {\n\t\tthis.onChange = onChange;\n\t\tconst outputReserve = Math.min(\n\t\t\tMAX_OUTPUT_RESERVE_TOKENS,\n\t\t\tsnapshot.model.maxTokens,\n\t\t\tMath.max(1024, Math.floor(snapshot.model.contextWindow / 8)),\n\t\t);\n\t\t// Leave room for the answer and estimation error; never trim the inherited prefix.\n\t\tthis.inputBudget = snapshot.model.contextWindow - outputReserve - 4096;\n\t\tconst tools: AgentTool[] = snapshot.tools.map((tool) => ({\n\t\t\t...structuredClone(tool),\n\t\t\tlabel: tool.name,\n\t\t\texecute: async () => {\n\t\t\t\t// Defense in depth: these objects never receive an original execute function.\n\t\t\t\tthrow new Error(TOOL_DENIAL);\n\t\t\t},\n\t\t}));\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: snapshot.model,\n\t\t\t\tthinkingLevel: snapshot.thinkingLevel,\n\t\t\t\tsystemPrompt: snapshot.systemPrompt,\n\t\t\t\ttools,\n\t\t\t\tmessages: createBtwMessages(snapshot),\n\t\t\t},\n\t\t\tsessionId: snapshot.streamOptions.sessionId ?? snapshot.sessionId,\n\t\t\ttransport: snapshot.streamOptions.transport,\n\t\t\tthinkingBudgets: snapshot.streamOptions.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: snapshot.streamOptions.maxRetryDelayMs,\n\t\t\tonPayload: snapshot.streamOptions.onPayload,\n\t\t\tonResponse: snapshot.streamOptions.onResponse,\n\t\t\tstreamFn: (model, context, options) =>\n\t\t\t\t// Keep the parent's generation settings as well as its message prefix.\n\t\t\t\t// The model's native output ceiling and our response-size guard still bound output.\n\t\t\t\truntime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),\n\t\t\tbeforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),\n\t\t\tfinishTurn: ({ message, toolResults, context }): AgentTurnDecision | undefined => {\n\t\t\t\tconst question = this.active;\n\t\t\t\t// Error and aborted responses are hard exits; the step budget only counts answered turns.\n\t\t\t\tif (!question || this.disposed || message.stopReason === \"error\" || message.stopReason === \"aborted\")\n\t\t\t\t\treturn undefined;\n\t\t\t\tquestion.steps++;\n\t\t\t\tif (!toolResults.length) return undefined;\n\t\t\t\tif (question.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {\n\t\t\t\t\tquestion.turn.status = \"error\";\n\t\t\t\t\tquestion.turn.notice =\n\t\t\t\t\t\tquestion.steps >= MAX_MODEL_STEPS\n\t\t\t\t\t\t\t? \"Stopped after repeated tool requests. BTW can only answer from its snapshot.\"\n\t\t\t\t\t\t\t: \"Context limit reached. Reopen /btw for a new conversation.\";\n\t\t\t\t\treturn { action: \"end\" };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t});\n\t\tthis.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.active !== undefined;\n\t}\n\n\tprivate validate(text: string): string | undefined {\n\t\tif (this.disposed) return \"This BTW conversation is closed.\";\n\t\tif (this.busy) return \"BTW is still answering. Your question is kept in the editor.\";\n\t\tif (this.turns.length >= MAX_QUESTIONS) return \"BTW conversation limit reached. Reopen /btw to start a new one.\";\n\t\tif (text.length > MAX_QUESTION_CHARS)\n\t\t\treturn `BTW questions are limited to ${MAX_QUESTION_CHARS.toLocaleString()} characters.`;\n\t\tconst question: AgentMessage = { role: \"user\", content: text, timestamp: Date.now() };\n\t\tif (!this.fits([...this.agent.state.messages, question])) {\n\t\t\treturn \"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw.\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */\n\tstartQuestion(text: string): { error: string } | { completion: Promise<void> } {\n\t\tconst error = this.validate(text);\n\t\tif (error) return { error };\n\t\tconst question: ActiveQuestion = {\n\t\t\tturn: {\n\t\t\t\tquestion: text,\n\t\t\t\tanswer: \"\",\n\t\t\t\tthinking: \"\",\n\t\t\t\tstatus: \"streaming\",\n\t\t\t\tstartedAt: Date.now(),\n\t\t\t\telapsedMs: 0,\n\t\t\t},\n\t\t\tsteps: 0,\n\t\t\tcompletedAnswer: \"\",\n\t\t\tresponseChars: 0,\n\t\t};\n\t\tthis.active = question;\n\t\tthis.turns.push(question.turn);\n\t\treturn { completion: this.runQuestion(question) };\n\t}\n\n\tprivate async runQuestion({ turn }: ActiveQuestion): Promise<void> {\n\t\ttry {\n\t\t\tthis.onChange();\n\t\t\tawait this.agent.prompt(turn.question);\n\t\t\tif (turn.status === \"streaming\") {\n\t\t\t\tturn.status = \"done\";\n\t\t\t\tif (!turn.answer) turn.notice = \"The model returned no answer text.\";\n\t\t\t} else if (turn.status === \"cancelling\") {\n\t\t\t\tturn.status = \"cancelled\";\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tturn.status = \"error\";\n\t\t\tturn.notice = displayText(error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\t// Cancellation remains busy until the native Agent has fully settled.\n\t\t\tthis.active = undefined;\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tif (this.disposed) this.agent.reset();\n\t\t\telse this.onChange();\n\t\t}\n\t}\n\n\tcancel(): void {\n\t\tif (!this.active || this.disposed) return;\n\t\tthis.active.turn.status = \"cancelling\";\n\t\tthis.agent.abort();\n\t\tthis.onChange();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.unsubscribe();\n\t\tthis.agent.abort();\n\t\tthis.turns.length = 0;\n\t\tif (!this.busy) this.agent.reset();\n\t\t// sessionId is cache affinity shared with main. Never clean up its provider resources here.\n\t}\n\n\tprivate fits(messages: AgentMessage[]): boolean {\n\t\treturn (\n\t\t\testimateContextTokens(\n\t\t\t\tnormalizeContext({\n\t\t\t\t\tsystemPrompt: this.agent.state.systemPrompt,\n\t\t\t\t\ttools: this.agent.state.tools,\n\t\t\t\t\tmessages: messages.filter(\n\t\t\t\t\t\t(message): message is Message =>\n\t\t\t\t\t\t\tmessage.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t).tokens < this.inputBudget\n\t\t);\n\t}\n\n\tprivate handleEvent(event: AgentEvent): void {\n\t\tconst question = this.active;\n\t\tif (\n\t\t\tthis.disposed ||\n\t\t\t!question ||\n\t\t\t(event.type !== \"message_update\" && event.type !== \"message_end\") ||\n\t\t\tevent.message.role !== \"assistant\"\n\t\t)\n\t\t\treturn;\n\t\tconst { turn } = question;\n\t\tconst message = event.message;\n\t\tthis.updateAnswer(question, message);\n\t\tif (event.type === \"message_end\") {\n\t\t\tquestion.completedAnswer = turn.answer;\n\t\t\tquestion.responseChars += message.content.reduce(\n\t\t\t\t(sum, part) =>\n\t\t\t\t\tsum +\n\t\t\t\t\t(part.type === \"text\"\n\t\t\t\t\t\t? part.text.length\n\t\t\t\t\t\t: part.type === \"thinking\"\n\t\t\t\t\t\t\t? part.thinking.length\n\t\t\t\t\t\t\t: JSON.stringify(part.arguments).length),\n\t\t\t\t0,\n\t\t\t);\n\t\t\tthis.blockedTools += message.content.filter((part) => part.type === \"toolCall\").length;\n\t\t\tconst usage = message.usage;\n\t\t\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\t\t\tthis.latestCacheHitPercent =\n\t\t\t\t(usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0\n\t\t\t\t\t? (usage.cacheRead / promptTokens) * 100\n\t\t\t\t\t: undefined;\n\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"totalTokens\"] as const)\n\t\t\t\tthis.usage[key] += usage[key];\n\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const)\n\t\t\t\tthis.usage.cost[key] += usage.cost[key];\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\tturn.status = message.stopReason === \"aborted\" ? \"cancelled\" : \"error\";\n\t\t\t\tturn.notice ??=\n\t\t\t\t\tmessage.stopReason === \"aborted\"\n\t\t\t\t\t\t? \"Stopped. You can ask another question.\"\n\t\t\t\t\t\t: displayText(message.errorMessage ?? \"The request failed.\");\n\t\t\t}\n\t\t}\n\t\tthis.onChange();\n\t}\n\n\tprivate updateAnswer(question: ActiveQuestion, message: AssistantMessage): void {\n\t\tconst { turn } = question;\n\t\tconst text = message.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\");\n\t\tconst thinking = message.content\n\t\t\t.filter((part) => part.type === \"thinking\")\n\t\t\t.map((part) => part.thinking)\n\t\t\t.join(\"\");\n\t\tif (text && turn.firstAnswerMs === undefined) turn.firstAnswerMs = Date.now() - turn.startedAt;\n\t\tturn.answer = displayText([question.completedAnswer, text].filter(Boolean).join(\"\\n\\n\"));\n\t\tturn.thinking = thinking.slice(-2000);\n\t\tif (question.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {\n\t\t\tturn.notice = \"Stopped at the BTW response size limit. You can ask a shorter follow-up.\";\n\t\t\tthis.agent.abort();\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/controller.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/controller.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAY1F,4FAA4F;AAC5F,qBAAa,aAAa;IACzB,OAAO,CAAC,OAAO,CAAC,CAAe;IAEzB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwDlE,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAU9G,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,MAAM;IAmBd,OAAO,CAAC,SAAS;CAgCjB"}
|