@oh-my-pi/pi-coding-agent 15.10.10 → 15.10.12
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 +142 -7
- package/dist/cli.js +23108 -0
- package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
- package/dist/types/async/job-manager.d.ts +18 -0
- package/dist/types/cli/args.d.ts +2 -1
- package/dist/types/cli/dry-balance-cli.d.ts +1 -1
- package/dist/types/cli/gallery-cli.d.ts +1 -1
- package/dist/types/cli/gallery-fixtures/types.d.ts +1 -1
- package/dist/types/cli/usage-cli.d.ts +72 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/read.d.ts +1 -1
- package/dist/types/commands/usage.d.ts +25 -0
- package/dist/types/config/api-key-resolver.d.ts +3 -0
- package/dist/types/config/append-only-context-mode.d.ts +2 -1
- package/dist/types/config/model-discovery.d.ts +55 -0
- package/dist/types/config/model-registry.d.ts +8 -219
- package/dist/types/config/model-resolver.d.ts +34 -10
- package/dist/types/config/model-roles.d.ts +28 -0
- package/dist/types/config/models-config-schema.d.ts +523 -42
- package/dist/types/config/models-config.d.ts +385 -0
- package/dist/types/config/settings-schema.d.ts +41 -8
- package/dist/types/config/settings.d.ts +8 -1
- package/dist/types/debug/log-viewer.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +1 -1
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/eval/backend.d.ts +0 -2
- package/dist/types/eval/idle-timeout.d.ts +0 -4
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
- package/dist/types/eval/py/executor.d.ts +5 -0
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/runner.d.ts +3 -2
- package/dist/types/extensibility/extensions/types.d.ts +6 -3
- package/dist/types/hindsight/mental-models.d.ts +17 -8
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/lsp/edits.d.ts +9 -0
- package/dist/types/lsp/index.d.ts +2 -2
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/lsp/utils.d.ts +3 -0
- package/dist/types/mcp/json-rpc.d.ts +5 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +66 -1
- package/dist/types/mnemopi/state.d.ts +11 -1
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/bash-execution.d.ts +1 -1
- package/dist/types/modes/components/copy-selector.d.ts +1 -1
- package/dist/types/modes/components/dynamic-border.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
- package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
- package/dist/types/modes/components/footer.d.ts +1 -1
- package/dist/types/modes/components/hook-editor.d.ts +5 -0
- package/dist/types/modes/components/hook-input.d.ts +4 -0
- package/dist/types/modes/components/hook-selector.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-review-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/component.d.ts +1 -1
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
- package/dist/types/modes/components/transcript-container.d.ts +25 -6
- package/dist/types/modes/components/tree-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message.d.ts +2 -1
- package/dist/types/modes/components/visual-truncate.d.ts +1 -1
- package/dist/types/modes/components/welcome.d.ts +19 -3
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +1 -1
- package/dist/types/modes/index.d.ts +3 -3
- package/dist/types/modes/interactive-mode.d.ts +8 -3
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
- package/dist/types/modes/setup-wizard/index.d.ts +5 -1
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +8 -2
- package/dist/types/session/agent-session.d.ts +15 -3
- package/dist/types/session/auth-broker-config.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +1 -1
- package/dist/types/session/streaming-output.d.ts +23 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
- package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
- package/dist/types/slash-commands/types.d.ts +1 -1
- package/dist/types/ssh/connection-manager.d.ts +8 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/index.d.ts +2 -2
- package/dist/types/task/parallel.d.ts +2 -2
- package/dist/types/task/types.d.ts +8 -0
- package/dist/types/task/worktree.d.ts +2 -0
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +11 -0
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/ask.d.ts +4 -0
- package/dist/types/tools/conflict-detect.d.ts +16 -0
- package/dist/types/tools/github-cache.d.ts +7 -0
- package/dist/types/tools/index.d.ts +6 -0
- package/dist/types/tools/sqlite-reader.d.ts +3 -0
- package/dist/types/tui/output-block.d.ts +3 -3
- package/dist/types/utils/changelog.d.ts +8 -0
- package/dist/types/utils/git.d.ts +15 -2
- package/dist/types/utils/title-generator.d.ts +3 -2
- package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
- package/dist/types/web/scrapers/types.d.ts +12 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -1
- package/dist/types/web/search/providers/gemini.d.ts +1 -1
- package/examples/extensions/tools.ts +5 -4
- package/package.json +14 -11
- package/scripts/build-binary.ts +18 -23
- package/scripts/bundle-dist.ts +81 -0
- package/scripts/{dev-launch → omp} +1 -1
- package/scripts/{dev-launch-preload.ts → omp.ts} +1 -1
- package/src/async/job-manager.ts +57 -3
- package/src/auto-thinking/classifier.ts +1 -0
- package/src/autoresearch/dashboard.ts +1 -1
- package/src/autoresearch/prompt-setup.md +6 -6
- package/src/autoresearch/prompt.md +6 -6
- package/src/capability/fs.ts +10 -0
- package/src/cli/args.ts +4 -1
- package/src/cli/auth-gateway-cli.ts +1 -3
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/fs.ts +1 -1
- package/src/cli/gallery-fixtures/types.ts +5 -1
- package/src/cli/list-models.ts +2 -1
- package/src/cli/usage-cli.ts +603 -0
- package/src/cli-commands.ts +30 -0
- package/src/cli.ts +76 -13
- package/src/commands/complete.ts +1 -1
- package/src/commands/launch.ts +5 -1
- package/src/commands/read.ts +6 -3
- package/src/commands/usage.ts +35 -0
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/model-selection.ts +4 -3
- package/src/config/api-key-resolver.ts +8 -6
- package/src/config/append-only-context-mode.ts +6 -12
- package/src/config/model-discovery.ts +554 -0
- package/src/config/model-registry.ts +320 -1041
- package/src/config/model-resolver.ts +173 -156
- package/src/config/model-roles.ts +74 -0
- package/src/config/models-config-schema.ts +57 -8
- package/src/config/models-config.ts +129 -0
- package/src/config/settings-schema.ts +61 -19
- package/src/config/settings.ts +98 -4
- package/src/dap/client.ts +124 -37
- package/src/dap/session.ts +259 -158
- package/src/debug/log-viewer.ts +1 -1
- package/src/debug/raw-sse.ts +1 -1
- package/src/edit/diff.ts +47 -3
- package/src/edit/hashline/block-resolver.ts +20 -1
- package/src/edit/hashline/diff.ts +36 -1
- package/src/edit/hashline/execute.ts +47 -4
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/edit/index.ts +16 -1
- package/src/edit/modes/patch.ts +52 -0
- package/src/edit/modes/replace.ts +56 -22
- package/src/edit/notebook.ts +22 -2
- package/src/edit/renderer.ts +36 -10
- package/src/eval/__tests__/completion-bridge.test.ts +1 -1
- package/src/eval/backend.ts +0 -2
- package/src/eval/completion-bridge.ts +3 -1
- package/src/eval/idle-timeout.ts +2 -9
- package/src/eval/js/context-manager.ts +6 -8
- package/src/eval/js/executor.ts +6 -2
- package/src/eval/js/index.ts +0 -2
- package/src/eval/js/shared/helpers.ts +5 -6
- package/src/eval/js/shared/local-module-loader.ts +1 -1
- package/src/eval/js/shared/prelude.txt +62 -1
- package/src/eval/js/shared/rewrite-imports.ts +40 -22
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/eval/py/executor.ts +29 -7
- package/src/eval/py/index.ts +6 -3
- package/src/eval/py/kernel.ts +43 -4
- package/src/eval/py/runner.py +107 -3
- package/src/eval/py/runtime.ts +37 -0
- package/src/exec/bash-executor.ts +85 -4
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/runner.ts +6 -1
- package/src/extensibility/extensions/types.ts +6 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +20 -3
- package/src/hindsight/bank.ts +17 -2
- package/src/hindsight/mental-models.ts +59 -12
- package/src/hindsight/state.ts +6 -1
- package/src/internal-urls/artifact-protocol.ts +11 -2
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/internal-urls/issue-pr-protocol.ts +12 -5
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/lib/xai-http.ts +1 -1
- package/src/lsp/client.ts +118 -38
- package/src/lsp/clients/biome-client.ts +101 -39
- package/src/lsp/edits.ts +143 -95
- package/src/lsp/index.ts +31 -22
- package/src/lsp/render.ts +1 -1
- package/src/lsp/types.ts +2 -0
- package/src/lsp/utils.ts +28 -10
- package/src/main.ts +183 -23
- package/src/mcp/json-rpc.ts +35 -5
- package/src/mcp/transports/stdio.ts +7 -1
- package/src/memories/index.ts +4 -1
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/local-backend.ts +9 -0
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +81 -1
- package/src/mnemopi/backend.ts +176 -7
- package/src/mnemopi/state.ts +38 -2
- package/src/modes/acp/acp-agent.ts +119 -11
- package/src/modes/components/agent-dashboard.ts +10 -7
- package/src/modes/components/assistant-message.ts +32 -28
- package/src/modes/components/bash-execution.ts +1 -1
- package/src/modes/components/copy-selector.ts +1 -1
- package/src/modes/components/diff.ts +13 -2
- package/src/modes/components/dynamic-border.ts +12 -3
- package/src/modes/components/extensions/extension-dashboard.ts +8 -5
- package/src/modes/components/extensions/extension-list.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +1 -1
- package/src/modes/components/footer.ts +4 -2
- package/src/modes/components/history-search.ts +1 -1
- package/src/modes/components/hook-editor.ts +8 -0
- package/src/modes/components/hook-input.ts +8 -0
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/model-selector.ts +4 -2
- package/src/modes/components/plan-review-overlay.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +2 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/settings-selector.ts +5 -1
- package/src/modes/components/status-line/component.ts +119 -35
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/transcript-container.ts +258 -53
- package/src/modes/components/tree-selector.ts +3 -3
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +17 -5
- package/src/modes/components/visual-truncate.ts +1 -1
- package/src/modes/components/welcome.ts +108 -26
- package/src/modes/controllers/command-controller.ts +11 -4
- package/src/modes/controllers/event-controller.ts +73 -4
- package/src/modes/controllers/input-controller.ts +2 -1
- package/src/modes/controllers/mcp-command-controller.ts +39 -4
- package/src/modes/controllers/selector-controller.ts +1 -1
- package/src/modes/controllers/streaming-reveal.ts +85 -18
- package/src/modes/index.ts +3 -21
- package/src/modes/interactive-mode.ts +42 -18
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +154 -3
- package/src/modes/rpc/rpc-mode.ts +97 -12
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +81 -1
- package/src/modes/setup-wizard/index.ts +12 -2
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +1 -1
- package/src/modes/setup-wizard/scenes/providers.ts +1 -1
- package/src/modes/setup-wizard/scenes/sign-in.ts +1 -1
- package/src/modes/setup-wizard/scenes/theme.ts +1 -1
- package/src/modes/setup-wizard/scenes/types.ts +1 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +1 -1
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/types.ts +4 -1
- package/src/prompts/agents/explore.md +2 -2
- package/src/prompts/agents/librarian.md +1 -2
- package/src/prompts/agents/oracle.md +1 -1
- package/src/prompts/agents/plan.md +5 -5
- package/src/prompts/agents/task.md +5 -5
- package/src/prompts/ci-green-request.md +5 -7
- package/src/prompts/goals/goal-budget-limit.md +2 -2
- package/src/prompts/goals/goal-continuation.md +4 -4
- package/src/prompts/goals/goal-mode-active.md +1 -1
- package/src/prompts/memories/read-path.md +1 -1
- package/src/prompts/memories/stage_one_system.md +2 -2
- package/src/prompts/review-custom-request.md +1 -1
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/auto-continue.md +1 -1
- package/src/prompts/system/background-tan-dispatch.md +1 -1
- package/src/prompts/system/btw-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +13 -1
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/eager-todo.md +2 -2
- package/src/prompts/system/irc-incoming.md +1 -1
- package/src/prompts/system/manual-continue.md +1 -1
- package/src/prompts/system/omfg-user.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +9 -9
- package/src/prompts/system/plan-mode-active.md +4 -4
- package/src/prompts/system/plan-mode-subagent.md +4 -5
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/subagent-system-prompt.md +4 -4
- package/src/prompts/system/system-prompt.md +13 -24
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +2 -2
- package/src/prompts/tools/bash.md +5 -7
- package/src/prompts/tools/browser.md +7 -7
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/eval.md +3 -3
- package/src/prompts/tools/find.md +0 -1
- package/src/prompts/tools/github.md +8 -7
- package/src/prompts/tools/goal.md +1 -1
- package/src/prompts/tools/image-gen.md +1 -1
- package/src/prompts/tools/inspect-image-system.md +1 -1
- package/src/prompts/tools/irc.md +15 -15
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/read.md +3 -4
- package/src/prompts/tools/recall.md +1 -1
- package/src/prompts/tools/reflect.md +1 -1
- package/src/prompts/tools/render-mermaid.md +2 -2
- package/src/prompts/tools/replace.md +4 -10
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search-tool-bm25.md +1 -9
- package/src/prompts/tools/search.md +0 -1
- package/src/prompts/tools/ssh.md +0 -4
- package/src/prompts/tools/task.md +2 -3
- package/src/prompts/tools/todo.md +1 -1
- package/src/sdk.ts +31 -11
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +39 -18
- package/src/session/agent-session.ts +223 -64
- package/src/session/auth-broker-config.ts +30 -1
- package/src/session/session-manager.ts +2 -2
- package/src/session/streaming-output.ts +188 -11
- package/src/slash-commands/acp-builtins.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +40 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
- package/src/slash-commands/types.ts +1 -1
- package/src/ssh/connection-manager.ts +27 -0
- package/src/system-prompt.ts +14 -0
- package/src/task/commands.ts +2 -1
- package/src/task/executor.ts +74 -65
- package/src/task/index.ts +146 -68
- package/src/task/parallel.ts +3 -3
- package/src/task/render.ts +20 -5
- package/src/task/types.ts +9 -0
- package/src/task/worktree.ts +64 -56
- package/src/thinking.ts +9 -1
- package/src/tiny/title-client.ts +60 -16
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +6 -4
- package/src/tools/archive-reader.ts +30 -2
- package/src/tools/ask.ts +104 -21
- package/src/tools/ast-edit.ts +25 -5
- package/src/tools/auto-generated-guard.ts +20 -3
- package/src/tools/bash-interactive.ts +27 -7
- package/src/tools/bash.ts +100 -18
- package/src/tools/browser/launch.ts +11 -2
- package/src/tools/browser/readable.ts +19 -2
- package/src/tools/browser/registry.ts +4 -1
- package/src/tools/browser/render.ts +2 -2
- package/src/tools/browser/tab-supervisor.ts +55 -16
- package/src/tools/conflict-detect.ts +50 -4
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval-render.ts +5 -5
- package/src/tools/eval.ts +0 -2
- package/src/tools/fetch.ts +33 -10
- package/src/tools/gh-cache-invalidation.ts +63 -8
- package/src/tools/gh-renderer.ts +1 -1
- package/src/tools/gh.ts +172 -29
- package/src/tools/github-cache.ts +70 -6
- package/src/tools/image-gen.ts +14 -13
- package/src/tools/index.ts +13 -1
- package/src/tools/inspect-image.ts +1 -0
- package/src/tools/irc.ts +5 -1
- package/src/tools/job.ts +1 -1
- package/src/tools/read.ts +202 -61
- package/src/tools/render-utils.ts +3 -3
- package/src/tools/resolve.ts +1 -1
- package/src/tools/search.ts +92 -29
- package/src/tools/sqlite-reader.ts +17 -5
- package/src/tools/ssh.ts +8 -8
- package/src/tools/todo.ts +38 -8
- package/src/tools/write.ts +118 -18
- package/src/tui/output-block.ts +4 -4
- package/src/utils/changelog.ts +27 -1
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/file-mentions.ts +2 -1
- package/src/utils/git.ts +267 -13
- package/src/utils/title-generator.ts +24 -5
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +1 -1
- package/src/web/scrapers/twitter.ts +2 -1
- package/src/web/scrapers/types.ts +87 -8
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/scrapers/youtube.ts +6 -1
- package/src/web/search/index.ts +1 -1
- package/src/web/search/providers/codex.ts +2 -1
- package/src/web/search/providers/gemini.ts +2 -3
- package/src/web/search/render.ts +8 -6
- package/dist/types/config/model-equivalence.d.ts +0 -24
- package/dist/types/config/model-id-affixes.d.ts +0 -12
- package/dist/types/config/model-provider-priority.d.ts +0 -1
- package/dist/types/exec/idle-timeout-watchdog.d.ts +0 -18
- package/src/config/model-equivalence.ts +0 -875
- package/src/config/model-id-affixes.ts +0 -81
- package/src/config/model-provider-priority.ts +0 -56
- package/src/exec/idle-timeout-watchdog.ts +0 -126
package/src/eval/backend.ts
CHANGED
|
@@ -20,8 +20,6 @@ export interface ExecutorBackendExecOptions {
|
|
|
20
20
|
*/
|
|
21
21
|
idleTimeoutMs: number;
|
|
22
22
|
reset: boolean;
|
|
23
|
-
artifactPath: string | undefined;
|
|
24
|
-
artifactId: string | undefined;
|
|
25
23
|
onChunk: (chunk: string) => void;
|
|
26
24
|
/**
|
|
27
25
|
* Live status events (read/write/agent/…) delivered as they are emitted,
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* in, text (or, with `schema`, a structured object) out.
|
|
13
13
|
*/
|
|
14
14
|
import { instrumentedCompleteSimple, resolveTelemetry } from "@oh-my-pi/pi-agent-core";
|
|
15
|
-
import { type Api, Effort,
|
|
15
|
+
import { type Api, Effort, type Model, type Tool } from "@oh-my-pi/pi-ai";
|
|
16
|
+
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
16
17
|
import * as z from "zod/v4";
|
|
17
18
|
import { extractTextContent, extractToolCall, parseJsonPayload } from "../commit/utils";
|
|
18
19
|
|
|
@@ -162,6 +163,7 @@ export async function runEvalCompletion(
|
|
|
162
163
|
apiKey: registry.resolver(model.provider, {
|
|
163
164
|
sessionId: options.session.getSessionId?.() ?? undefined,
|
|
164
165
|
baseUrl: model.baseUrl,
|
|
166
|
+
modelId: model.id,
|
|
165
167
|
}),
|
|
166
168
|
signal: options.signal,
|
|
167
169
|
reasoning: reasoningForTier(tier, model),
|
package/src/eval/idle-timeout.ts
CHANGED
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
* `agent()`/`parallel()`/`completion()` work is ignored completely, then {@link resume}
|
|
7
7
|
* starts a fresh timeout window once the runtime gets control back.
|
|
8
8
|
*
|
|
9
|
-
* The active timer self-reschedules instead of being torn down on every
|
|
10
|
-
* activity event, so frequent activity costs one timestamp write per event.
|
|
11
9
|
* Pause is reference-counted because `parallel()` can have multiple bridge calls
|
|
12
10
|
* in flight at once.
|
|
13
11
|
*/
|
|
@@ -36,11 +34,6 @@ export class IdleTimeout {
|
|
|
36
34
|
return this.#idleMs;
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
/** Record runtime activity, pushing the active deadline forward by `idleMs`. */
|
|
40
|
-
bump(): void {
|
|
41
|
-
if (this.#settled || this.#pauseDepth > 0) return;
|
|
42
|
-
this.#deadlineMs = Date.now() + this.#idleMs;
|
|
43
|
-
}
|
|
44
37
|
/** Suspend timeout accounting while control is delegated to host-side work. */
|
|
45
38
|
pause(): void {
|
|
46
39
|
if (this.#settled) return;
|
|
@@ -86,8 +79,8 @@ export class IdleTimeout {
|
|
|
86
79
|
if (this.#settled || this.#pauseDepth > 0) return;
|
|
87
80
|
const remainingMs = this.#deadlineMs - Date.now();
|
|
88
81
|
if (remainingMs > 0) {
|
|
89
|
-
//
|
|
90
|
-
// out the remaining window instead of firing early.
|
|
82
|
+
// The deadline moved forward (resume re-arming) after this timer was
|
|
83
|
+
// armed; wait out the remaining window instead of firing early.
|
|
91
84
|
this.#arm(remainingMs);
|
|
92
85
|
return;
|
|
93
86
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { logger, Snowflake, workerHostEntry } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import type { ToolSession } from "../../tools";
|
|
3
3
|
import { ToolAbortError, ToolError } from "../../tools/tool-errors";
|
|
4
4
|
import { callSessionTool, type JsStatusEvent } from "./tool-bridge";
|
|
5
5
|
import { WorkerCore } from "./worker-core";
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// Bun's `--compile` bundler discovers, the `new URL` form is what makes dev
|
|
9
|
-
// runs portable across cwds. The worker is registered as an additional
|
|
10
|
-
// `--compile` entrypoint in `scripts/build-binary.ts`.
|
|
6
|
+
// Coding-agent binary/bundle workers route through the CLI entrypoint with a
|
|
7
|
+
// hidden argv mode, so compiled/npm builds only need one JavaScript entry.
|
|
11
8
|
import type {
|
|
12
9
|
JsDisplayOutput,
|
|
13
10
|
RunErrorPayload,
|
|
@@ -384,8 +381,9 @@ async function raceWithTimeout<T>(promise: Promise<T>, timeoutMs: number, reason
|
|
|
384
381
|
|
|
385
382
|
async function spawnJsWorker(): Promise<WorkerHandle> {
|
|
386
383
|
try {
|
|
387
|
-
const
|
|
388
|
-
|
|
384
|
+
const hostEntry = workerHostEntry();
|
|
385
|
+
const worker = hostEntry
|
|
386
|
+
? new Worker(hostEntry, { type: "module", argv: ["__omp_js_eval_worker"] })
|
|
389
387
|
: new Worker(new URL("./worker-entry.ts", import.meta.url).href, { type: "module" });
|
|
390
388
|
return wrapBunWorker(worker);
|
|
391
389
|
} catch (err) {
|
package/src/eval/js/executor.ts
CHANGED
|
@@ -63,9 +63,13 @@ function isTimeoutReason(reason: unknown): boolean {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function formatJsTimeoutAnnotation(timeoutMs: number | undefined): string {
|
|
66
|
-
|
|
66
|
+
// Timeout cancellation force-kills the worker (the only way to interrupt
|
|
67
|
+
// synchronous user code), which discards the persistent VM state. Say so,
|
|
68
|
+
// or the model will keep referencing variables that no longer exist.
|
|
69
|
+
const reset = "The JS worker was force-killed and its VM state was reset; variables from earlier cells are gone.";
|
|
70
|
+
if (timeoutMs === undefined) return `Command timed out. ${reset}`;
|
|
67
71
|
const secs = Math.max(1, Math.round(timeoutMs / 1000));
|
|
68
|
-
return `Command timed out after ${secs} seconds`;
|
|
72
|
+
return `Command timed out after ${secs} seconds. ${reset}`;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
export async function executeJs(code: string, options: JsExecutorOptions): Promise<JsResult> {
|
package/src/eval/js/index.ts
CHANGED
|
@@ -30,8 +30,6 @@ export default {
|
|
|
30
30
|
sessionId: namespaceSessionId(opts.sessionId),
|
|
31
31
|
sessionFile: opts.sessionFile,
|
|
32
32
|
reset: opts.reset,
|
|
33
|
-
artifactPath: opts.artifactPath,
|
|
34
|
-
artifactId: opts.artifactId,
|
|
35
33
|
onChunk: opts.onChunk,
|
|
36
34
|
onStatus: opts.onStatus,
|
|
37
35
|
session: opts.session,
|
|
@@ -83,12 +83,11 @@ export function createHelpers(ctx: HelperContext): HelperBundle {
|
|
|
83
83
|
},
|
|
84
84
|
append: async (rawPath, content) => {
|
|
85
85
|
const target = resolveHelperPath(ctx, rawPath, "write");
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
86
|
+
// O(1) append; read-all+rewrite both raced concurrent writers and went
|
|
87
|
+
// quadratic when called in a loop. Bun.write creates parent dirs, so
|
|
88
|
+
// keep that behavior for the append path too.
|
|
89
|
+
await fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
90
|
+
await fs.promises.appendFile(target, content, "utf-8");
|
|
92
91
|
ctx.emitStatus({
|
|
93
92
|
op: "append",
|
|
94
93
|
path: target,
|
|
@@ -102,7 +102,7 @@ export class LocalModuleLoader {
|
|
|
102
102
|
});
|
|
103
103
|
const moduleDir = path.dirname(modulePath);
|
|
104
104
|
const localDeps = new Set<string>();
|
|
105
|
-
for (const specifier of collectModuleSourceSpecifiers(stripped)) {
|
|
105
|
+
for (const specifier of await collectModuleSourceSpecifiers(stripped)) {
|
|
106
106
|
const resolved = resolveImportSpecifier(moduleDir, specifier);
|
|
107
107
|
if (isLocalPathSpecifier(specifier) && isManagedLocalModulePath(resolved)) {
|
|
108
108
|
localDeps.add(resolved);
|
|
@@ -90,15 +90,25 @@ if (!globalThis.__omp_js_prelude_loaded__) {
|
|
|
90
90
|
const limit = await __concurrencyLimit();
|
|
91
91
|
const concurrency = limit > 0 ? Math.min(limit, list.length) : list.length;
|
|
92
92
|
const results = new Array(list.length);
|
|
93
|
+
// Barrier semantics (mirrors the Python _pool_map): every item settles
|
|
94
|
+
// before we return or throw, then the lowest-index error propagates.
|
|
95
|
+
// Early-rejecting would orphan in-flight thunks (e.g. live agent()
|
|
96
|
+
// subagents) whose worker-side promises would never be observed.
|
|
97
|
+
const errors = new Map();
|
|
93
98
|
let next = 0;
|
|
94
99
|
const worker = async () => {
|
|
95
100
|
while (true) {
|
|
96
101
|
const index = next++;
|
|
97
102
|
if (index >= list.length) return;
|
|
98
|
-
|
|
103
|
+
try {
|
|
104
|
+
results[index] = await fn(list[index], index);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
errors.set(index, error);
|
|
107
|
+
}
|
|
99
108
|
}
|
|
100
109
|
};
|
|
101
110
|
await Promise.all(Array.from({ length: concurrency }, () => worker()));
|
|
111
|
+
if (errors.size > 0) throw errors.get(Math.min(...errors.keys()));
|
|
102
112
|
return results;
|
|
103
113
|
};
|
|
104
114
|
|
|
@@ -148,6 +158,8 @@ if (!globalThis.__omp_js_prelude_loaded__) {
|
|
|
148
158
|
|
|
149
159
|
const formatArgs = args => args.map(arg => (typeof arg === "string" ? arg : arg));
|
|
150
160
|
|
|
161
|
+
const consoleTimers = new Map();
|
|
162
|
+
const consoleCounts = new Map();
|
|
151
163
|
const consoleBridge = {
|
|
152
164
|
log: (...args) => globalThis.__omp_log__("log", ...formatArgs(args)),
|
|
153
165
|
info: (...args) => globalThis.__omp_log__("info", ...formatArgs(args)),
|
|
@@ -158,6 +170,55 @@ if (!globalThis.__omp_js_prelude_loaded__) {
|
|
|
158
170
|
columns === undefined
|
|
159
171
|
? globalThis.__omp_table__(data)
|
|
160
172
|
: globalThis.__omp_table__(data, columns),
|
|
173
|
+
dir: (value, _options) => globalThis.__omp_log__("log", value),
|
|
174
|
+
dirxml: (...args) => globalThis.__omp_log__("log", ...formatArgs(args)),
|
|
175
|
+
trace: (...args) => {
|
|
176
|
+
const stack = (new Error().stack ?? "").split("\n").slice(2).join("\n");
|
|
177
|
+
globalThis.__omp_log__("log", args.length > 0 ? `Trace: ${formatArgs(args).join(" ")}` : "Trace", `\n${stack}`);
|
|
178
|
+
},
|
|
179
|
+
assert: (condition, ...args) => {
|
|
180
|
+
if (condition) return;
|
|
181
|
+
if (args.length > 0) globalThis.__omp_log__("error", "Assertion failed:", ...formatArgs(args));
|
|
182
|
+
else globalThis.__omp_log__("error", "Assertion failed");
|
|
183
|
+
},
|
|
184
|
+
group: (...args) => {
|
|
185
|
+
if (args.length > 0) globalThis.__omp_log__("log", ...formatArgs(args));
|
|
186
|
+
},
|
|
187
|
+
groupCollapsed: (...args) => {
|
|
188
|
+
if (args.length > 0) globalThis.__omp_log__("log", ...formatArgs(args));
|
|
189
|
+
},
|
|
190
|
+
groupEnd: () => {},
|
|
191
|
+
time: label => {
|
|
192
|
+
consoleTimers.set(String(label ?? "default"), Date.now());
|
|
193
|
+
},
|
|
194
|
+
timeLog: (label, ...args) => {
|
|
195
|
+
const key = String(label ?? "default");
|
|
196
|
+
const start = consoleTimers.get(key);
|
|
197
|
+
if (start === undefined) {
|
|
198
|
+
globalThis.__omp_log__("warn", `Timer '${key}' does not exist`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
globalThis.__omp_log__("log", `${key}: ${Date.now() - start}ms`, ...formatArgs(args));
|
|
202
|
+
},
|
|
203
|
+
timeEnd: label => {
|
|
204
|
+
const key = String(label ?? "default");
|
|
205
|
+
const start = consoleTimers.get(key);
|
|
206
|
+
if (start === undefined) {
|
|
207
|
+
globalThis.__omp_log__("warn", `Timer '${key}' does not exist`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
consoleTimers.delete(key);
|
|
211
|
+
globalThis.__omp_log__("log", `${key}: ${Date.now() - start}ms`);
|
|
212
|
+
},
|
|
213
|
+
count: label => {
|
|
214
|
+
const key = String(label ?? "default");
|
|
215
|
+
const next = (consoleCounts.get(key) ?? 0) + 1;
|
|
216
|
+
consoleCounts.set(key, next);
|
|
217
|
+
globalThis.__omp_log__("log", `${key}: ${next}`);
|
|
218
|
+
},
|
|
219
|
+
countReset: label => {
|
|
220
|
+
consoleCounts.delete(String(label ?? "default"));
|
|
221
|
+
},
|
|
161
222
|
};
|
|
162
223
|
|
|
163
224
|
globalThis.console = consoleBridge;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type * as BabelParser from "@babel/parser";
|
|
2
2
|
|
|
3
3
|
// Static ESM `import` declarations are not valid inside vm.runInContext (script-mode parsing),
|
|
4
4
|
// and dynamic `import(...)` would otherwise resolve specifiers against the worker module's URL
|
|
@@ -64,9 +64,22 @@ type BabelModuleSourceDeclaration = {
|
|
|
64
64
|
|
|
65
65
|
type BabelNode = { type: string; start: number; end: number; [key: string]: unknown };
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
// @babel/parser sits on the CLI launch graph (tools → eval backend → worker-core →
|
|
68
|
+
// runtime → this module) but only runs when an eval cell executes, so it is loaded
|
|
69
|
+
// lazily and memoized.
|
|
70
|
+
let babelParser: typeof BabelParser | undefined;
|
|
71
|
+
|
|
72
|
+
async function loadBabelParser(): Promise<typeof BabelParser> {
|
|
73
|
+
if (!babelParser) {
|
|
74
|
+
babelParser = await import("@babel/parser");
|
|
75
|
+
}
|
|
76
|
+
return babelParser;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function parseProgram(code: string): Promise<{ program: { body: ReadonlyArray<BabelProgramNode> } } | null> {
|
|
80
|
+
const { parse } = await loadBabelParser();
|
|
68
81
|
try {
|
|
69
|
-
return
|
|
82
|
+
return parse(code, {
|
|
70
83
|
sourceType: "module",
|
|
71
84
|
allowAwaitOutsideFunction: true,
|
|
72
85
|
allowReturnOutsideFunction: true,
|
|
@@ -162,10 +175,10 @@ function rewriteImportNode(node: BabelImportDeclaration): string {
|
|
|
162
175
|
return `await ${importCall};`;
|
|
163
176
|
}
|
|
164
177
|
|
|
165
|
-
export function rewriteImports(code: string): string {
|
|
178
|
+
export async function rewriteImports(code: string): Promise<string> {
|
|
166
179
|
if (!code.includes("import")) return code;
|
|
167
180
|
|
|
168
|
-
const ast = parseProgram(code);
|
|
181
|
+
const ast = await parseProgram(code);
|
|
169
182
|
if (!ast) {
|
|
170
183
|
// Parser bailed entirely — let the VM surface the real syntax error.
|
|
171
184
|
return code;
|
|
@@ -201,8 +214,8 @@ export function rewriteImports(code: string): string {
|
|
|
201
214
|
}
|
|
202
215
|
return result;
|
|
203
216
|
}
|
|
204
|
-
export function collectModuleSourceSpecifiers(code: string): string[] {
|
|
205
|
-
const ast = parseProgram(code);
|
|
217
|
+
export async function collectModuleSourceSpecifiers(code: string): Promise<string[]> {
|
|
218
|
+
const ast = await parseProgram(code);
|
|
206
219
|
if (!ast) return [];
|
|
207
220
|
const sources: string[] = [];
|
|
208
221
|
for (const node of ast.program.body) {
|
|
@@ -218,8 +231,11 @@ export function collectModuleSourceSpecifiers(code: string): string[] {
|
|
|
218
231
|
return sources;
|
|
219
232
|
}
|
|
220
233
|
|
|
221
|
-
export function rewriteModuleSourceSpecifiers(
|
|
222
|
-
|
|
234
|
+
export async function rewriteModuleSourceSpecifiers(
|
|
235
|
+
code: string,
|
|
236
|
+
replacer: (source: string) => string,
|
|
237
|
+
): Promise<string> {
|
|
238
|
+
const ast = await parseProgram(code);
|
|
223
239
|
if (!ast) return code;
|
|
224
240
|
|
|
225
241
|
type Edit = { start: number; end: number; text: string };
|
|
@@ -249,9 +265,9 @@ export function rewriteModuleSourceSpecifiers(code: string, replacer: (source: s
|
|
|
249
265
|
return result;
|
|
250
266
|
}
|
|
251
267
|
|
|
252
|
-
export function rewriteDynamicImports(code: string, callee = "__omp_import__"): string {
|
|
268
|
+
export async function rewriteDynamicImports(code: string, callee = "__omp_import__"): Promise<string> {
|
|
253
269
|
if (!code.includes("import")) return code;
|
|
254
|
-
const ast = parseProgram(code);
|
|
270
|
+
const ast = await parseProgram(code);
|
|
255
271
|
if (!ast) return code;
|
|
256
272
|
|
|
257
273
|
type Edit = { start: number; end: number; text: string };
|
|
@@ -339,10 +355,10 @@ function appendGlobalBindingPublish(source: string, names: readonly string[]): s
|
|
|
339
355
|
* Nested declarations (inside functions, blocks, classes) are left alone \u2014 they're
|
|
340
356
|
* scoped to their enclosing function/block regardless of `var` vs `let`/`const`.
|
|
341
357
|
*/
|
|
342
|
-
function demoteTopLevelLexicals(code: string, options: { publishGlobals?: boolean } = {}): string {
|
|
358
|
+
async function demoteTopLevelLexicals(code: string, options: { publishGlobals?: boolean } = {}): Promise<string> {
|
|
343
359
|
if (!/\b(?:const|let|class)\b/.test(code)) return code;
|
|
344
360
|
|
|
345
|
-
const ast = parseProgram(code);
|
|
361
|
+
const ast = await parseProgram(code);
|
|
346
362
|
if (!ast) {
|
|
347
363
|
return code;
|
|
348
364
|
}
|
|
@@ -381,8 +397,8 @@ function demoteTopLevelLexicals(code: string, options: { publishGlobals?: boolea
|
|
|
381
397
|
return result;
|
|
382
398
|
}
|
|
383
399
|
|
|
384
|
-
function returnFinalExpression(code: string): { source: string; returned: boolean } {
|
|
385
|
-
const ast = parseProgram(code);
|
|
400
|
+
async function returnFinalExpression(code: string): Promise<{ source: string; returned: boolean }> {
|
|
401
|
+
const ast = await parseProgram(code);
|
|
386
402
|
const body = ast?.program.body;
|
|
387
403
|
if (!body) return { source: code, returned: false };
|
|
388
404
|
let lastIndex = body.length - 1;
|
|
@@ -446,8 +462,8 @@ function containsAsyncWrapperSyntax(value: unknown): boolean {
|
|
|
446
462
|
return false;
|
|
447
463
|
}
|
|
448
464
|
|
|
449
|
-
function requiresAsyncWrapper(code: string): boolean {
|
|
450
|
-
const ast = parseProgram(code);
|
|
465
|
+
async function requiresAsyncWrapper(code: string): Promise<boolean> {
|
|
466
|
+
const ast = await parseProgram(code);
|
|
451
467
|
if (!ast) return false;
|
|
452
468
|
for (const node of ast.program.body) {
|
|
453
469
|
if (containsAsyncWrapperSyntax(node)) return true;
|
|
@@ -494,13 +510,15 @@ export function stripTypeScriptSyntax(
|
|
|
494
510
|
const LOOKS_LIKE_TS =
|
|
495
511
|
/(?:\bimport\s+type\b|\bexport\s+type\b|\b(?:import|export)\s*\{[^}\n]*\btype\s+\w|\binterface\s+\w|\btype\s+\w+\s*=|\b(?:as|satisfies)\s+(?:[A-Z]|\bconst\b)|:\s*(?:string|number|boolean|any|unknown|void|never|object|[A-Z]\w*)\b|<\s*[A-Z]\w*\s*[,>])/;
|
|
496
512
|
|
|
497
|
-
export function wrapCode(
|
|
498
|
-
|
|
513
|
+
export async function wrapCode(
|
|
514
|
+
code: string,
|
|
515
|
+
): Promise<{ source: string; asyncWrapped: boolean; finalExpressionReturned: boolean }> {
|
|
516
|
+
const finalExpression = await returnFinalExpression(code);
|
|
499
517
|
const stripped = stripTypeScript(finalExpression.source);
|
|
500
|
-
const importsRewritten = rewriteImports(stripped);
|
|
501
|
-
const needsAsyncWrapper = requiresAsyncWrapper(importsRewritten);
|
|
518
|
+
const importsRewritten = await rewriteImports(stripped);
|
|
519
|
+
const needsAsyncWrapper = await requiresAsyncWrapper(importsRewritten);
|
|
502
520
|
const rewritten = {
|
|
503
|
-
source: demoteTopLevelLexicals(importsRewritten, { publishGlobals: needsAsyncWrapper }),
|
|
521
|
+
source: await demoteTopLevelLexicals(importsRewritten, { publishGlobals: needsAsyncWrapper }),
|
|
504
522
|
returned: finalExpression.returned,
|
|
505
523
|
};
|
|
506
524
|
if (!needsAsyncWrapper) {
|
|
@@ -181,7 +181,7 @@ export class JsRuntime {
|
|
|
181
181
|
finalExpressionValue: undefined,
|
|
182
182
|
};
|
|
183
183
|
return await this.#als.run(context, async () => {
|
|
184
|
-
const wrapped = wrapCode(code);
|
|
184
|
+
const wrapped = await wrapCode(code);
|
|
185
185
|
const value = indirectEval(wrapped.source, filename);
|
|
186
186
|
if (wrapped.finalExpressionReturned) {
|
|
187
187
|
const awaited = await awaitMaybePromise(value);
|
package/src/eval/py/executor.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
1
2
|
import * as path from "node:path";
|
|
2
3
|
|
|
3
4
|
import { getProjectDir, logger } from "@oh-my-pi/pi-utils";
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
type KernelRuntimeEnv,
|
|
16
17
|
PythonKernel,
|
|
17
18
|
} from "./kernel";
|
|
19
|
+
import { resolveExplicitPythonRuntime } from "./runtime";
|
|
18
20
|
import { ensurePyToolBridge, registerPyToolBridge } from "./tool-bridge";
|
|
19
21
|
|
|
20
22
|
export type PythonKernelMode = "session" | "per-call";
|
|
@@ -42,6 +44,11 @@ export interface PythonExecutorOptions {
|
|
|
42
44
|
kernelOwnerId?: string;
|
|
43
45
|
/** Kernel mode (session reuse vs per-call) */
|
|
44
46
|
kernelMode?: PythonKernelMode;
|
|
47
|
+
/**
|
|
48
|
+
* Explicit interpreter path (`python.interpreter` resolved from the
|
|
49
|
+
* session's settings). Skips automatic runtime discovery when set.
|
|
50
|
+
*/
|
|
51
|
+
interpreter?: string;
|
|
45
52
|
/** Restart the kernel before executing */
|
|
46
53
|
reset?: boolean;
|
|
47
54
|
/** Session file path for accessing task outputs */
|
|
@@ -116,9 +123,9 @@ export interface PythonResult {
|
|
|
116
123
|
// ---------------------------------------------------------------------------
|
|
117
124
|
// Session bookkeeping
|
|
118
125
|
//
|
|
119
|
-
// One PythonKernel subprocess per (session id, cwd) tuple. The
|
|
120
|
-
// process-global cwd/sys.path during execution, so cross-directory
|
|
121
|
-
// never share a live kernel. Multiple agent owners can still register against
|
|
126
|
+
// One PythonKernel subprocess per (session id, cwd, interpreter) tuple. The
|
|
127
|
+
// runner mutates process-global cwd/sys.path during execution, so cross-directory
|
|
128
|
+
// work must never share a live kernel. Multiple agent owners can still register against
|
|
122
129
|
// the same tuple; the kernel stays alive until the last owner detaches.
|
|
123
130
|
// ---------------------------------------------------------------------------
|
|
124
131
|
|
|
@@ -139,8 +146,19 @@ function normalizeSessionCwd(cwd: string): string {
|
|
|
139
146
|
return path.resolve(cwd);
|
|
140
147
|
}
|
|
141
148
|
|
|
142
|
-
function
|
|
143
|
-
|
|
149
|
+
function normalizeExplicitInterpreter(cwd: string, interpreter: string | undefined): string {
|
|
150
|
+
if (interpreter === undefined) return "";
|
|
151
|
+
const resolved = resolveExplicitPythonRuntime(interpreter, cwd, {}).pythonPath;
|
|
152
|
+
try {
|
|
153
|
+
return fs.realpathSync.native(resolved);
|
|
154
|
+
} catch {
|
|
155
|
+
return resolved;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function buildSessionKey(sessionId: string, cwd: string, interpreter: string | undefined): string {
|
|
160
|
+
const normalizedCwd = normalizeSessionCwd(cwd);
|
|
161
|
+
return `${sessionId}\0${normalizedCwd}\0${normalizeExplicitInterpreter(normalizedCwd, interpreter)}`;
|
|
144
162
|
}
|
|
145
163
|
|
|
146
164
|
// ---------------------------------------------------------------------------
|
|
@@ -326,6 +344,7 @@ async function startKernel(cwd: string, options: PythonExecutorOptions): Promise
|
|
|
326
344
|
env: buildKernelEnv(options),
|
|
327
345
|
signal: options.signal,
|
|
328
346
|
deadlineMs: options.deadlineMs,
|
|
347
|
+
interpreter: options.interpreter,
|
|
329
348
|
});
|
|
330
349
|
}
|
|
331
350
|
|
|
@@ -587,7 +606,10 @@ async function executeWithKernel(
|
|
|
587
606
|
}
|
|
588
607
|
|
|
589
608
|
async function ensureKernelAvailable(cwd: string, options: PythonExecutorOptions): Promise<void> {
|
|
590
|
-
const availability = await waitForPromiseWithCancellation(
|
|
609
|
+
const availability = await waitForPromiseWithCancellation(
|
|
610
|
+
checkPythonKernelAvailability(cwd, options.interpreter),
|
|
611
|
+
options,
|
|
612
|
+
);
|
|
591
613
|
if (!availability.ok) {
|
|
592
614
|
throw new Error(availability.reason ?? "Python kernel unavailable");
|
|
593
615
|
}
|
|
@@ -618,7 +640,7 @@ async function executePerCall(code: string, cwd: string, options: PythonExecutor
|
|
|
618
640
|
|
|
619
641
|
async function executeOnSession(code: string, cwd: string, options: PythonExecutorOptions): Promise<PythonResult> {
|
|
620
642
|
const sessionId = options.sessionId ?? `session:${cwd}`;
|
|
621
|
-
const sessionKey = buildSessionKey(sessionId, cwd);
|
|
643
|
+
const sessionKey = buildSessionKey(sessionId, cwd, options.interpreter);
|
|
622
644
|
if (options.bridge && !options.bridgeSessionId) {
|
|
623
645
|
options.bridgeSessionId = sessionId;
|
|
624
646
|
}
|
package/src/eval/py/index.ts
CHANGED
|
@@ -19,13 +19,17 @@ function readSetting<T>(session: ToolSession, key: string): T | undefined {
|
|
|
19
19
|
return settings?.get?.(key);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function readInterpreterSetting(session: ToolSession): string | undefined {
|
|
23
|
+
return readSetting<string>(session, "python.interpreter")?.trim() || undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
export default {
|
|
23
27
|
id: "python",
|
|
24
28
|
label: "Python",
|
|
25
29
|
highlightLang: "python",
|
|
26
30
|
|
|
27
31
|
async isAvailable(session: ToolSession): Promise<boolean> {
|
|
28
|
-
const availability = await checkPythonKernelAvailability(session.cwd);
|
|
32
|
+
const availability = await checkPythonKernelAvailability(session.cwd, readInterpreterSetting(session));
|
|
29
33
|
return availability.ok;
|
|
30
34
|
},
|
|
31
35
|
|
|
@@ -37,13 +41,12 @@ export default {
|
|
|
37
41
|
signal: opts.signal,
|
|
38
42
|
sessionId: namespaceSessionId(opts.sessionId),
|
|
39
43
|
kernelMode,
|
|
44
|
+
interpreter: readInterpreterSetting(opts.session),
|
|
40
45
|
sessionFile: opts.sessionFile,
|
|
41
46
|
artifactsDir: opts.session.getArtifactsDir?.() ?? undefined,
|
|
42
47
|
localRoots: resolveEvalUrlRoots(opts.session),
|
|
43
48
|
kernelOwnerId: opts.kernelOwnerId,
|
|
44
49
|
reset: opts.reset,
|
|
45
|
-
artifactPath: opts.artifactPath,
|
|
46
|
-
artifactId: opts.artifactId,
|
|
47
50
|
onChunk: opts.onChunk,
|
|
48
51
|
onStatus: opts.onStatus,
|
|
49
52
|
toolSession: opts.session,
|
package/src/eval/py/kernel.ts
CHANGED
|
@@ -17,7 +17,13 @@ import { Settings } from "../../config/settings";
|
|
|
17
17
|
import { type KernelDisplayOutput, renderKernelDisplay } from "./display";
|
|
18
18
|
import { PYTHON_PRELUDE } from "./prelude";
|
|
19
19
|
import RUNNER_SCRIPT from "./runner.py" with { type: "text" };
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
enumeratePythonRuntimes,
|
|
22
|
+
filterEnv,
|
|
23
|
+
type PythonRuntime,
|
|
24
|
+
resolveExplicitPythonRuntime,
|
|
25
|
+
resolvePythonRuntime,
|
|
26
|
+
} from "./runtime";
|
|
21
27
|
import { hostHasInheritableConsole, shouldHideKernelWindow } from "./spawn-options";
|
|
22
28
|
|
|
23
29
|
export type { KernelDisplayOutput, PythonStatusEvent } from "./display";
|
|
@@ -96,6 +102,11 @@ interface KernelLifecycleOptions {
|
|
|
96
102
|
interface KernelStartOptions extends KernelLifecycleOptions {
|
|
97
103
|
cwd: string;
|
|
98
104
|
env?: Record<string, string | undefined>;
|
|
105
|
+
/**
|
|
106
|
+
* Explicit interpreter path (`python.interpreter` from the session's
|
|
107
|
+
* settings). When set, runtime discovery is skipped entirely.
|
|
108
|
+
*/
|
|
109
|
+
interpreter?: string;
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
interface KernelShutdownOptions {
|
|
@@ -129,15 +140,40 @@ function throwIfAborted(signal: AbortSignal | undefined, fallbackReason: string)
|
|
|
129
140
|
throw createAbortError("AbortError", typeof reason === "string" ? reason : fallbackReason);
|
|
130
141
|
}
|
|
131
142
|
|
|
132
|
-
|
|
143
|
+
// Cache successful probes per resolved cwd + explicit interpreter: every cell
|
|
144
|
+
// otherwise pays one (or two — backend.isAvailable + ensureKernelAvailable)
|
|
145
|
+
// interpreter spawns even when the kernel is already hot. Failures are not
|
|
146
|
+
// cached so installing a Python mid-session is picked up on the next attempt.
|
|
147
|
+
const availabilityCache = new Map<string, Promise<PythonKernelAvailability>>();
|
|
148
|
+
|
|
149
|
+
export async function checkPythonKernelAvailability(
|
|
150
|
+
cwd: string,
|
|
151
|
+
interpreter?: string,
|
|
152
|
+
): Promise<PythonKernelAvailability> {
|
|
133
153
|
if (isBunTestRuntime() || $flag("PI_PYTHON_SKIP_CHECK")) {
|
|
134
154
|
return { ok: true };
|
|
135
155
|
}
|
|
156
|
+
const resolvedCwd = path.resolve(cwd);
|
|
157
|
+
const key = `${resolvedCwd}\0${interpreter ?? ""}`;
|
|
158
|
+
const cached = availabilityCache.get(key);
|
|
159
|
+
if (cached) return await cached;
|
|
160
|
+
const probe = probePythonKernelAvailability(resolvedCwd, interpreter);
|
|
161
|
+
availabilityCache.set(key, probe);
|
|
162
|
+
const result = await probe;
|
|
163
|
+
if (!result.ok && availabilityCache.get(key) === probe) {
|
|
164
|
+
availabilityCache.delete(key);
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function probePythonKernelAvailability(cwd: string, interpreter?: string): Promise<PythonKernelAvailability> {
|
|
136
170
|
try {
|
|
137
171
|
const settings = await Settings.init();
|
|
138
172
|
const { env } = settings.getShellConfig();
|
|
139
173
|
const baseEnv = filterEnv(env);
|
|
140
|
-
const runtimes =
|
|
174
|
+
const runtimes = interpreter
|
|
175
|
+
? [resolveExplicitPythonRuntime(interpreter, cwd, baseEnv)]
|
|
176
|
+
: enumeratePythonRuntimes(cwd, baseEnv);
|
|
141
177
|
if (runtimes.length === 0) {
|
|
142
178
|
return { ok: false, reason: "Python executable not found on PATH" };
|
|
143
179
|
}
|
|
@@ -220,6 +256,7 @@ export class PythonKernel {
|
|
|
220
256
|
"PythonKernel.start:availabilityCheck",
|
|
221
257
|
checkPythonKernelAvailability,
|
|
222
258
|
options.cwd,
|
|
259
|
+
options.interpreter,
|
|
223
260
|
);
|
|
224
261
|
if (!availability.ok) {
|
|
225
262
|
throw new Error(availability.reason ?? "Python kernel unavailable");
|
|
@@ -232,7 +269,9 @@ export class PythonKernel {
|
|
|
232
269
|
let runtime = availability.runtime;
|
|
233
270
|
if (!runtime) {
|
|
234
271
|
const { env: shellEnv } = (await Settings.init()).getShellConfig();
|
|
235
|
-
runtime =
|
|
272
|
+
runtime = options.interpreter
|
|
273
|
+
? resolveExplicitPythonRuntime(options.interpreter, options.cwd, filterEnv(shellEnv))
|
|
274
|
+
: resolvePythonRuntime(options.cwd, filterEnv(shellEnv));
|
|
236
275
|
}
|
|
237
276
|
const spawnEnv: Record<string, string> = {};
|
|
238
277
|
for (const [key, value] of Object.entries(runtime.env)) {
|