@code-yeongyu/senpi 2026.9.23-5 → 2026.9.24-2
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 +51 -0
- package/dist/bundle/chunks/{anthropic-messages-77YBORJ5.js → anthropic-messages-UPLQFNTT.js} +2 -2
- package/dist/bundle/chunks/{app-server-command-BGT65PGC.js → app-server-command-UHPJ2C4D.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-PSESFNHN.js → azure-openai-responses-XAR2E66I.js} +1 -1
- package/dist/bundle/chunks/{chunk-WXIRFRXY.js → chunk-2PLPSKHD.js} +1 -1
- package/dist/bundle/chunks/{chunk-7PANH3NB.js → chunk-3WBSBDBX.js} +1 -1
- package/dist/bundle/chunks/{chunk-BBOQ5H4W.js → chunk-6WBYI25N.js} +1 -1
- package/dist/bundle/chunks/{chunk-RG3UEFSF.js → chunk-7DY7UYLL.js} +1 -1
- package/dist/bundle/chunks/{chunk-VKBY4F76.js → chunk-BSOJHK4W.js} +1 -1
- package/dist/bundle/chunks/{chunk-3XHWW7SQ.js → chunk-CLZVNQW3.js} +1 -1
- package/dist/bundle/chunks/{chunk-ORCF262V.js → chunk-EJKCBRYK.js} +3 -3
- package/dist/bundle/chunks/chunk-J7IUURQ6.js +8 -0
- package/dist/bundle/chunks/{chunk-PSMTQDII.js → chunk-JRQSHZPP.js} +15 -9
- package/dist/bundle/chunks/{chunk-DUV3UFKX.js → chunk-MKAM7IRH.js} +1 -1
- package/dist/bundle/chunks/chunk-MO2U7YRX.js +11 -0
- package/dist/bundle/chunks/{chunk-ZEFQYQOU.js → chunk-NGHOUIPR.js} +1 -1
- package/dist/bundle/chunks/{chunk-XDSQYM4F.js → chunk-NKVUDCGZ.js} +2 -2
- package/dist/bundle/chunks/{chunk-J3QXPP4T.js → chunk-ONR57UMO.js} +1 -1
- package/dist/bundle/chunks/{chunk-TQDWU3ZQ.js → chunk-SYQVC7UM.js} +1 -1
- package/dist/bundle/chunks/chunk-TTHMOL5G.js +2 -0
- package/dist/bundle/chunks/{chunk-NNHFMZD5.js → chunk-UBPMXBOJ.js} +1 -1
- package/dist/bundle/chunks/chunk-WASCMT6Y.js +2 -0
- package/dist/bundle/chunks/{chunk-EN6KDFY2.js → chunk-WISJJQ4K.js} +1 -1
- package/dist/bundle/chunks/{chunk-IVYZMSFY.js → chunk-WL5EQYNL.js} +1 -1
- package/dist/bundle/chunks/{chunk-LC6SZTVE.js → chunk-WTSAB6AE.js} +1 -1
- package/dist/bundle/chunks/{chunk-HKE42SWX.js → chunk-Y54V65MS.js} +1 -1
- package/dist/bundle/chunks/{chunk-3RN6BFG2.js → chunk-YBC274GY.js} +4 -4
- package/dist/bundle/chunks/{chunk-RRSND33J.js → chunk-YKU45B65.js} +54 -54
- package/dist/bundle/chunks/{chunk-WUYBEF7C.js → chunk-YWO3OBYK.js} +1 -1
- package/dist/bundle/chunks/cli-main-O5Y3TBID.js +3 -0
- package/dist/bundle/chunks/{google-generative-ai-YJHSZAY5.js → google-generative-ai-B5QMFONL.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-JTFWEDNJ.js → google-vertex-O2TGMVWF.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-QXVCHTP3.js → help-fast-path-Y33OIZBU.js} +1 -1
- package/dist/bundle/chunks/{host-command-3PUZYQOK.js → host-command-WJOL27Q7.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-OHPSU5VU.js → host-lifecycle-YBFXYFZP.js} +1 -1
- package/dist/bundle/chunks/{interactive-host-runtime-57LEAJPU.js → interactive-host-runtime-XVTF3NUD.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-OO3NGM4G.js +2 -0
- package/dist/bundle/chunks/{list-tips-Z62FXPOJ.js → list-tips-EBRNBPBM.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-VJPMPQ5T.js → mistral-conversations-AS3SAWPA.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-GFSDQQUJ.js → multi-session-host-6MKBBOKF.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-IQ35QACK.js → openai-codex-responses-CK7T4WNM.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-74OLE55U.js → openai-completions-OPQKN7FH.js} +3 -3
- package/dist/bundle/chunks/openai-responses-QHWM3KPO.js +2 -0
- package/dist/bundle/chunks/{openrouter-images-T4GY3JYM.js → openrouter-images-MW5TXV7L.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-J7244EJE.js → package-manager-cli-BMEWLAI2.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-CZT4TRPD.js → rotation-stream-ZFA6ELXJ.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-75CRTY24.js → rpc-mode-5653CV65.js} +1 -1
- package/dist/bundle/chunks/{session-picker-ZIBANFBQ.js → session-picker-PPYK56TA.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +265 -259
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +13 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +28 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +75 -12
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/dynamic-prompt/build.d.ts +6 -1
- package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
- package/dist/core/dynamic-prompt/build.js +0 -7
- package/dist/core/dynamic-prompt/build.js.map +1 -1
- package/dist/core/environment-context.d.ts +32 -0
- package/dist/core/environment-context.d.ts.map +1 -0
- package/dist/core/environment-context.js +63 -0
- package/dist/core/environment-context.js.map +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-sync.d.ts.map +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/session-sync.js +1 -15
- package/dist/core/extensions/builtin/anthropic-subscription/session-sync.js.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm-renderer.js +3 -0
- package/dist/core/extensions/builtin/goal/cache-warm-renderer.js.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm.d.ts +19 -2
- package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/cache-warm.js +28 -2
- package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
- package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/monitor-continuation.js +4 -2
- package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
- package/dist/core/extensions/builtin/goal/parked-wait.js +2 -0
- package/dist/core/extensions/builtin/goal/parked-wait.js.map +1 -1
- package/dist/core/extensions/builtin/goal/prompt.js +1 -1
- package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/herdr/herdr-state.d.ts +5 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.d.ts.map +1 -1
- package/dist/core/extensions/builtin/herdr/herdr-state.js +28 -3
- package/dist/core/extensions/builtin/herdr/herdr-state.js.map +1 -1
- package/dist/core/extensions/builtin/herdr/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/herdr/index.js +7 -1
- package/dist/core/extensions/builtin/herdr/index.js.map +1 -1
- package/dist/core/extensions/builtin/hooks/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/hooks/index.js +3 -15
- package/dist/core/extensions/builtin/hooks/index.js.map +1 -1
- package/dist/core/extensions/builtin/hooks/stop-lifecycle.d.ts +26 -0
- package/dist/core/extensions/builtin/hooks/stop-lifecycle.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/stop-lifecycle.js +88 -0
- package/dist/core/extensions/builtin/hooks/stop-lifecycle.js.map +1 -0
- package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.js +28 -10
- package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
- package/dist/core/extensions/builtin/rules/commands.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/commands.js +5 -1
- package/dist/core/extensions/builtin/rules/commands.js.map +1 -1
- package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/index.js +25 -3
- package/dist/core/extensions/builtin/rules/index.js.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/constants.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/constants.js +22 -14
- package/dist/core/extensions/builtin/rules/rules/constants.js.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/engine.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/engine.js +39 -9
- package/dist/core/extensions/builtin/rules/rules/engine.js.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/finder.js +3 -0
- package/dist/core/extensions/builtin/rules/rules/finder.js.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/project-root.d.ts +17 -0
- package/dist/core/extensions/builtin/rules/rules/project-root.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/project-root.js +67 -5
- package/dist/core/extensions/builtin/rules/rules/project-root.js.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/types.d.ts +2 -2
- package/dist/core/extensions/builtin/rules/rules/types.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/rules/types.js.map +1 -1
- package/dist/core/extensions/builtin/rules/ui/rules-banner.d.ts +3 -1
- package/dist/core/extensions/builtin/rules/ui/rules-banner.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/ui/rules-banner.js +1 -1
- package/dist/core/extensions/builtin/rules/ui/rules-banner.js.map +1 -1
- package/dist/core/extensions/builtin/todotools/todo-storage.d.ts.map +1 -1
- package/dist/core/extensions/builtin/todotools/todo-storage.js +10 -2
- package/dist/core/extensions/builtin/todotools/todo-storage.js.map +1 -1
- package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -1
- package/dist/core/extensions/builtin/todotools/tools/todo.js +2 -1
- package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/config.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/config.js +2 -0
- package/dist/core/extensions/builtin/websearch/websearch/config.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js +2 -0
- package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.d.ts +3 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.d.ts.map +1 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.js +34 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.js.map +1 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.d.ts +3 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.d.ts.map +1 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.js +22 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.js.map +1 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/providers.js +4 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
- package/dist/core/session-discovery.d.ts +9 -3
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +19 -8
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +8 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-summary-cache.d.ts +16 -3
- package/dist/core/session-summary-cache.d.ts.map +1 -1
- package/dist/core/session-summary-cache.js +19 -3
- package/dist/core/session-summary-cache.js.map +1 -1
- package/dist/core/session-summary-index-file.d.ts +38 -0
- package/dist/core/session-summary-index-file.d.ts.map +1 -0
- package/dist/core/session-summary-index-file.js +119 -0
- package/dist/core/session-summary-index-file.js.map +1 -0
- package/dist/core/session-summary-index.d.ts +52 -0
- package/dist/core/session-summary-index.d.ts.map +1 -0
- package/dist/core/session-summary-index.js +157 -0
- package/dist/core/session-summary-index.js.map +1 -0
- package/dist/core/session-summary.d.ts +21 -2
- package/dist/core/session-summary.d.ts.map +1 -1
- package/dist/core/session-summary.js +53 -14
- package/dist/core/session-summary.js.map +1 -1
- package/dist/core/timings.d.ts +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/renderers/read.d.ts.map +1 -1
- package/dist/core/tools/renderers/read.js +7 -2
- package/dist/core/tools/renderers/read.js.map +1 -1
- package/dist/core/tools/renderers/skill-read-path.d.ts +9 -0
- package/dist/core/tools/renderers/skill-read-path.d.ts.map +1 -0
- package/dist/core/tools/renderers/skill-read-path.js +49 -0
- package/dist/core/tools/renderers/skill-read-path.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/exploration-call.d.ts +1 -1
- package/dist/modes/interactive/components/exploration-call.d.ts.map +1 -1
- package/dist/modes/interactive/components/exploration-call.js +3 -1
- package/dist/modes/interactive/components/exploration-call.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +32 -16
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-tree.d.ts +32 -0
- package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-tree.js +82 -0
- package/dist/modes/interactive/components/session-selector-tree.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +6 -71
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +32 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +8 -4
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/AGENTS.md +1 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/code-preview.ts +31 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-code.ts +34 -131
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js-ast.ts +65 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js-layout.ts +90 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js-mask.ts +178 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js.ts +100 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-python-script.ts +127 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-python.ts +150 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-request.ts +18 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +9 -25
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +16 -9
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +22 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +3 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.d.ts +6 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.js +6 -19
- package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +8 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-references.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-references.js +8 -35
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-references.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +10 -6
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +4 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +53 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.d.ts +17 -0
- package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.js +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/chatgpt-subscription.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js +71 -14
- package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.d.ts +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.js +71 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts +5 -0
- package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +7 -2
- package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/bundle/chunks/chunk-KLDLZHHS.js +0 -11
- package/dist/bundle/chunks/chunk-LTIMMSDM.js +0 -8
- package/dist/bundle/chunks/chunk-XYM54ZWK.js +0 -2
- package/dist/bundle/chunks/cli-main-W55CWPEI.js +0 -3
- package/dist/bundle/chunks/interactive-mode-EDJZ4CSY.js +0 -2
- package/dist/bundle/chunks/openai-responses-7IGZSW33.js +0 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { isRecord, parseFile, type SourceNode } from "./display-js-ast.ts";
|
|
2
|
+
import { finishLayout } from "./display-js-layout.ts";
|
|
3
|
+
import { maskSource, restoreComments, restoreValues } from "./display-js-mask.ts";
|
|
4
|
+
|
|
5
|
+
// Bun.Transpiler is a transpiler, not a formatter: printed directly it rewrites literals ("a\nb"
|
|
6
|
+
// becomes a multi-line template, 0xff becomes 255, emoji become escapes), folds `typeof
|
|
7
|
+
// undefined`, and drops comments and directives. It only ever lays out a masked cell here, and the
|
|
8
|
+
// original text is substituted back; a cell that cannot be restored exactly is shown as sent.
|
|
9
|
+
const INDENT = " ";
|
|
10
|
+
|
|
11
|
+
export type JsPrinter = (code: string) => string;
|
|
12
|
+
|
|
13
|
+
let bunPrinter: JsPrinter | null | undefined;
|
|
14
|
+
|
|
15
|
+
function resolveBunPrinter(): JsPrinter | null {
|
|
16
|
+
if (typeof process.versions.bun !== "string") return null;
|
|
17
|
+
const bun: unknown = Reflect.get(globalThis, "Bun");
|
|
18
|
+
if (!isRecord(bun) || typeof bun.Transpiler !== "function") return null;
|
|
19
|
+
const transpiler: unknown = Reflect.construct(bun.Transpiler, [
|
|
20
|
+
{ loader: "js", trimUnusedImports: false, deadCodeElimination: false, inline: false },
|
|
21
|
+
]);
|
|
22
|
+
if (!isRecord(transpiler) || typeof transpiler.transformSync !== "function") return null;
|
|
23
|
+
const transformSync = transpiler.transformSync;
|
|
24
|
+
return (code) => {
|
|
25
|
+
const output: unknown = Reflect.apply(transformSync, transpiler, [code]);
|
|
26
|
+
if (typeof output !== "string") throw new TypeError("Bun.Transpiler.transformSync returned a non-string");
|
|
27
|
+
return output;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The built-in Bun printer when this renderer runs on Bun; null on Node. */
|
|
32
|
+
export function bunJsPrinter(): JsPrinter | null {
|
|
33
|
+
if (bunPrinter === undefined) bunPrinter = resolveBunPrinter();
|
|
34
|
+
return bunPrinter;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function layout(masked: string, prefix: string, print: JsPrinter): string | undefined {
|
|
38
|
+
try {
|
|
39
|
+
return print(masked).trim();
|
|
40
|
+
} catch {
|
|
41
|
+
// Module syntax only parses unwrapped; the kernel's top-level `return` only inside a function.
|
|
42
|
+
}
|
|
43
|
+
const header = `async function ${prefix}cell() {`;
|
|
44
|
+
let lines: string[];
|
|
45
|
+
try {
|
|
46
|
+
lines = print(`${header}\n${masked}\n}`).trim().split("\n");
|
|
47
|
+
} catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
if (lines[0] !== header || lines.at(-1) !== "}") return undefined;
|
|
51
|
+
return lines
|
|
52
|
+
.slice(1, -1)
|
|
53
|
+
.map((line) => (line.startsWith(INDENT) ? line.slice(INDENT.length) : line))
|
|
54
|
+
.join("\n");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function sameTokens(left: string, right: string): boolean {
|
|
58
|
+
const strip = (text: string) => text.replace(/[\s;,()]/gu, "");
|
|
59
|
+
return strip(left) === strip(right);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const POSITION_KEYS = new Set([
|
|
63
|
+
"start",
|
|
64
|
+
"end",
|
|
65
|
+
"loc",
|
|
66
|
+
"range",
|
|
67
|
+
"extra",
|
|
68
|
+
"leadingComments",
|
|
69
|
+
"trailingComments",
|
|
70
|
+
"innerComments",
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
// Positions, raw spellings, and parenthesization flags aside, the preview must be the same program:
|
|
74
|
+
// the character guard alone cannot see a dropped `(`, which can change how an expression groups.
|
|
75
|
+
function programSignature(file: SourceNode): string {
|
|
76
|
+
return JSON.stringify({ program: file.record.program, comments: file.record.comments }, (key, value: unknown) => {
|
|
77
|
+
if (POSITION_KEYS.has(key)) return undefined;
|
|
78
|
+
if (typeof value === "bigint") return `${value}n`;
|
|
79
|
+
// A stray `;` in a statement list is a no-op the printer drops.
|
|
80
|
+
return Array.isArray(value) ? value.filter((item) => !isRecord(item) || item.type !== "EmptyStatement") : value;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function sameProgram(original: SourceNode, preview: string): boolean {
|
|
85
|
+
const reparsed = parseFile(preview);
|
|
86
|
+
return reparsed !== undefined && programSignature(reparsed) === programSignature(original);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The printer's layout of `code` with its literal, name, and comment text intact, or undefined. */
|
|
90
|
+
export function prettifyJs(code: string, print: JsPrinter): string | undefined {
|
|
91
|
+
const file = parseFile(code);
|
|
92
|
+
if (file === undefined) return undefined;
|
|
93
|
+
const mask = maskSource(code, file);
|
|
94
|
+
if (mask === undefined) return undefined;
|
|
95
|
+
const printed = layout(mask.masked, mask.prefix, print);
|
|
96
|
+
const withComments = printed === undefined ? undefined : restoreComments(printed, mask.comments);
|
|
97
|
+
const restored = withComments === undefined ? undefined : restoreValues(withComments, mask);
|
|
98
|
+
const finished = restored === undefined ? undefined : finishLayout(restored);
|
|
99
|
+
return finished !== undefined && sameTokens(finished, code) && sameProgram(file, finished) ? finished : undefined;
|
|
100
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Runs in the user's own Python interpreter: `python -c <script> <ruff timeout s> <strategies...>` with the cell on
|
|
2
|
+
// stdin, printing {"via", "code"} as JSON. A strategy's output is kept only when it parses to the same
|
|
3
|
+
// AST as the source and keeps every string, number, and comment token's text (senpi#2076).
|
|
4
|
+
export const PYTHON_FORMATTER_SCRIPT = [
|
|
5
|
+
"import ast, io, json, re, shutil, subprocess, sys, tokenize",
|
|
6
|
+
"",
|
|
7
|
+
"def emit(via, code):",
|
|
8
|
+
" sys.stdout.write(json.dumps({'via': via, 'code': code}))",
|
|
9
|
+
" sys.exit(0)",
|
|
10
|
+
"",
|
|
11
|
+
"RUFF_TIMEOUT = float(sys.argv[1])",
|
|
12
|
+
"FLAGS = ast.PyCF_ONLY_AST | getattr(ast, 'PyCF_ALLOW_TOP_LEVEL_AWAIT', 0)",
|
|
13
|
+
"",
|
|
14
|
+
"def parse(text):",
|
|
15
|
+
" return compile(text, '<cell>', 'exec', flags=FLAGS, dont_inherit=True)",
|
|
16
|
+
"",
|
|
17
|
+
"def literal_texts(text):",
|
|
18
|
+
" kinds = {tokenize.STRING, tokenize.NUMBER, tokenize.COMMENT} | token_kinds('FSTRING_MIDDLE', 'TSTRING_MIDDLE')",
|
|
19
|
+
" return [t.string for t in tokenize.generate_tokens(io.StringIO(text).readline) if t.type in kinds]",
|
|
20
|
+
"",
|
|
21
|
+
"def equivalent(source, formatted):",
|
|
22
|
+
" try:",
|
|
23
|
+
" same_tree = ast.dump(parse(source)) == ast.dump(parse(formatted))",
|
|
24
|
+
" return same_tree and literal_texts(source) == literal_texts(formatted)",
|
|
25
|
+
" except (SyntaxError, ValueError, tokenize.TokenError):",
|
|
26
|
+
" return False",
|
|
27
|
+
"",
|
|
28
|
+
"def ruff_binary():",
|
|
29
|
+
" found = shutil.which('ruff')",
|
|
30
|
+
" if found:",
|
|
31
|
+
" return found",
|
|
32
|
+
" try:",
|
|
33
|
+
" from ruff.__main__ import find_ruff_bin",
|
|
34
|
+
" return find_ruff_bin()",
|
|
35
|
+
" except Exception:",
|
|
36
|
+
" return None",
|
|
37
|
+
"",
|
|
38
|
+
"def with_ruff(source):",
|
|
39
|
+
" binary = ruff_binary()",
|
|
40
|
+
" if not binary:",
|
|
41
|
+
" return None",
|
|
42
|
+
" args = [binary, 'format', '--quiet', '--no-cache', '--config', \"format.quote-style = 'preserve'\",",
|
|
43
|
+
" '--stdin-filename', 'cell.py', '-']",
|
|
44
|
+
" try:",
|
|
45
|
+
" done = subprocess.run(args, input=source, capture_output=True, text=True, timeout=RUFF_TIMEOUT)",
|
|
46
|
+
" except Exception:",
|
|
47
|
+
" return None",
|
|
48
|
+
" return done.stdout if done.returncode == 0 else None",
|
|
49
|
+
"",
|
|
50
|
+
"def with_black(source):",
|
|
51
|
+
" try:",
|
|
52
|
+
" import black",
|
|
53
|
+
" return black.format_str(source, mode=black.Mode(string_normalization=False))",
|
|
54
|
+
" except Exception:",
|
|
55
|
+
" return None",
|
|
56
|
+
"",
|
|
57
|
+
"def token_kinds(*names):",
|
|
58
|
+
" return {getattr(tokenize, name) for name in names if hasattr(tokenize, name)}",
|
|
59
|
+
"",
|
|
60
|
+
"def literal_spans(source):",
|
|
61
|
+
" tokens = list(tokenize.generate_tokens(io.StringIO(source).readline))",
|
|
62
|
+
" starts = [0]",
|
|
63
|
+
" for line in source.splitlines(keepends=True):",
|
|
64
|
+
" starts.append(starts[-1] + len(line))",
|
|
65
|
+
" offset = lambda position: starts[position[0] - 1] + position[1]",
|
|
66
|
+
" opening, closing = token_kinds('FSTRING_START', 'TSTRING_START'), token_kinds('FSTRING_END', 'TSTRING_END')",
|
|
67
|
+
" spans, depth = [], 0",
|
|
68
|
+
" for token in tokens:",
|
|
69
|
+
" if token.type == tokenize.COMMENT:",
|
|
70
|
+
" return None",
|
|
71
|
+
" if depth:",
|
|
72
|
+
" depth += 1 if token.type in opening else -1 if token.type in closing else 0",
|
|
73
|
+
" if depth == 0:",
|
|
74
|
+
" spans[-1][1] = offset(token.end)",
|
|
75
|
+
" continue",
|
|
76
|
+
" is_string = token.type == tokenize.STRING or token.type in opening",
|
|
77
|
+
" if not is_string and token.type != tokenize.NUMBER:",
|
|
78
|
+
" continue",
|
|
79
|
+
" start, end = offset(token.start), offset(token.end)",
|
|
80
|
+
" joined = spans and spans[-1][2] and is_string and not re.sub(r'[\\s\\\\]', '', source[spans[-1][1]:start])",
|
|
81
|
+
" if joined:",
|
|
82
|
+
" spans[-1][1] = end",
|
|
83
|
+
" else:",
|
|
84
|
+
" spans.append([start, end, is_string])",
|
|
85
|
+
" if token.type in opening:",
|
|
86
|
+
" depth = 1",
|
|
87
|
+
" return spans",
|
|
88
|
+
"",
|
|
89
|
+
"def with_ast(source):",
|
|
90
|
+
" if not hasattr(ast, 'unparse'):",
|
|
91
|
+
" return None",
|
|
92
|
+
" try:",
|
|
93
|
+
" spans = literal_spans(source)",
|
|
94
|
+
" except (tokenize.TokenError, SyntaxError):",
|
|
95
|
+
" return None",
|
|
96
|
+
" if spans is None:",
|
|
97
|
+
" return None",
|
|
98
|
+
" prefix = '_display'",
|
|
99
|
+
" while prefix in source:",
|
|
100
|
+
" prefix += '_'",
|
|
101
|
+
" raws, masked, cursor = {}, [], 0",
|
|
102
|
+
" for index, (start, end, _) in enumerate(spans):",
|
|
103
|
+
" name = prefix + str(index)",
|
|
104
|
+
" raws[name] = source[start:end]",
|
|
105
|
+
" masked.append(source[cursor:start] + name)",
|
|
106
|
+
" cursor = end",
|
|
107
|
+
" masked.append(source[cursor:])",
|
|
108
|
+
" try:",
|
|
109
|
+
" tree = parse(''.join(masked))",
|
|
110
|
+
" except (SyntaxError, ValueError):",
|
|
111
|
+
" return None",
|
|
112
|
+
" seen = []",
|
|
113
|
+
" def restore(match):",
|
|
114
|
+
" seen.append(match.group(0))",
|
|
115
|
+
" return raws.get(match.group(0), match.group(0))",
|
|
116
|
+
" text = re.sub(r'\\b' + re.escape(prefix) + r'\\d+\\b', restore, ast.unparse(tree))",
|
|
117
|
+
" return text if sorted(seen) == sorted(raws) else None",
|
|
118
|
+
"",
|
|
119
|
+
"STRATEGIES = {'ruff': with_ruff, 'black': with_black, 'ast': with_ast}",
|
|
120
|
+
"source = sys.stdin.read()",
|
|
121
|
+
"for name in sys.argv[2:]:",
|
|
122
|
+
" strategy = STRATEGIES.get(name)",
|
|
123
|
+
" formatted = strategy(source) if strategy else None",
|
|
124
|
+
" if formatted is not None and equivalent(source, formatted):",
|
|
125
|
+
" emit(name, formatted.rstrip('\\n'))",
|
|
126
|
+
"emit('none', source)",
|
|
127
|
+
].join("\n");
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createInterpreterDetector } from "../interpreters/detect.ts";
|
|
3
|
+
import { PYTHON_FORMATTER_SCRIPT } from "./display-python-script.ts";
|
|
4
|
+
|
|
5
|
+
export type PythonStrategy = "ruff" | "black" | "ast";
|
|
6
|
+
export type PythonInvocation = { readonly command: string; readonly args: readonly string[] };
|
|
7
|
+
|
|
8
|
+
export interface PythonFormatOptions {
|
|
9
|
+
readonly strategies: readonly PythonStrategy[];
|
|
10
|
+
readonly timeoutMs: number;
|
|
11
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface PythonDisplayOptions extends PythonFormatOptions {
|
|
15
|
+
readonly interpreter: () => Promise<PythonInvocation | null>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PythonDisplay {
|
|
19
|
+
/**
|
|
20
|
+
* The formatted cell once it is known, otherwise the cell as sent. With `onFormatted`, a missing
|
|
21
|
+
* result is formatted in the background and `onFormatted` runs when a formatted cell is ready.
|
|
22
|
+
*/
|
|
23
|
+
display(code: string, onFormatted?: () => void): string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DEFAULT_STRATEGIES: readonly PythonStrategy[] = ["ruff", "black", "ast"];
|
|
27
|
+
const FORMAT_TIMEOUT_MS = 5_000;
|
|
28
|
+
const MAX_CONCURRENT_FORMATTERS = 2;
|
|
29
|
+
const CACHE_LIMIT = 64;
|
|
30
|
+
|
|
31
|
+
function formattedCode(stdout: string): string | undefined {
|
|
32
|
+
try {
|
|
33
|
+
const parsed: unknown = JSON.parse(stdout);
|
|
34
|
+
if (parsed === null || typeof parsed !== "object" || !("code" in parsed)) return undefined;
|
|
35
|
+
return typeof parsed.code === "string" ? parsed.code : undefined;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (error instanceof SyntaxError) return undefined;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ruff runs inside the formatter process, so it gets most of the caller's budget and never outlives it.
|
|
43
|
+
function ruffTimeoutSeconds(timeoutMs: number): string {
|
|
44
|
+
return String(Math.max(1, timeoutMs - 1_000) / 1_000);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function formatPythonCell(
|
|
48
|
+
code: string,
|
|
49
|
+
invocation: PythonInvocation,
|
|
50
|
+
options: PythonFormatOptions,
|
|
51
|
+
): Promise<string | undefined> {
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
const child = spawn(
|
|
54
|
+
invocation.command,
|
|
55
|
+
[
|
|
56
|
+
...invocation.args,
|
|
57
|
+
"-c",
|
|
58
|
+
PYTHON_FORMATTER_SCRIPT,
|
|
59
|
+
ruffTimeoutSeconds(options.timeoutMs),
|
|
60
|
+
...options.strategies,
|
|
61
|
+
],
|
|
62
|
+
{
|
|
63
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
64
|
+
timeout: options.timeoutMs,
|
|
65
|
+
windowsHide: true,
|
|
66
|
+
...(options.env === undefined ? {} : { env: options.env }),
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
let stdout = "";
|
|
70
|
+
child.stdout.setEncoding("utf8");
|
|
71
|
+
child.stdout.on("data", (chunk: string) => {
|
|
72
|
+
stdout += chunk;
|
|
73
|
+
});
|
|
74
|
+
child.on("error", () => resolve(undefined));
|
|
75
|
+
child.on("close", (exitCode) => resolve(exitCode === 0 ? formattedCode(stdout) : undefined));
|
|
76
|
+
child.stdin.on("error", () => resolve(undefined));
|
|
77
|
+
child.stdin.end(code);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function createPythonDisplay(options: PythonDisplayOptions): PythonDisplay {
|
|
82
|
+
const settled = new Map<string, string>();
|
|
83
|
+
const listeners = new Map<string, Set<() => void>>();
|
|
84
|
+
const queue: string[] = [];
|
|
85
|
+
let running = 0;
|
|
86
|
+
|
|
87
|
+
const remember = (code: string, formatted: string) => {
|
|
88
|
+
if (settled.size >= CACHE_LIMIT) settled.delete(settled.keys().next().value ?? "");
|
|
89
|
+
settled.set(code, formatted);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const format = async (code: string): Promise<string | undefined> => {
|
|
93
|
+
const invocation = await options.interpreter();
|
|
94
|
+
return invocation === null ? undefined : formatPythonCell(code, invocation, options);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const pump = () => {
|
|
98
|
+
while (running < MAX_CONCURRENT_FORMATTERS) {
|
|
99
|
+
const code = queue.shift();
|
|
100
|
+
if (code === undefined) return;
|
|
101
|
+
running += 1;
|
|
102
|
+
void format(code)
|
|
103
|
+
.catch(() => undefined)
|
|
104
|
+
.then((formatted) => {
|
|
105
|
+
remember(code, formatted ?? code);
|
|
106
|
+
const waiting = listeners.get(code);
|
|
107
|
+
listeners.delete(code);
|
|
108
|
+
if (formatted !== undefined && formatted !== code) for (const listener of waiting ?? []) listener();
|
|
109
|
+
})
|
|
110
|
+
.finally(() => {
|
|
111
|
+
running -= 1;
|
|
112
|
+
pump();
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
display(code, onFormatted) {
|
|
119
|
+
const known = settled.get(code);
|
|
120
|
+
if (known !== undefined || onFormatted === undefined) return known ?? code;
|
|
121
|
+
const waiting = listeners.get(code);
|
|
122
|
+
if (waiting !== undefined) {
|
|
123
|
+
waiting.add(onFormatted);
|
|
124
|
+
return code;
|
|
125
|
+
}
|
|
126
|
+
listeners.set(code, new Set([onFormatted]));
|
|
127
|
+
queue.push(code);
|
|
128
|
+
pump();
|
|
129
|
+
return code;
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function detectedPython(): Promise<PythonInvocation | null> {
|
|
135
|
+
const detected = await createInterpreterDetector().detect("py");
|
|
136
|
+
if (!detected.ok) return null;
|
|
137
|
+
const [command, ...args] = detected.path.split(" ");
|
|
138
|
+
return command === undefined ? null : { command, args };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let userPython: Promise<PythonInvocation | null> | undefined;
|
|
142
|
+
|
|
143
|
+
export const pythonDisplay: PythonDisplay = createPythonDisplay({
|
|
144
|
+
interpreter: () => {
|
|
145
|
+
userPython ??= detectedPython();
|
|
146
|
+
return userPython;
|
|
147
|
+
},
|
|
148
|
+
strategies: DEFAULT_STRATEGIES,
|
|
149
|
+
timeoutMs: FORMAT_TIMEOUT_MS,
|
|
150
|
+
});
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@code-yeongyu/senpi";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
type EvalControlInput,
|
|
4
|
+
type EvalLanguage,
|
|
5
|
+
type EvalToolInput,
|
|
6
|
+
type EvalToolRequest,
|
|
7
|
+
evalLanguageOrder,
|
|
8
|
+
} from "./types.ts";
|
|
3
9
|
|
|
4
10
|
const NON_INTERACTIVE_MODES = new Set(["print", "json"]);
|
|
5
11
|
|
|
@@ -11,7 +17,10 @@ export function normalizeEvalSummary(value: unknown): string | undefined {
|
|
|
11
17
|
return normalized.length === 0 ? undefined : normalized;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
export function parseEvalRequest(
|
|
20
|
+
export function parseEvalRequest(
|
|
21
|
+
params: unknown,
|
|
22
|
+
enabledLanguages: readonly EvalLanguage[] = evalLanguageOrder,
|
|
23
|
+
): EvalToolRequest {
|
|
15
24
|
if (!isRecord(params)) throw new TypeError("eval parameters must be an object");
|
|
16
25
|
if (params.action === "list") return { action: "list" };
|
|
17
26
|
if (params.action === "peek" || params.action === "stop") {
|
|
@@ -21,8 +30,9 @@ export function parseEvalRequest(params: unknown): EvalToolRequest {
|
|
|
21
30
|
}
|
|
22
31
|
if (params.action !== undefined && params.action !== "run")
|
|
23
32
|
throw new TypeError(`Unknown eval action "${String(params.action)}"`);
|
|
24
|
-
if (!isEvalLanguage(params.language)) throw new TypeError(
|
|
25
|
-
if (typeof params.code !== "string")
|
|
33
|
+
if (!isEvalLanguage(params.language)) throw new TypeError(evalRunRequiresLanguageMessage(enabledLanguages));
|
|
34
|
+
if (typeof params.code !== "string")
|
|
35
|
+
throw new TypeError("eval run requires code — the cell body to execute, verbatim");
|
|
26
36
|
const summary = normalizeEvalSummary(params.summary);
|
|
27
37
|
if (summary === undefined)
|
|
28
38
|
throw new TypeError(
|
|
@@ -57,3 +67,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
57
67
|
function isEvalLanguage(value: unknown): value is EvalToolInput["language"] {
|
|
58
68
|
return value === "py" || value === "js" || value === "rb" || value === "jl";
|
|
59
69
|
}
|
|
70
|
+
|
|
71
|
+
function evalRunRequiresLanguageMessage(languages: readonly EvalLanguage[]): string {
|
|
72
|
+
return `eval run requires language — one of ${languages.map((language) => `"${language}"`).join(", ")}`;
|
|
73
|
+
}
|
|
@@ -73,7 +73,7 @@ export function createEvalTool(options: CreateEvalToolOptions) {
|
|
|
73
73
|
async function execute(
|
|
74
74
|
...[toolCallId, params, signal, onUpdate, ctx]: EvalExecuteArgs<EvalToolRequest>
|
|
75
75
|
): Promise<AgentToolResult<EvalResultDetails>> {
|
|
76
|
-
const request = parseEvalRequest(params);
|
|
76
|
+
const request = parseEvalRequest(params, languages);
|
|
77
77
|
if (isEvalControlRequest(request)) return await executeEvalControl(cellManager, request);
|
|
78
78
|
if (options.proxyExecutor) return await options.proxyExecutor(request, signal);
|
|
79
79
|
if (!languages.includes(request.language))
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// allow: SIZE_OK — one eval render pipeline avoids the runtime/render TDZ that motivated this module boundary.
|
|
2
2
|
import {
|
|
3
3
|
type AgentToolResult,
|
|
4
|
-
highlightCode,
|
|
5
4
|
sanitizeTerminalLabel,
|
|
6
5
|
type Theme,
|
|
7
6
|
type ThemeColor,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
truncateToVisualLines,
|
|
11
10
|
} from "@code-yeongyu/senpi";
|
|
12
11
|
import type { TruncationMeta } from "../output/output-meta.ts";
|
|
12
|
+
import { highlightedCode } from "./code-preview.ts";
|
|
13
13
|
import { displayCode } from "./display-code.ts";
|
|
14
14
|
import { normalizeEvalSummary } from "./eval-request.ts";
|
|
15
15
|
import {
|
|
@@ -26,7 +26,6 @@ import { codePointPrefix, formatDuration, renderToolCallWidget } from "./tool-wi
|
|
|
26
26
|
import type {
|
|
27
27
|
EvalCellResult,
|
|
28
28
|
EvalInputSchema,
|
|
29
|
-
EvalLanguage,
|
|
30
29
|
EvalResultDetails,
|
|
31
30
|
EvalStatusEvent,
|
|
32
31
|
EvalToolDetails,
|
|
@@ -269,6 +268,8 @@ type RenderEnvironment = {
|
|
|
269
268
|
readonly meta: TruncationMeta | undefined;
|
|
270
269
|
/** Render-time clock, injected so elapsed time is deterministic under test. */
|
|
271
270
|
readonly now: number;
|
|
271
|
+
/** Repaints the row once a background-formatted code preview is ready; absent while args stream. */
|
|
272
|
+
readonly repaint?: () => void;
|
|
272
273
|
};
|
|
273
274
|
type CellBadges = {
|
|
274
275
|
readonly reset: boolean;
|
|
@@ -288,27 +289,6 @@ function assertNever(value: never): never {
|
|
|
288
289
|
throw new TypeError(`Unhandled eval render variant: ${String(value)}`);
|
|
289
290
|
}
|
|
290
291
|
|
|
291
|
-
function languageForHighlighter(language: EvalLanguage): "python" | "javascript" | "ruby" | "julia" {
|
|
292
|
-
switch (language) {
|
|
293
|
-
case "py":
|
|
294
|
-
return "python";
|
|
295
|
-
case "js":
|
|
296
|
-
return "javascript";
|
|
297
|
-
case "rb":
|
|
298
|
-
return "ruby";
|
|
299
|
-
case "jl":
|
|
300
|
-
return "julia";
|
|
301
|
-
default:
|
|
302
|
-
return assertNever(language);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function highlightedCode(code: string, language: EvalLanguage, theme: Theme | undefined): string {
|
|
307
|
-
const normalizedCode = code.trim().length > 0 ? code : "...";
|
|
308
|
-
const lines = highlightCode(displayCode(normalizedCode, language), languageForHighlighter(language));
|
|
309
|
-
return (theme === undefined ? lines.map((line) => line.replace(/\u001b\[[0-9;]*m/gu, "")) : lines).join("\n");
|
|
310
|
-
}
|
|
311
|
-
|
|
312
292
|
function spinner(frame: number | undefined): string {
|
|
313
293
|
return SPINNER_FRAMES.at((frame ?? 0) % SPINNER_FRAMES.length) ?? SPINNER_FRAMES[0];
|
|
314
294
|
}
|
|
@@ -644,7 +624,7 @@ function renderCell(cell: EvalCellResult, environment: RenderEnvironment, badges
|
|
|
644
624
|
}
|
|
645
625
|
const innerWidth = Math.max(1, environment.width - 2);
|
|
646
626
|
const codePreview = previewText(
|
|
647
|
-
highlightedCode(cell.code, cell.language, environment.theme),
|
|
627
|
+
highlightedCode(cell.code, cell.language, environment.theme, environment.repaint),
|
|
648
628
|
environment.expanded ? Number.POSITIVE_INFINITY : CODE_PREVIEW_LINES,
|
|
649
629
|
innerWidth,
|
|
650
630
|
);
|
|
@@ -926,7 +906,9 @@ export function renderEvalCall(
|
|
|
926
906
|
text: style(
|
|
927
907
|
theme,
|
|
928
908
|
"mdCodeBlock",
|
|
929
|
-
args.code.trim().length > 0
|
|
909
|
+
args.code.trim().length > 0
|
|
910
|
+
? displayCode(args.code, args.language, context.argsComplete ? context.invalidate : undefined)
|
|
911
|
+
: "...",
|
|
930
912
|
),
|
|
931
913
|
maxVisualLines: context.expanded ? undefined : CODE_PREVIEW_LINES,
|
|
932
914
|
collapseKind: "code",
|
|
@@ -946,6 +928,7 @@ export function renderEvalCall(
|
|
|
946
928
|
width,
|
|
947
929
|
meta: undefined,
|
|
948
930
|
now: renderNow(context),
|
|
931
|
+
...(context.argsComplete ? { repaint: context.invalidate } : {}),
|
|
949
932
|
};
|
|
950
933
|
const cell: EvalCellResult = {
|
|
951
934
|
index: 0,
|
|
@@ -998,6 +981,7 @@ export function renderEvalResult(
|
|
|
998
981
|
width,
|
|
999
982
|
meta: details.meta,
|
|
1000
983
|
now: renderNow(context),
|
|
984
|
+
repaint: context.invalidate,
|
|
1001
985
|
},
|
|
1002
986
|
args: context.args,
|
|
1003
987
|
showImageFallback: context.showImages && imageProtocol === null,
|
|
@@ -65,6 +65,12 @@ export type EvalControlInput =
|
|
|
65
65
|
|
|
66
66
|
export type EvalToolRequest = EvalToolInput | EvalControlInput;
|
|
67
67
|
|
|
68
|
+
// Like `summary`, `language` and `code` stay optional in the wire schema because control
|
|
69
|
+
// actions share it; the description teaches the requirement and parseEvalRequest enforces it.
|
|
70
|
+
const LANGUAGE_FIELD_DESCRIPTION =
|
|
71
|
+
"REQUIRED for run. Kernel that runs the cell; each language keeps its own persistent state across eval calls.";
|
|
72
|
+
const CODE_FIELD_DESCRIPTION = "REQUIRED for run. Cell body, verbatim.";
|
|
73
|
+
|
|
68
74
|
function evalInputProperties<Language extends TSchema>(languageSchema: Language, deadlines: EvalDeadlineSeconds) {
|
|
69
75
|
return {
|
|
70
76
|
action: Type.Optional(
|
|
@@ -74,7 +80,7 @@ function evalInputProperties<Language extends TSchema>(languageSchema: Language,
|
|
|
74
80
|
}),
|
|
75
81
|
),
|
|
76
82
|
language: Type.Optional(languageSchema),
|
|
77
|
-
code: Type.Optional(Type.String({ description:
|
|
83
|
+
code: Type.Optional(Type.String({ description: CODE_FIELD_DESCRIPTION })),
|
|
78
84
|
summary: Type.Optional(
|
|
79
85
|
Type.String({
|
|
80
86
|
description:
|
|
@@ -96,11 +102,15 @@ function evalInputProperties<Language extends TSchema>(languageSchema: Language,
|
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
|
|
105
|
+
function evalLanguageUnion(languages: readonly EvalLanguage[]) {
|
|
106
|
+
return Type.Union(
|
|
107
|
+
languages.map((item) => Type.Literal(item)),
|
|
108
|
+
{ description: LANGUAGE_FIELD_DESCRIPTION },
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
99
112
|
const fullEvalInputSchema = Type.Object(
|
|
100
|
-
evalInputProperties(
|
|
101
|
-
Type.Union([Type.Literal("js"), Type.Literal("py"), Type.Literal("rb"), Type.Literal("jl")]),
|
|
102
|
-
defaultEvalDeadlineSeconds,
|
|
103
|
-
),
|
|
113
|
+
evalInputProperties(evalLanguageUnion(evalLanguageOrder), defaultEvalDeadlineSeconds),
|
|
104
114
|
);
|
|
105
115
|
|
|
106
116
|
/** Runtime accepts a discriminated run/control union. */
|
|
@@ -112,10 +122,7 @@ export function createEvalInputSchema(
|
|
|
112
122
|
): EvalInputSchema {
|
|
113
123
|
const languages = enabledLanguageList(enabled);
|
|
114
124
|
if (languages.length === 0) throw new Error("eval requires at least one enabled language");
|
|
115
|
-
const languageSchema =
|
|
116
|
-
languages.length === 1
|
|
117
|
-
? Type.Union([Type.Literal(languages[0])])
|
|
118
|
-
: Type.Union(languages.map((item) => Type.Literal(item)));
|
|
125
|
+
const languageSchema = evalLanguageUnion(languages);
|
|
119
126
|
return Type.Unsafe<EvalToolRequest>(
|
|
120
127
|
Type.Object(evalInputProperties(languageSchema, deadlines), {
|
|
121
128
|
anyOf: [
|
|
@@ -26,7 +26,7 @@ export declare class StreamStartTimeoutError extends Error {
|
|
|
26
26
|
constructor(timeoutMs: number);
|
|
27
27
|
}
|
|
28
28
|
/** Build the provider context using the same transform and conversion pipeline as an agent request. */
|
|
29
|
-
export declare function buildProviderContext(context: AgentContext, config: Pick<AgentLoopConfig, "convertToLlm" | "transformContext"
|
|
29
|
+
export declare function buildProviderContext(context: AgentContext, config: Pick<AgentLoopConfig, "convertToLlm" | "transformContext"> & Partial<Pick<AgentLoopConfig, "model">>, signal?: AbortSignal): Promise<Context>;
|
|
30
30
|
export interface PreparedAgentToolCall {
|
|
31
31
|
toolCall: AgentToolCall;
|
|
32
32
|
tool: AgentTool;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIN,KAAK,OAAO,EAEZ,WAAW,
|
|
1
|
+
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIN,KAAK,OAAO,EAEZ,WAAW,EAKX,MAAM,uBAAuB,CAAC;AAW/B,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EAEf,YAAY,EACZ,SAAS,EACT,aAAa,EAEb,QAAQ,EACR,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAiBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAwBzC;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB;AAmBD,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,YAAY,SAAS,EAAE,MAAM,EAK5B;CACD;AA+OD,uGAAuG;AACvG,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,cAAc,GAAG,kBAAkB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,EAC5G,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,OAAO,CAAC,CAQlB;AAknBD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACd;AAED,OAAO,EAAE,6BAA6B,EAAE,CAAC;AAEzC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,qBAAqB,CAOpG"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Agent loop that works with AgentMessage throughout.
|
|
3
3
|
* Transforms to Message[] only at the LLM call boundary.
|
|
4
4
|
*/
|
|
5
|
-
import { EventStream, isCursorExecResolved, validateToolArguments, } from "@earendil-works/pi-ai";
|
|
5
|
+
import { EventStream, isCursorExecResolved, supportsAllowedToolChoice, validateToolArguments, } from "@earendil-works/pi-ai";
|
|
6
6
|
import { createTerminalFailureAssistantMessage, demoteToolUseWithoutToolCalls, isStreamIdleTimeoutError, normalizeTerminalAssistantMessage, promoteStopWithPendingToolCalls, shouldFinalizeIdleAsStop, shouldTerminateAssistantTurn, } from "./assistant-terminal-state.js";
|
|
7
7
|
import { getDefaultStreamFn, withEmptyAssistantRecovery } from "./stream-fn.js";
|
|
8
8
|
import { prepareAgentToolCallArguments } from "./tool-arguments.js";
|
|
@@ -279,12 +279,32 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
279
279
|
}
|
|
280
280
|
await emit({ type: "agent_end", messages: newMessages });
|
|
281
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* senpi#2095: a model that accepts an allowed-tools restriction receives every declared tool plus the
|
|
284
|
+
* callable subset by name; any other model receives the callable tools alone, as before.
|
|
285
|
+
*/
|
|
286
|
+
function providerTools(context, model) {
|
|
287
|
+
const declaredTools = context.declaredTools;
|
|
288
|
+
if (declaredTools === undefined || model === undefined || !supportsAllowedToolChoice(model)) {
|
|
289
|
+
return { tools: context.tools };
|
|
290
|
+
}
|
|
291
|
+
const activeTools = context.tools ?? [];
|
|
292
|
+
const declaredNames = new Set(declaredTools.map((tool) => tool.name));
|
|
293
|
+
return {
|
|
294
|
+
tools: [...declaredTools, ...activeTools.filter((tool) => !declaredNames.has(tool.name))],
|
|
295
|
+
activeToolNames: activeTools.map((tool) => tool.name),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
282
298
|
/** Build the provider context using the same transform and conversion pipeline as an agent request. */
|
|
283
299
|
export async function buildProviderContext(context, config, signal) {
|
|
284
300
|
let messages = context.messages;
|
|
285
301
|
if (config.transformContext)
|
|
286
302
|
messages = await config.transformContext(messages, signal);
|
|
287
|
-
return {
|
|
303
|
+
return {
|
|
304
|
+
systemPrompt: context.systemPrompt,
|
|
305
|
+
messages: await config.convertToLlm(messages),
|
|
306
|
+
...providerTools(context, config.model),
|
|
307
|
+
};
|
|
288
308
|
}
|
|
289
309
|
/**
|
|
290
310
|
* Stream an assistant response from the LLM.
|