@qduc/term2 0.22.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +1 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +30 -18
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +20 -1
- package/dist/app.js.map +1 -1
- package/dist/cli.js +27 -1
- package/dist/cli.js.map +1 -1
- package/dist/components/input/ApplicationInputSurface.js +1 -1
- package/dist/components/input/ApplicationInputSurface.js.map +1 -1
- package/dist/components/input/SettingsMenuSession.d.ts.map +1 -1
- package/dist/components/input/SettingsMenuSession.js +8 -5
- package/dist/components/input/SettingsMenuSession.js.map +1 -1
- package/dist/components/input/SubagentPoolMenuSession.d.ts +9 -0
- package/dist/components/input/SubagentPoolMenuSession.d.ts.map +1 -0
- package/dist/components/input/{MentorPoolMenuSession.js → SubagentPoolMenuSession.js} +17 -10
- package/dist/components/input/SubagentPoolMenuSession.js.map +1 -0
- package/dist/components/input/menu-controller.d.ts.map +1 -1
- package/dist/components/input/menu-controller.js +4 -3
- package/dist/components/input/menu-controller.js.map +1 -1
- package/dist/components/input/menu-registry.js +2 -2
- package/dist/components/input/menu-registry.js.map +1 -1
- package/dist/components/input/menu-types.d.ts +5 -1
- package/dist/components/input/menu-types.d.ts.map +1 -1
- package/dist/components/input/triggers.d.ts.map +1 -1
- package/dist/components/input/triggers.js +10 -7
- package/dist/components/input/triggers.js.map +1 -1
- package/dist/components/layout/Banner.d.ts.map +1 -1
- package/dist/components/layout/Banner.js +4 -1
- package/dist/components/layout/Banner.js.map +1 -1
- package/dist/components/layout/StatusBar.d.ts.map +1 -1
- package/dist/components/layout/StatusBar.js +10 -17
- package/dist/components/layout/StatusBar.js.map +1 -1
- package/dist/components/menu/SettingsSelectionMenu.d.ts.map +1 -1
- package/dist/components/menu/SettingsSelectionMenu.js +3 -1
- package/dist/components/menu/SettingsSelectionMenu.js.map +1 -1
- package/dist/components/menu/SubagentPoolSelectionMenu.d.ts +19 -0
- package/dist/components/menu/SubagentPoolSelectionMenu.d.ts.map +1 -0
- package/dist/components/menu/{MentorPoolSelectionMenu.js → SubagentPoolSelectionMenu.js} +29 -15
- package/dist/components/menu/SubagentPoolSelectionMenu.js.map +1 -0
- package/dist/components/message/ChatMessage.js +5 -4
- package/dist/components/message/ChatMessage.js.map +1 -1
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +19 -0
- package/dist/components/message/MessageList.js.map +1 -1
- package/dist/components/theme.d.ts +2 -0
- package/dist/components/theme.d.ts.map +1 -1
- package/dist/components/theme.js +2 -0
- package/dist/components/theme.js.map +1 -1
- package/dist/context/InputContext.d.ts +1 -1
- package/dist/context/InputContext.d.ts.map +1 -1
- package/dist/context/InputContext.js +2 -2
- package/dist/context/InputContext.js.map +1 -1
- package/dist/contracts/conversation-items.d.ts +4 -0
- package/dist/contracts/conversation-items.d.ts.map +1 -1
- package/dist/contracts/provider-input.d.ts +2 -0
- package/dist/contracts/provider-input.d.ts.map +1 -1
- package/dist/contracts/provider-input.js.map +1 -1
- package/dist/gateway/assertion.d.ts +1 -1
- package/dist/gateway/assertion.d.ts.map +1 -1
- package/dist/gateway/contracts.d.ts +13 -3
- package/dist/gateway/contracts.d.ts.map +1 -1
- package/dist/gateway/contracts.js +56 -0
- package/dist/gateway/contracts.js.map +1 -1
- package/dist/gateway/gateway.d.ts +40 -1
- package/dist/gateway/gateway.d.ts.map +1 -1
- package/dist/gateway/gateway.js +1319 -76
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/persistence/admission-persistence.d.ts +3 -3
- package/dist/gateway/persistence/admission-persistence.d.ts.map +1 -1
- package/dist/gateway/persistence/admission-persistence.js +25 -11
- package/dist/gateway/persistence/admission-persistence.js.map +1 -1
- package/dist/gateway/persistence/contracts.d.ts +5 -3
- package/dist/gateway/persistence/contracts.d.ts.map +1 -1
- package/dist/gateway/persistence/contracts.js +13 -0
- package/dist/gateway/persistence/contracts.js.map +1 -1
- package/dist/gateway/persistence/interaction-checkpoint.d.ts +5 -0
- package/dist/gateway/persistence/interaction-checkpoint.d.ts.map +1 -1
- package/dist/gateway/persistence/interaction-checkpoint.js +22 -0
- package/dist/gateway/persistence/interaction-checkpoint.js.map +1 -1
- package/dist/gateway/persistence/projection.d.ts.map +1 -1
- package/dist/gateway/persistence/projection.js +4 -1
- package/dist/gateway/persistence/projection.js.map +1 -1
- package/dist/gateway/persistence/session-index.d.ts +1 -1
- package/dist/gateway/persistence/session-index.d.ts.map +1 -1
- package/dist/gateway/persistence/session-index.js +2 -2
- package/dist/gateway/persistence/session-index.js.map +1 -1
- package/dist/gateway/persistence/session-snapshot.d.ts +32 -0
- package/dist/gateway/persistence/session-snapshot.d.ts.map +1 -0
- package/dist/gateway/persistence/session-snapshot.js +50 -0
- package/dist/gateway/persistence/session-snapshot.js.map +1 -0
- package/dist/gateway/runtime-factory.d.ts +37 -1
- package/dist/gateway/runtime-factory.d.ts.map +1 -1
- package/dist/gateway/runtime-factory.js +155 -24
- package/dist/gateway/runtime-factory.js.map +1 -1
- package/dist/gateway/safe-log.d.ts +1 -1
- package/dist/gateway/safe-log.d.ts.map +1 -1
- package/dist/gateway/safe-log.js +5 -46
- package/dist/gateway/safe-log.js.map +1 -1
- package/dist/gateway/serve-args.d.ts +53 -0
- package/dist/gateway/serve-args.d.ts.map +1 -0
- package/dist/gateway/serve-args.js +172 -0
- package/dist/gateway/serve-args.js.map +1 -0
- package/dist/gateway/serve.d.ts +79 -0
- package/dist/gateway/serve.d.ts.map +1 -0
- package/dist/gateway/serve.js +375 -0
- package/dist/gateway/serve.js.map +1 -0
- package/dist/gateway/server-session.d.ts +9 -0
- package/dist/gateway/server-session.d.ts.map +1 -1
- package/dist/gateway/server-session.js +142 -26
- package/dist/gateway/server-session.js.map +1 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/gateway/server.js +13 -2
- package/dist/gateway/server.js.map +1 -1
- package/dist/hooks/use-subagent-pool-selection.d.ts +115 -0
- package/dist/hooks/use-subagent-pool-selection.d.ts.map +1 -0
- package/dist/hooks/{use-mentor-pool-selection.js → use-subagent-pool-selection.js} +110 -54
- package/dist/hooks/use-subagent-pool-selection.js.map +1 -0
- package/dist/lib/agent-client.d.ts +3 -0
- package/dist/lib/agent-client.d.ts.map +1 -1
- package/dist/lib/agent-client.js +7 -0
- package/dist/lib/agent-client.js.map +1 -1
- package/dist/lib/agent-configuration.d.ts +1 -0
- package/dist/lib/agent-configuration.d.ts.map +1 -1
- package/dist/lib/agent-configuration.js +3 -0
- package/dist/lib/agent-configuration.js.map +1 -1
- package/dist/lib/agent-factory.d.ts +2 -0
- package/dist/lib/agent-factory.d.ts.map +1 -1
- package/dist/lib/agent-factory.js +5 -0
- package/dist/lib/agent-factory.js.map +1 -1
- package/dist/lib/subagent-bridge.d.ts +5 -0
- package/dist/lib/subagent-bridge.d.ts.map +1 -1
- package/dist/lib/subagent-bridge.js +5 -0
- package/dist/lib/subagent-bridge.js.map +1 -1
- package/dist/lib/tool-selection-policy.d.ts +2 -0
- package/dist/lib/tool-selection-policy.d.ts.map +1 -1
- package/dist/lib/tool-selection-policy.js +6 -1
- package/dist/lib/tool-selection-policy.js.map +1 -1
- package/dist/prompts/explorer-delegation-contract.test.ts +1 -1
- package/dist/prompts/prompt-constructor.d.ts.map +1 -1
- package/dist/prompts/prompt-constructor.js +1 -0
- package/dist/prompts/prompt-constructor.js.map +1 -1
- package/dist/prompts/prompt-constructor.test.ts +3 -0
- package/dist/prompts/prompt-constructor.ts +1 -0
- package/dist/prompts/prompt-profiles.d.ts.map +1 -1
- package/dist/prompts/prompt-profiles.js +3 -2
- package/dist/prompts/prompt-profiles.js.map +1 -1
- package/dist/prompts/prompt-profiles.ts +4 -2
- package/dist/prompts/subagent-delegation.d.ts +2 -1
- package/dist/prompts/subagent-delegation.d.ts.map +1 -1
- package/dist/prompts/subagent-delegation.js +10 -5
- package/dist/prompts/subagent-delegation.js.map +1 -1
- package/dist/prompts/subagent-delegation.test.ts +10 -3
- package/dist/prompts/subagent-delegation.ts +16 -4
- package/dist/prompts/subagents/librarian.md +26 -21
- package/dist/prompts/subagents/reviewer.md +33 -0
- package/dist/providers/grok-auth.d.ts +7 -3
- package/dist/providers/grok-auth.d.ts.map +1 -1
- package/dist/providers/grok-auth.js +11 -6
- package/dist/providers/grok-auth.js.map +1 -1
- package/dist/providers/oauth-pkce.d.ts +7 -6
- package/dist/providers/oauth-pkce.d.ts.map +1 -1
- package/dist/providers/oauth-pkce.js +33 -6
- package/dist/providers/oauth-pkce.js.map +1 -1
- package/dist/services/agent-runtime/application-run-loop.d.ts.map +1 -1
- package/dist/services/agent-runtime/application-run-loop.js +10 -5
- package/dist/services/agent-runtime/application-run-loop.js.map +1 -1
- package/dist/services/agent-runtime/context-compaction/local-context-compactor.d.ts +9 -0
- package/dist/services/agent-runtime/context-compaction/local-context-compactor.d.ts.map +1 -1
- package/dist/services/agent-runtime/context-compaction/local-context-compactor.js +6 -0
- package/dist/services/agent-runtime/context-compaction/local-context-compactor.js.map +1 -1
- package/dist/services/agent-runtime/model-resolver.d.ts +6 -0
- package/dist/services/agent-runtime/model-resolver.d.ts.map +1 -1
- package/dist/services/agent-runtime/model-resolver.js +18 -4
- package/dist/services/agent-runtime/model-resolver.js.map +1 -1
- package/dist/services/approval/non-interactive-approval-policy.d.ts.map +1 -1
- package/dist/services/approval/non-interactive-approval-policy.js +2 -1
- package/dist/services/approval/non-interactive-approval-policy.js.map +1 -1
- package/dist/services/approval/shell-auto-approval-evaluator.js +2 -2
- package/dist/services/approval/shell-auto-approval-evaluator.js.map +1 -1
- package/dist/services/conversation/conversation-service.d.ts +28 -0
- package/dist/services/conversation/conversation-service.d.ts.map +1 -1
- package/dist/services/conversation/conversation-service.js +95 -27
- package/dist/services/conversation/conversation-service.js.map +1 -1
- package/dist/services/conversation/run-item-normalizer.d.ts.map +1 -1
- package/dist/services/conversation/run-item-normalizer.js +3 -0
- package/dist/services/conversation/run-item-normalizer.js.map +1 -1
- package/dist/services/conversation/session-browser.d.ts +5 -0
- package/dist/services/conversation/session-browser.d.ts.map +1 -1
- package/dist/services/conversation/session-browser.js +94 -31
- package/dist/services/conversation/session-browser.js.map +1 -1
- package/dist/services/conversation/session-index/session-index-database.d.ts +1 -0
- package/dist/services/conversation/session-index/session-index-database.d.ts.map +1 -1
- package/dist/services/conversation/session-index/session-index-database.js +6 -4
- package/dist/services/conversation/session-index/session-index-database.js.map +1 -1
- package/dist/services/conversation/session-index/session-index-schema.d.ts +1 -1
- package/dist/services/conversation/session-index/session-index-schema.d.ts.map +1 -1
- package/dist/services/conversation/session-index/session-index-schema.js +2 -1
- package/dist/services/conversation/session-index/session-index-schema.js.map +1 -1
- package/dist/services/conversation-agent-client.d.ts +3 -0
- package/dist/services/conversation-agent-client.d.ts.map +1 -1
- package/dist/services/memory/memory-capabilities.d.ts.map +1 -1
- package/dist/services/memory/memory-capabilities.js +2 -5
- package/dist/services/memory/memory-capabilities.js.map +1 -1
- package/dist/services/plan-mode-interceptor.js +2 -2
- package/dist/services/plan-mode-interceptor.js.map +1 -1
- package/dist/services/sandboxed-code-host/host-types.d.ts +12 -1
- package/dist/services/sandboxed-code-host/host-types.d.ts.map +1 -1
- package/dist/services/sandboxed-code-host/host-types.js.map +1 -1
- package/dist/services/sandboxed-code-host/host-worker.d.ts.map +1 -1
- package/dist/services/sandboxed-code-host/host-worker.js +146 -31
- package/dist/services/sandboxed-code-host/host-worker.js.map +1 -1
- package/dist/services/sandboxed-code-host/sandbox.d.ts +6 -1
- package/dist/services/sandboxed-code-host/sandbox.d.ts.map +1 -1
- package/dist/services/sandboxed-code-host/sandbox.js +5 -0
- package/dist/services/sandboxed-code-host/sandbox.js.map +1 -1
- package/dist/services/sandboxed-code-host/sandboxed-code-host.d.ts +3 -3
- package/dist/services/sandboxed-code-host/sandboxed-code-host.d.ts.map +1 -1
- package/dist/services/sandboxed-code-host/sandboxed-code-host.js +173 -22
- package/dist/services/sandboxed-code-host/sandboxed-code-host.js.map +1 -1
- package/dist/services/session/session-access-state.d.ts +5 -1
- package/dist/services/session/session-access-state.d.ts.map +1 -1
- package/dist/services/session/session-access-state.js +8 -1
- package/dist/services/session/session-access-state.js.map +1 -1
- package/dist/services/session/session-client-factory.d.ts +1 -0
- package/dist/services/session/session-client-factory.d.ts.map +1 -1
- package/dist/services/session/session-client-factory.js +1 -1
- package/dist/services/session/session-client-factory.js.map +1 -1
- package/dist/services/session/session-composition.d.ts +22 -4
- package/dist/services/session/session-composition.d.ts.map +1 -1
- package/dist/services/session/session-composition.js +9 -5
- package/dist/services/session/session-composition.js.map +1 -1
- package/dist/services/settings/ancillary-settings-migration.d.ts.map +1 -1
- package/dist/services/settings/ancillary-settings-migration.js +8 -1
- package/dist/services/settings/ancillary-settings-migration.js.map +1 -1
- package/dist/services/settings/settings-schema.d.ts +12 -40
- package/dist/services/settings/settings-schema.d.ts.map +1 -1
- package/dist/services/settings/settings-schema.js +27 -53
- package/dist/services/settings/settings-schema.js.map +1 -1
- package/dist/services/settings/settings-sources.d.ts +0 -3
- package/dist/services/settings/settings-sources.d.ts.map +1 -1
- package/dist/services/settings/settings-sources.js +0 -3
- package/dist/services/settings/settings-sources.js.map +1 -1
- package/dist/services/settings/settings-ui-metadata.d.ts.map +1 -1
- package/dist/services/settings/settings-ui-metadata.js +3 -3
- package/dist/services/settings/settings-ui-metadata.js.map +1 -1
- package/dist/services/settings/test-helpers/settings-consumer-inventory.d.ts +1 -1
- package/dist/services/settings/test-helpers/settings-consumer-inventory.d.ts.map +1 -1
- package/dist/services/settings/test-helpers/settings-consumer-inventory.js +5 -8
- package/dist/services/settings/test-helpers/settings-consumer-inventory.js.map +1 -1
- package/dist/services/subagents/execution-runner.js +1 -1
- package/dist/services/subagents/execution-runner.js.map +1 -1
- package/dist/services/subagents/nested-runner.d.ts +3 -0
- package/dist/services/subagents/nested-runner.d.ts.map +1 -1
- package/dist/services/subagents/nested-runner.js +32 -5
- package/dist/services/subagents/nested-runner.js.map +1 -1
- package/dist/services/subagents/role-loader.d.ts +1 -1
- package/dist/services/subagents/role-loader.d.ts.map +1 -1
- package/dist/services/subagents/role-loader.js +11 -19
- package/dist/services/subagents/role-loader.js.map +1 -1
- package/dist/services/subagents/runtime.d.ts +3 -0
- package/dist/services/subagents/runtime.d.ts.map +1 -1
- package/dist/services/subagents/runtime.js +35 -3
- package/dist/services/subagents/runtime.js.map +1 -1
- package/dist/services/subagents/subagent-async-registry.d.ts +10 -1
- package/dist/services/subagents/subagent-async-registry.d.ts.map +1 -1
- package/dist/services/subagents/subagent-async-registry.js +21 -4
- package/dist/services/subagents/subagent-async-registry.js.map +1 -1
- package/dist/services/subagents/subagent-manager.d.ts +3 -0
- package/dist/services/subagents/subagent-manager.d.ts.map +1 -1
- package/dist/services/subagents/subagent-manager.js.map +1 -1
- package/dist/services/subagents/subagent-pool-config.d.ts +39 -0
- package/dist/services/subagents/subagent-pool-config.d.ts.map +1 -0
- package/dist/services/subagents/subagent-pool-config.js +84 -0
- package/dist/services/subagents/subagent-pool-config.js.map +1 -0
- package/dist/services/subagents/subagent-role-pool-selector.d.ts +29 -0
- package/dist/services/subagents/subagent-role-pool-selector.d.ts.map +1 -0
- package/dist/services/subagents/subagent-role-pool-selector.js +56 -0
- package/dist/services/subagents/subagent-role-pool-selector.js.map +1 -0
- package/dist/services/subagents/tool-policy.d.ts +13 -0
- package/dist/services/subagents/tool-policy.d.ts.map +1 -1
- package/dist/services/subagents/tool-policy.js +36 -4
- package/dist/services/subagents/tool-policy.js.map +1 -1
- package/dist/services/subagents/types.d.ts +1 -1
- package/dist/services/subagents/types.d.ts.map +1 -1
- package/dist/services/subagents/types.js +1 -1
- package/dist/services/subagents/types.js.map +1 -1
- package/dist/test-helpers/outside-sandbox-temp-dir.d.ts +2 -0
- package/dist/test-helpers/outside-sandbox-temp-dir.d.ts.map +1 -0
- package/dist/test-helpers/outside-sandbox-temp-dir.js +38 -0
- package/dist/test-helpers/outside-sandbox-temp-dir.js.map +1 -0
- package/dist/tools/agent/configure-task-check-in.d.ts +2 -0
- package/dist/tools/agent/configure-task-check-in.d.ts.map +1 -1
- package/dist/tools/agent/configure-task-check-in.js +3 -0
- package/dist/tools/agent/configure-task-check-in.js.map +1 -1
- package/dist/tools/agent/run-explorer.d.ts +6 -0
- package/dist/tools/agent/run-explorer.d.ts.map +1 -0
- package/dist/tools/agent/run-explorer.js +58 -0
- package/dist/tools/agent/run-explorer.js.map +1 -0
- package/dist/tools/agent/run-subagent-async.d.ts +2 -0
- package/dist/tools/agent/run-subagent-async.d.ts.map +1 -1
- package/dist/tools/agent/run-subagent-async.js +3 -3
- package/dist/tools/agent/run-subagent-async.js.map +1 -1
- package/dist/tools/agent/run-subagent.d.ts +2 -2
- package/dist/tools/agent/run-subagent.d.ts.map +1 -1
- package/dist/tools/agent/run-subagent.js +8 -6
- package/dist/tools/agent/run-subagent.js.map +1 -1
- package/dist/tools/file/apply-patch.d.ts.map +1 -1
- package/dist/tools/file/apply-patch.js +7 -2
- package/dist/tools/file/apply-patch.js.map +1 -1
- package/dist/tools/file/create-file.d.ts.map +1 -1
- package/dist/tools/file/create-file.js +4 -0
- package/dist/tools/file/create-file.js.map +1 -1
- package/dist/tools/file/glob.d.ts.map +1 -1
- package/dist/tools/file/glob.js +6 -0
- package/dist/tools/file/glob.js.map +1 -1
- package/dist/tools/file/search-replace.d.ts.map +1 -1
- package/dist/tools/file/search-replace.js +6 -2
- package/dist/tools/file/search-replace.js.map +1 -1
- package/dist/tools/format-helpers.d.ts +5 -0
- package/dist/tools/format-helpers.d.ts.map +1 -1
- package/dist/tools/format-helpers.js.map +1 -1
- package/dist/tools/memory/memory-tools.d.ts +0 -1
- package/dist/tools/memory/memory-tools.d.ts.map +1 -1
- package/dist/tools/memory/memory-tools.js +1 -116
- package/dist/tools/memory/memory-tools.js.map +1 -1
- package/dist/tools/scripted-return-contract.d.ts +24 -0
- package/dist/tools/scripted-return-contract.d.ts.map +1 -0
- package/dist/tools/scripted-return-contract.js +36 -0
- package/dist/tools/scripted-return-contract.js.map +1 -0
- package/dist/tools/session-browser/session-browser-tools.d.ts.map +1 -1
- package/dist/tools/session-browser/session-browser-tools.js +21 -8
- package/dist/tools/session-browser/session-browser-tools.js.map +1 -1
- package/dist/tools/system/run-code/index.d.ts +3 -0
- package/dist/tools/system/run-code/index.d.ts.map +1 -1
- package/dist/tools/system/run-code/index.js +3 -0
- package/dist/tools/system/run-code/index.js.map +1 -1
- package/dist/tools/system/run-code/run-code-execution.d.ts +62 -0
- package/dist/tools/system/run-code/run-code-execution.d.ts.map +1 -0
- package/dist/tools/system/run-code/run-code-execution.js +74 -0
- package/dist/tools/system/run-code/run-code-execution.js.map +1 -0
- package/dist/tools/system/run-code/run-code-runtime-contract.d.ts +20 -0
- package/dist/tools/system/run-code/run-code-runtime-contract.d.ts.map +1 -0
- package/dist/tools/system/run-code/run-code-runtime-contract.js +2 -0
- package/dist/tools/system/run-code/run-code-runtime-contract.js.map +1 -0
- package/dist/tools/system/run-code/run-code-runtime.d.ts +99 -0
- package/dist/tools/system/run-code/run-code-runtime.d.ts.map +1 -0
- package/dist/tools/system/run-code/run-code-runtime.js +725 -0
- package/dist/tools/system/run-code/run-code-runtime.js.map +1 -0
- package/dist/tools/system/run-code/run-code-telemetry.d.ts +17 -10
- package/dist/tools/system/run-code/run-code-telemetry.d.ts.map +1 -1
- package/dist/tools/system/run-code/run-code-telemetry.js +53 -73
- package/dist/tools/system/run-code/run-code-telemetry.js.map +1 -1
- package/dist/tools/system/run-code/run-code.d.ts +22 -59
- package/dist/tools/system/run-code/run-code.d.ts.map +1 -1
- package/dist/tools/system/run-code/run-code.js +122 -786
- package/dist/tools/system/run-code/run-code.js.map +1 -1
- package/dist/tools/system/run-code/tools-header.d.ts +16 -4
- package/dist/tools/system/run-code/tools-header.d.ts.map +1 -1
- package/dist/tools/system/run-code/tools-header.js +33 -16
- package/dist/tools/system/run-code/tools-header.js.map +1 -1
- package/dist/tools/system/shell.d.ts +3 -0
- package/dist/tools/system/shell.d.ts.map +1 -1
- package/dist/tools/system/shell.js +18 -12
- package/dist/tools/system/shell.js.map +1 -1
- package/dist/tools/types.d.ts +12 -4
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/utils/ai/model-settings.d.ts +6 -0
- package/dist/utils/ai/model-settings.d.ts.map +1 -1
- package/dist/utils/ai/model-settings.js +7 -1
- package/dist/utils/ai/model-settings.js.map +1 -1
- package/dist/utils/ai/token-usage.d.ts +4 -5
- package/dist/utils/ai/token-usage.d.ts.map +1 -1
- package/dist/utils/ai/token-usage.js +3 -3
- package/dist/utils/ai/token-usage.js.map +1 -1
- package/dist/utils/conversation/conversation-utils.d.ts.map +1 -1
- package/dist/utils/conversation/conversation-utils.js +3 -0
- package/dist/utils/conversation/conversation-utils.js.map +1 -1
- package/dist/utils/settings-command.d.ts.map +1 -1
- package/dist/utils/settings-command.js +2 -1
- package/dist/utils/settings-command.js.map +1 -1
- package/dist/utils/shell/sandbox/sandbox-policy.d.ts +2 -0
- package/dist/utils/shell/sandbox/sandbox-policy.d.ts.map +1 -1
- package/dist/utils/shell/sandbox/sandbox-policy.js +1 -1
- package/dist/utils/shell/sandbox/sandbox-policy.js.map +1 -1
- package/dist/utils/streaming/streaming-session-factory.d.ts.map +1 -1
- package/dist/utils/streaming/streaming-session-factory.js +22 -22
- package/dist/utils/streaming/streaming-session-factory.js.map +1 -1
- package/dist/utils/value-suggestions.js +1 -1
- package/dist/utils/value-suggestions.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/input/MentorPoolMenuSession.d.ts +0 -9
- package/dist/components/input/MentorPoolMenuSession.d.ts.map +0 -1
- package/dist/components/input/MentorPoolMenuSession.js.map +0 -1
- package/dist/components/menu/MentorPoolSelectionMenu.d.ts +0 -13
- package/dist/components/menu/MentorPoolSelectionMenu.d.ts.map +0 -1
- package/dist/components/menu/MentorPoolSelectionMenu.js.map +0 -1
- package/dist/hooks/use-mentor-pool-selection.d.ts +0 -105
- package/dist/hooks/use-mentor-pool-selection.d.ts.map +0 -1
- package/dist/hooks/use-mentor-pool-selection.js.map +0 -1
|
@@ -1,76 +1,71 @@
|
|
|
1
|
-
import { appendFileSync } from 'node:fs';
|
|
2
|
-
import { lstat } from 'node:fs/promises';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
4
1
|
import { z } from 'zod';
|
|
5
2
|
import { relaxedNumber } from '../../utils.js';
|
|
6
|
-
import { normalizeToolParameters } from '../../../lib/tool-invoke.js';
|
|
7
|
-
import { SandboxedCodeHostImpl } from '../../../services/sandboxed-code-host/sandboxed-code-host.js';
|
|
8
|
-
import { applyApprovalGrant } from '../../../services/approval/approval-grant-executor.js';
|
|
9
|
-
import { isZodToolParameterSchema, } from '../../types.js';
|
|
10
3
|
import { createBaseMessage, getCallIdFromItem, getOutputText, isSuccessOutput, normalizeToolArguments, } from '../../format-helpers.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import { saveOutputArtifact, formatFullOutputSavedNote } from '../../../utils/shell/shell-output.js';
|
|
18
|
-
export const TOOL_NAME_RUN_CODE = 'run_code';
|
|
19
|
-
export const TOOL_NAME_DESCRIBE = 'describe';
|
|
4
|
+
import { renderToolsHeader } from './tools-header.js';
|
|
5
|
+
import { RUN_CODE_EXECUTION_RESULT } from './run-code-execution.js';
|
|
6
|
+
import { formatFullOutputSavedNote, saveOutputArtifact } from '../../../utils/shell/shell-output.js';
|
|
7
|
+
import { RUN_CODE_LIMITS, RUN_CODE_PROHIBITED_TOOLS, TOOL_NAME_RUN_CODE, createRunCodeRuntime, } from './run-code-runtime.js';
|
|
8
|
+
export { RUN_CODE_EXECUTION_RESULT, getRunCodeExecutionResult } from './run-code-execution.js';
|
|
9
|
+
export { RUN_CODE_LIMITS, RUN_CODE_PROHIBITED_TOOLS, TOOL_NAME_DESCRIBE, TOOL_NAME_RUN_CODE, isDirectlyCallable, } from './run-code-runtime.js';
|
|
20
10
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
21
11
|
/** Node `setTimeout` wraps delays above `2**31-1` to ~1 ms. */
|
|
22
12
|
const MAX_TIMEOUT_MS = 2_147_483_647;
|
|
23
13
|
const MAX_OUTPUT_CHARS = 30_000;
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
const encodeInputKeysForValidation = (value) => {
|
|
15
|
+
if (Array.isArray(value))
|
|
16
|
+
return value.map(encodeInputKeysForValidation);
|
|
17
|
+
if (value === null || typeof value !== 'object')
|
|
18
|
+
return value;
|
|
19
|
+
const encoded = Object.create(null);
|
|
20
|
+
for (const [key, item] of Object.entries(value)) {
|
|
21
|
+
Object.defineProperty(encoded, `$${key}`, {
|
|
22
|
+
value: encodeInputKeysForValidation(item),
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return encoded;
|
|
29
|
+
};
|
|
30
|
+
const decodeValidatedInputKeys = (value) => {
|
|
31
|
+
const decode = (item) => {
|
|
32
|
+
if (Array.isArray(item))
|
|
33
|
+
return item.map(decode);
|
|
34
|
+
if (item === null || typeof item !== 'object')
|
|
35
|
+
return item;
|
|
36
|
+
const decoded = Object.create(null);
|
|
37
|
+
for (const [key, nested] of Object.entries(item)) {
|
|
38
|
+
Object.defineProperty(decoded, key.slice(1), {
|
|
39
|
+
value: decode(nested),
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return decoded;
|
|
46
|
+
};
|
|
47
|
+
return decode(value);
|
|
48
|
+
};
|
|
49
|
+
const runCodeInputsSchema = z
|
|
50
|
+
.preprocess(encodeInputKeysForValidation, z.record(z.string(), z.json()))
|
|
51
|
+
// Zod records omit `__proto__`; prefixing every key before validation and
|
|
52
|
+
// removing exactly one prefix afterward keeps all JSON object keys inert.
|
|
53
|
+
.overwrite(decodeValidatedInputKeys);
|
|
26
54
|
/**
|
|
27
55
|
* Script-shaped limits. They are deliberately not the workflow's: a workflow
|
|
28
56
|
* spawns a handful of agents, while a script's whole point is looping over many
|
|
29
57
|
* cheap tool calls.
|
|
30
58
|
*/
|
|
31
|
-
export const RUN_CODE_LIMITS = {
|
|
32
|
-
/** Total `tools.*` calls one script may make. */
|
|
33
|
-
maxCalls: 200,
|
|
34
|
-
/** Parallel-safe calls that may overlap; others take a serial lane of one. */
|
|
35
|
-
maxConcurrency: 8,
|
|
36
|
-
/** Per-result cap. A larger result is truncated with an explicit marker. */
|
|
37
|
-
maxResultChars: 100_000,
|
|
38
|
-
/** Maximum raw bytes in one media attachment retained outside the script. */
|
|
39
|
-
maxMediaBytes: 8 * 1024 * 1024,
|
|
40
|
-
/** Maximum raw bytes and attachment count retained for one script run. */
|
|
41
|
-
maxMediaTotalBytes: 32 * 1024 * 1024,
|
|
42
|
-
maxMediaAttachments: 32,
|
|
43
|
-
maxCodeBytes: 65_536,
|
|
44
|
-
maxOutputBytes: 262_144,
|
|
45
|
-
maxConsoleBytes: 262_144,
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Tools a script may never call.
|
|
49
|
-
*
|
|
50
|
-
* `run_code` excludes itself because each run owns its own call budget, and
|
|
51
|
-
* nesting would let one run spend many. The rest are the workflow's prohibited
|
|
52
|
-
* set: `run_subagent` in particular spawns agents outside any run budget, so a
|
|
53
|
-
* script could loop on it indefinitely. Shell tools are excluded because their
|
|
54
|
-
* complete approval state also lives in the interactive batch coordinator.
|
|
55
|
-
*/
|
|
56
|
-
export const RUN_CODE_PROHIBITED_TOOLS = new Set([
|
|
57
|
-
...WORKFLOW_PROHIBITED_TOOLS,
|
|
58
|
-
TOOL_NAME_RUN_CODE,
|
|
59
|
-
'ask_mentor',
|
|
60
|
-
'session_rollover',
|
|
61
|
-
// Shell approval also depends on coordinator-owned Docker/session state that
|
|
62
|
-
// the raw policy registry cannot express for an out-of-band script call.
|
|
63
|
-
'shell',
|
|
64
|
-
'bash',
|
|
65
|
-
'enter_worktree',
|
|
66
|
-
'exit_worktree',
|
|
67
|
-
]);
|
|
68
59
|
export const runCodeParametersSchema = z.object({
|
|
69
60
|
code: z
|
|
70
61
|
.string()
|
|
71
62
|
.min(1)
|
|
72
63
|
.describe('JavaScript (not TypeScript) executed as the body of an async function. Top-level await is available. ' +
|
|
73
64
|
'Return the value you want the model to receive. Use console.log only for debugging.'),
|
|
65
|
+
inputs: runCodeInputsSchema
|
|
66
|
+
.optional()
|
|
67
|
+
.describe('JSON data exposed to the script as the global `inputs`. Use this for patch or file text. ' +
|
|
68
|
+
'Code and serialized inputs share the 65,536-byte admission limit.'),
|
|
74
69
|
include_console: z
|
|
75
70
|
.boolean()
|
|
76
71
|
.optional()
|
|
@@ -95,7 +90,8 @@ const RUN_CODE_DESCRIPTION = 'Write a JavaScript program and execute it. Return
|
|
|
95
90
|
'but it is included when the script fails or times out. The code runs in an isolated ' +
|
|
96
91
|
'context with no filesystem, network, timers, require, or eval: `tools.*` is the only way out. Auto-approved tools ' +
|
|
97
92
|
'run immediately. Tools that require user approval present the existing approval prompt and resume this script after ' +
|
|
98
|
-
'a decision; denial is catchable.
|
|
93
|
+
'a decision; denial is catchable. The catalogue below is the complete set of tools a script can call: a name that is ' +
|
|
94
|
+
'absent from it is not available inside the script, even when the direct tool surface offers it.\n\n' +
|
|
99
95
|
`Each script may admit at most ${RUN_CODE_LIMITS.maxCalls} tools.* calls. Track progress and split large work into chunks; catch individual ` +
|
|
100
96
|
'failures or use Promise.allSettled so you can return partial results. When the call budget is exhausted, the error ' +
|
|
101
97
|
'reports calls admitted and calls remaining: return the partial results and start another run_code call only for ' +
|
|
@@ -104,61 +100,24 @@ const RUN_CODE_DESCRIPTION = 'Write a JavaScript program and execute it. Return
|
|
|
104
100
|
'and larger host results can fail before rendering. For independent reads, preserve successful siblings with ' +
|
|
105
101
|
'`Promise.allSettled`, mapping rejections to `{error: r.reason.message}` before returning. ' +
|
|
106
102
|
'If the final result says `Full output saved to`, read that exact path with `read_file` rather than repeating completed calls; ' +
|
|
107
|
-
'for a large artifact,
|
|
103
|
+
'for a large artifact, read line ranges or the fields you need instead of transferring the whole value. A scripted ' +
|
|
104
|
+
'`read_file` result may itself have ' +
|
|
108
105
|
'`truncated: true` and a `fullOutputPath`; follow that path or narrow the projection before returning it. ' +
|
|
109
|
-
'Use `tools.describe` before guessing parameters or returned fields. If a patch
|
|
110
|
-
'
|
|
106
|
+
'Use `tools.describe` before guessing parameters or returned fields. If a patch or file body contains JavaScript ' +
|
|
107
|
+
'syntax such as backticks or `${...}`, pass it through the `inputs` parameter and read it from the global `inputs` ' +
|
|
108
|
+
'object instead of embedding it in code. Code and serialized inputs share the 65,536-byte admission limit. ' +
|
|
111
109
|
'Example: `const r = await Promise.allSettled([tools.read_file({path:"a.ts"}), tools.read_file({path:"b.ts"})]); ' +
|
|
112
110
|
'return r.map(x => x.status === "fulfilled" ? {content:(typeof x.value === "string" ? x.value : x.value.content).slice(0,2000)} : {error:x.reason.message});`';
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
if (parsed.ok === true)
|
|
125
|
-
return { outcome: 'applied' };
|
|
126
|
-
const detail = typeof parsed.error === 'string' && parsed.error ? parsed.error : 'action reported ok:false';
|
|
127
|
-
return { outcome: 'not_applied', reason: detail };
|
|
128
|
-
},
|
|
129
|
-
cancel_run: (raw) => {
|
|
130
|
-
const parsed = parseActionPayload(raw);
|
|
131
|
-
if (!isRecord(parsed) || typeof parsed.ok !== 'boolean') {
|
|
132
|
-
return { outcome: 'unknown', reason: 'unrecognized action result shape' };
|
|
133
|
-
}
|
|
134
|
-
if (parsed.ok === true &&
|
|
135
|
-
typeof parsed.runId === 'string' &&
|
|
136
|
-
parsed.runId.length > 0 &&
|
|
137
|
-
parsed.status === 'cancelling') {
|
|
138
|
-
return { outcome: 'applied', reason: 'cancellation requested and accepted; settlement is reported separately' };
|
|
139
|
-
}
|
|
140
|
-
if (parsed.ok === false &&
|
|
141
|
-
parsed.code === 'not_active' &&
|
|
142
|
-
typeof parsed.target === 'string' &&
|
|
143
|
-
parsed.target.length > 0) {
|
|
144
|
-
return { outcome: 'not_applied', reason: `not_active (target: ${parsed.target})` };
|
|
145
|
-
}
|
|
146
|
-
return { outcome: 'unknown', reason: 'unrecognized action result shape' };
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
const isActionTool = (name) => ACTION_SEMANTICS[name] !== undefined;
|
|
150
|
-
const parseActionPayload = (raw) => {
|
|
151
|
-
if (typeof raw !== 'string')
|
|
152
|
-
return raw;
|
|
153
|
-
try {
|
|
154
|
-
return JSON.parse(raw);
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
-
return raw;
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
const MAX_RECEIPT_REASON_CHARS = 280;
|
|
161
|
-
const clipReason = (reason) => reason.length <= MAX_RECEIPT_REASON_CHARS ? reason : `${reason.slice(0, MAX_RECEIPT_REASON_CHARS)}…`;
|
|
111
|
+
function attachRunCodeExecution(value, execution) {
|
|
112
|
+
if (Array.isArray(value)) {
|
|
113
|
+
const result = [...value];
|
|
114
|
+
Object.defineProperty(result, RUN_CODE_EXECUTION_RESULT, { value: execution });
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
const result = new String(value);
|
|
118
|
+
Object.defineProperty(result, RUN_CODE_EXECUTION_RESULT, { value: execution });
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
162
121
|
/**
|
|
163
122
|
* Marks a definition as accepting the final, wrapped tool registry.
|
|
164
123
|
*
|
|
@@ -181,45 +140,6 @@ export function bindRunCodeNestedApprovalOwner(tools, owner) {
|
|
|
181
140
|
tool[NESTED_OWNER_BINDER]?.(owner, tools);
|
|
182
141
|
}
|
|
183
142
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Direct calls are the tools a script structurally cannot reach, including
|
|
186
|
-
* `run_code` itself. Visibility does not depend on `canRequireApproval`.
|
|
187
|
-
*/
|
|
188
|
-
export function isDirectlyCallable(tool) {
|
|
189
|
-
return RUN_CODE_PROHIBITED_TOOLS.has(tool.name);
|
|
190
|
-
}
|
|
191
|
-
function unknownToolMessage(name, registry) {
|
|
192
|
-
return `Unknown tool "${name}". Available: ${registry.map((entry) => entry.name).join(', ')}`;
|
|
193
|
-
}
|
|
194
|
-
function describeTool(tool) {
|
|
195
|
-
let parameters;
|
|
196
|
-
const targetSchema = tool.canonicalParameters ?? tool.parameters;
|
|
197
|
-
if (isZodToolParameterSchema(targetSchema)) {
|
|
198
|
-
try {
|
|
199
|
-
parameters = z.toJSONSchema(targetSchema, { io: 'input' });
|
|
200
|
-
}
|
|
201
|
-
catch {
|
|
202
|
-
parameters = { unconvertible: true };
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
else if (targetSchema && typeof targetSchema === 'object') {
|
|
206
|
-
parameters = targetSchema;
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
parameters = { unconvertible: true };
|
|
210
|
-
}
|
|
211
|
-
return {
|
|
212
|
-
name: tool.name,
|
|
213
|
-
description: tool.description,
|
|
214
|
-
parameters,
|
|
215
|
-
// The scripted-path return contract. Agents discover it here before
|
|
216
|
-
// calling, and the tools header renders the same string for essential
|
|
217
|
-
// tools, so both surfaces stay consistent.
|
|
218
|
-
...(typeof tool.scriptedReturnShape === 'string' && tool.scriptedReturnShape
|
|
219
|
-
? { scriptedReturnShape: tool.scriptedReturnShape }
|
|
220
|
-
: {}),
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
143
|
const summarizeCalls = (calls) => {
|
|
224
144
|
const describeCalls = calls.filter((call) => call.outcome === 'describe');
|
|
225
145
|
const executionCalls = calls.filter((call) => call.outcome !== 'describe');
|
|
@@ -263,112 +183,23 @@ const clip = async (text, protectedAction) => {
|
|
|
263
183
|
prefix = prefix.slice(0, -1);
|
|
264
184
|
return `${prefix}${marker}${action}`;
|
|
265
185
|
};
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
];
|
|
273
|
-
/**
|
|
274
|
-
* Whether a rendered run_code result reads as unsuccessful. Script-level
|
|
275
|
-
* failures start with a known prefix; a script can also complete at the JS
|
|
276
|
-
* level while its nested result is an error string (status-string tools such as
|
|
277
|
-
* apply_patch), which the renderer places under a `Result:` heading. Lifecycle
|
|
278
|
-
* status stays 'completed' in both cases — this is the call-level success bit,
|
|
279
|
-
* kept separate from script success (visible in the text) and task success
|
|
280
|
-
* (conversation-level).
|
|
281
|
-
*/
|
|
282
|
-
const isUnsuccessfulRunCodeOutput = (output) => {
|
|
283
|
-
if (FAILURE_PREFIXES.some((prefix) => output.startsWith(prefix)))
|
|
284
|
-
return true;
|
|
186
|
+
/** Compatibility-only reader for old persisted messages. New executions carry
|
|
187
|
+
* a typed marker and never use rendered text for their success bit. */
|
|
188
|
+
const legacyRunCodeSuccess = (output) => {
|
|
189
|
+
if (/^(?:Error:|Script failed|Script timed out|Script was cancelled|Script exceeded its deadline)/.test(output)) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
285
192
|
if (output.startsWith('Result:')) {
|
|
286
|
-
// The renderer joins the rendered value and the trailing tool-call summary
|
|
287
|
-
// with a blank line. Evaluate only the value block, using the shared
|
|
288
|
-
// success heuristic: an 'Error:' text prefix or a JSON value carrying an
|
|
289
|
-
// 'error' key (string or structured envelope) both read as unsuccessful.
|
|
290
193
|
const valueBlock = output.slice('Result:'.length).trimStart().split('\n\n')[0];
|
|
291
|
-
return
|
|
194
|
+
return isSuccessOutput(valueBlock);
|
|
292
195
|
}
|
|
293
|
-
return
|
|
196
|
+
return true;
|
|
294
197
|
};
|
|
295
|
-
/**
|
|
296
|
-
* Truncation is a display concern, but a script may branch on the result, so
|
|
297
|
-
* the marker has to be unmistakable rather than a silent cut.
|
|
298
|
-
*/
|
|
299
|
-
const truncate = (text, limit) => text.length <= limit ? text : `${text.slice(0, limit)}\n[truncated: result exceeded ${limit} characters]`;
|
|
300
198
|
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
301
199
|
const isMediaContentPart = (value) => isRecord(value) && ((value.type === 'image' && 'image' in value) || (value.type === 'file' && 'file' in value));
|
|
302
200
|
const isContentPartArray = (value) => Array.isArray(value) &&
|
|
303
201
|
value.length > 0 &&
|
|
304
202
|
value.every((part) => isRecord(part) && (part.type === 'text' || isMediaContentPart(part)));
|
|
305
|
-
const MEDIA_REFERENCE_KEY = '__term2_run_code_media_reference__';
|
|
306
|
-
const isMediaReference = (value) => isRecord(value) && typeof value[MEDIA_REFERENCE_KEY] === 'string' && Object.keys(value).length === 1;
|
|
307
|
-
/** Count the bytes that will eventually be sent to the model, not its JSON wrapper. */
|
|
308
|
-
function mediaBytes(value) {
|
|
309
|
-
const payload = value.type === 'image' ? value.image : value.type === 'file' ? value.file : undefined;
|
|
310
|
-
if (isRecord(payload) && typeof payload.data === 'string') {
|
|
311
|
-
try {
|
|
312
|
-
return Buffer.from(payload.data, 'base64').byteLength;
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
return Buffer.byteLength(payload.data, 'utf8');
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
return Buffer.byteLength(JSON.stringify(payload) ?? '', 'utf8');
|
|
320
|
-
}
|
|
321
|
-
catch {
|
|
322
|
-
return Number.POSITIVE_INFINITY;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Keep large media out of both the worker transport and its generic result
|
|
327
|
-
* budget. The reference is deliberately scoped to one execute call: a token
|
|
328
|
-
* from another run is just an ordinary object and cannot recover its bytes.
|
|
329
|
-
*/
|
|
330
|
-
function createMediaReferenceStore() {
|
|
331
|
-
const attachments = new Map();
|
|
332
|
-
const byValue = new WeakMap();
|
|
333
|
-
let totalBytes = 0;
|
|
334
|
-
const capture = (value) => {
|
|
335
|
-
if (isMediaContentPart(value)) {
|
|
336
|
-
const existing = byValue.get(value);
|
|
337
|
-
if (existing !== undefined)
|
|
338
|
-
return existing ? { [MEDIA_REFERENCE_KEY]: existing } : '[media content omitted]';
|
|
339
|
-
const size = mediaBytes(value);
|
|
340
|
-
if (!Number.isFinite(size) ||
|
|
341
|
-
size > RUN_CODE_LIMITS.maxMediaBytes ||
|
|
342
|
-
attachments.size >= RUN_CODE_LIMITS.maxMediaAttachments ||
|
|
343
|
-
totalBytes + size > RUN_CODE_LIMITS.maxMediaTotalBytes) {
|
|
344
|
-
byValue.set(value, null);
|
|
345
|
-
return (`[media content omitted: attachment exceeds the ${RUN_CODE_LIMITS.maxMediaBytes}-byte per-image or ` +
|
|
346
|
-
`${RUN_CODE_LIMITS.maxMediaTotalBytes}-byte per-run limit]`);
|
|
347
|
-
}
|
|
348
|
-
const token = `run_code_media_${randomUUID()}`;
|
|
349
|
-
byValue.set(value, token);
|
|
350
|
-
attachments.set(token, value);
|
|
351
|
-
totalBytes += size;
|
|
352
|
-
return { [MEDIA_REFERENCE_KEY]: token };
|
|
353
|
-
}
|
|
354
|
-
if (Array.isArray(value))
|
|
355
|
-
return value.map(capture);
|
|
356
|
-
if (isRecord(value)) {
|
|
357
|
-
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, capture(entry)]));
|
|
358
|
-
}
|
|
359
|
-
return value;
|
|
360
|
-
};
|
|
361
|
-
const resolve = (value) => {
|
|
362
|
-
if (isMediaReference(value))
|
|
363
|
-
return attachments.get(value[MEDIA_REFERENCE_KEY]) ?? value;
|
|
364
|
-
if (Array.isArray(value))
|
|
365
|
-
return value.map(resolve);
|
|
366
|
-
if (isRecord(value))
|
|
367
|
-
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, resolve(entry)]));
|
|
368
|
-
return value;
|
|
369
|
-
};
|
|
370
|
-
return { capture, resolve };
|
|
371
|
-
}
|
|
372
203
|
/** Look through script wrappers without mistaking ordinary arrays for media. */
|
|
373
204
|
function containsMediaContent(value, ancestors = new Set()) {
|
|
374
205
|
if (isMediaContentPart(value))
|
|
@@ -384,41 +215,6 @@ function containsMediaContent(value, ancestors = new Set()) {
|
|
|
384
215
|
ancestors.delete(value);
|
|
385
216
|
return found;
|
|
386
217
|
}
|
|
387
|
-
const serializeResult = async (result, limit, toolName, callsCompleted) => {
|
|
388
|
-
if (typeof result === 'string')
|
|
389
|
-
return { ok: true, result: truncate(result, limit) };
|
|
390
|
-
try {
|
|
391
|
-
const encoded = JSON.stringify(result);
|
|
392
|
-
if (encoded === undefined)
|
|
393
|
-
return { ok: true, result: null };
|
|
394
|
-
if (encoded.length <= limit)
|
|
395
|
-
return { ok: true, result: result };
|
|
396
|
-
// Never turn a multimodal result into a partial JSON string: that both
|
|
397
|
-
// corrupts image data and makes the failure look like a successful text
|
|
398
|
-
// result to the script. A clear value lets the script continue (or catch
|
|
399
|
-
// the omission) without sending an unusable image to the worker.
|
|
400
|
-
if (containsMediaContent(result)) {
|
|
401
|
-
return {
|
|
402
|
-
ok: true,
|
|
403
|
-
result: `[truncated: media result exceeded ${limit} characters; media content omitted]`,
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
let retrieval = '';
|
|
407
|
-
try {
|
|
408
|
-
const artifactPath = await saveOutputArtifact(encoded, { filenamePrefix: 'tool-overflow' });
|
|
409
|
-
retrieval = `Full output saved to: ${artifactPath}. `;
|
|
410
|
-
}
|
|
411
|
-
catch {
|
|
412
|
-
retrieval = 'Full output could not be saved; the omitted result is unavailable. ';
|
|
413
|
-
}
|
|
414
|
-
const callUnit = callsCompleted === 1 ? 'call' : 'calls';
|
|
415
|
-
const message = `Tool "${toolName}" result exceeded ${limit} characters and could not be delivered to script. ${retrieval}${callsCompleted} nested tool ${callUnit} completed — inspect state before retrying; tool effects have already completed.`;
|
|
416
|
-
return { ok: false, error: message };
|
|
417
|
-
}
|
|
418
|
-
catch {
|
|
419
|
-
return { ok: true, result: truncate(String(result), limit) };
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
218
|
/** Replace embedded media with a text marker while retaining the real parts. */
|
|
423
219
|
function stripMediaContent(value, media) {
|
|
424
220
|
if (isMediaContentPart(value)) {
|
|
@@ -432,8 +228,6 @@ function stripMediaContent(value, media) {
|
|
|
432
228
|
}
|
|
433
229
|
return value;
|
|
434
230
|
}
|
|
435
|
-
/** Renders one console.log's arguments the way a terminal would. */
|
|
436
|
-
const renderConsoleValues = (values) => values.map((value) => (typeof value === 'string' ? value : JSON.stringify(value))).join(' ');
|
|
437
231
|
export const formatRunCodeCommandMessage = (item, index, toolCallArgumentsById) => {
|
|
438
232
|
const callId = getCallIdFromItem(item);
|
|
439
233
|
const fallbackArgs = callId && toolCallArgumentsById.has(callId) ? toolCallArgumentsById.get(callId) : null;
|
|
@@ -441,36 +235,17 @@ export const formatRunCodeCommandMessage = (item, index, toolCallArgumentsById)
|
|
|
441
235
|
const description = typeof args?.description === 'string' ? args.description : undefined;
|
|
442
236
|
const code = typeof args?.code === 'string' ? args.code : '';
|
|
443
237
|
const output = getOutputText(item) || 'No output';
|
|
238
|
+
const semantic = item.runCodeExecution;
|
|
444
239
|
return [
|
|
445
240
|
createBaseMessage(item, index, 0, false, {
|
|
446
241
|
command: description ? `run_code — ${description}` : 'run_code',
|
|
447
242
|
output,
|
|
448
|
-
success:
|
|
243
|
+
success: semantic ? semantic.success : legacyRunCodeSuccess(output),
|
|
449
244
|
toolName: TOOL_NAME_RUN_CODE,
|
|
450
245
|
toolArgs: { ...args, code },
|
|
451
246
|
}),
|
|
452
247
|
];
|
|
453
248
|
};
|
|
454
|
-
function getConversationSessionId(context) {
|
|
455
|
-
if (!context || typeof context !== 'object')
|
|
456
|
-
return undefined;
|
|
457
|
-
const runContext = context.context;
|
|
458
|
-
if (!runContext || typeof runContext !== 'object')
|
|
459
|
-
return undefined;
|
|
460
|
-
const sessionId = runContext.sessionId;
|
|
461
|
-
return typeof sessionId === 'string' && sessionId.length > 0 ? sessionId : undefined;
|
|
462
|
-
}
|
|
463
|
-
function writeNestedCallRecord(tool, sessionId, outcome) {
|
|
464
|
-
const logPath = process.env.TERM2_NESTED_CALL_LOG;
|
|
465
|
-
if (!logPath || !sessionId)
|
|
466
|
-
return;
|
|
467
|
-
try {
|
|
468
|
-
appendFileSync(logPath, `${JSON.stringify({ tool, sessionId, timestamp: new Date().toISOString(), outcome })}\n`, 'utf8');
|
|
469
|
-
}
|
|
470
|
-
catch {
|
|
471
|
-
// Experiment-only logging must never affect tool execution.
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
249
|
export function createRunCodeToolDefinition(options) {
|
|
475
250
|
const { loggingService, getCwd = () => options.executionContext?.getCwd() || process.cwd() } = options;
|
|
476
251
|
const approvalRegistry = options.approvalPolicyRegistry;
|
|
@@ -478,372 +253,48 @@ export function createRunCodeToolDefinition(options) {
|
|
|
478
253
|
let boundRegistry;
|
|
479
254
|
let nestedApprovalOwner = options.nestedApprovalOwner;
|
|
480
255
|
const exposedTools = () => (options.getToolRegistry?.() ?? boundRegistry ?? []).filter((tool) => !RUN_CODE_PROHIBITED_TOOLS.has(tool.name));
|
|
256
|
+
const createRuntime = (registry) => createRunCodeRuntime({
|
|
257
|
+
registry,
|
|
258
|
+
graphIdentity: boundRegistry ?? registry,
|
|
259
|
+
loggingService,
|
|
260
|
+
approvalPolicyRegistry: approvalRegistry,
|
|
261
|
+
getCwd,
|
|
262
|
+
executionContext: options.executionContext,
|
|
263
|
+
nestedApprovalOwner,
|
|
264
|
+
sessionAccess: options.sessionAccess,
|
|
265
|
+
nestedCompatibility: options.nestedCompatibility,
|
|
266
|
+
});
|
|
481
267
|
const definition = {
|
|
482
268
|
name: TOOL_NAME_RUN_CODE,
|
|
483
269
|
// Read late, after bindRunCodeRegistry, so the model is told which tools
|
|
484
270
|
// the script can actually reach rather than a guess made before wrapping.
|
|
485
271
|
get description() {
|
|
486
|
-
const header = renderToolsHeader(exposedTools());
|
|
272
|
+
const header = renderToolsHeader(createRuntime(exposedTools()).discovery());
|
|
487
273
|
return header ? `${RUN_CODE_DESCRIPTION}\n\n${header}` : RUN_CODE_DESCRIPTION;
|
|
488
274
|
},
|
|
489
275
|
parameters: runCodeParametersSchema,
|
|
490
276
|
effect: 'mutating',
|
|
491
277
|
needsApproval: () => false,
|
|
492
|
-
execute: async (params, context) => {
|
|
493
|
-
const { code, timeout_ms, description, include_console = false } = params;
|
|
278
|
+
execute: async (params, context, details) => {
|
|
279
|
+
const { code, inputs = {}, timeout_ms, description, include_console = false } = params;
|
|
494
280
|
const timeout = timeout_ms ?? DEFAULT_TIMEOUT_MS;
|
|
495
281
|
const callerSignal = context?.signal;
|
|
496
282
|
const registry = exposedTools();
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const pendingReceiptByCallId = new Map();
|
|
505
|
-
let rejectedSeq = 0;
|
|
506
|
-
const output = [];
|
|
507
|
-
const sessionId = getConversationSessionId(context);
|
|
508
|
-
const mediaReferences = createMediaReferenceStore();
|
|
509
|
-
const record = (tool, outcome, started, directlyCallable) => {
|
|
510
|
-
calls.push({ tool, outcome, durationMs: Date.now() - started, directlyCallable });
|
|
511
|
-
if (outcome === 'describe')
|
|
512
|
-
return;
|
|
513
|
-
writeNestedCallRecord(tool, sessionId, outcome === 'ok' ? 'success' : outcome === 'approval_required' ? 'denied-by-approval' : 'failure');
|
|
514
|
-
};
|
|
515
|
-
const failed = (message) => ({
|
|
516
|
-
kind: 'result',
|
|
517
|
-
result: { ok: false, error: message },
|
|
518
|
-
});
|
|
519
|
-
const recordReceipt = (callId, toolName, outcome, reason) => {
|
|
520
|
-
const pendingIndex = pendingReceiptByCallId.get(callId);
|
|
521
|
-
if (pendingIndex !== undefined) {
|
|
522
|
-
receipts[pendingIndex] = {
|
|
523
|
-
callId,
|
|
524
|
-
tool: toolName,
|
|
525
|
-
outcome,
|
|
526
|
-
...(reason ? { reason: clipReason(reason) } : {}),
|
|
527
|
-
};
|
|
528
|
-
pendingReceiptByCallId.delete(callId);
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
receipts.push({
|
|
532
|
-
callId,
|
|
533
|
-
tool: toolName,
|
|
534
|
-
outcome,
|
|
535
|
-
...(reason ? { reason: clipReason(reason) } : {}),
|
|
536
|
-
});
|
|
537
|
-
};
|
|
538
|
-
const tools = {
|
|
539
|
-
binding: {
|
|
540
|
-
name: 'tools',
|
|
541
|
-
kind: 'namespace',
|
|
542
|
-
members: [...new Set([...registry.map((tool) => tool.name), TOOL_NAME_DESCRIBE])],
|
|
543
|
-
},
|
|
544
|
-
limits: {
|
|
545
|
-
maxCalls: RUN_CODE_LIMITS.maxCalls,
|
|
546
|
-
maxConcurrency: RUN_CODE_LIMITS.maxConcurrency,
|
|
547
|
-
limitExceededMessage: `Tool call limit reached (${RUN_CODE_LIMITS.maxCalls} calls per script run).`,
|
|
548
|
-
},
|
|
549
|
-
// A budget-exhausted call is the script's problem, not a reason to
|
|
550
|
-
// discard the work it has already printed.
|
|
551
|
-
overBudget: ({ usedCalls, maxCalls }, rejected) => {
|
|
552
|
-
// The host supplies the exact prepared call that was rejected.
|
|
553
|
-
// Preparation is async and concurrent, so a local FIFO would be
|
|
554
|
-
// unable to attribute a budget rejection safely.
|
|
555
|
-
if (isActionTool(rejected.tool.name)) {
|
|
556
|
-
rejectedSeq += 1;
|
|
557
|
-
recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, rejected.tool.name, 'unknown', 'call budget exhausted before dispatch');
|
|
558
|
-
}
|
|
559
|
-
return failed(`Tool call limit reached (${maxCalls} calls per script run; ${usedCalls} calls admitted, ${Math.max(0, maxCalls - usedCalls)} remaining). ` +
|
|
560
|
-
'Return the partial results you collected and start another run_code call only for unattempted work; ' +
|
|
561
|
-
'Do not repeat completed tool effects.');
|
|
562
|
-
},
|
|
563
|
-
onAdmitted: (prepared, callContext) => {
|
|
564
|
-
if (!isActionTool(prepared.tool.name))
|
|
565
|
-
return;
|
|
566
|
-
const callId = `${bridgeRunId}:${callContext.callId}`;
|
|
567
|
-
pendingReceiptByCallId.set(callId, receipts.length);
|
|
568
|
-
receipts.push({ callId, tool: prepared.tool.name, outcome: 'unknown' });
|
|
569
|
-
},
|
|
570
|
-
prepare: async (payload) => {
|
|
571
|
-
const started = Date.now();
|
|
572
|
-
const name = typeof payload.member === 'string' ? payload.member : '';
|
|
573
|
-
const tool = registry.find((candidate) => candidate.name === name);
|
|
574
|
-
if (name === TOOL_NAME_DESCRIBE && typeof payload.params === 'string') {
|
|
575
|
-
const described = registry.find((candidate) => candidate.name === payload.params);
|
|
576
|
-
if (!described)
|
|
577
|
-
return failed(unknownToolMessage(payload.params, registry));
|
|
578
|
-
record(name, 'describe', started);
|
|
579
|
-
return {
|
|
580
|
-
kind: 'result',
|
|
581
|
-
result: { ok: true, result: describeTool(described) },
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
if (!tool) {
|
|
585
|
-
record(name || '(unnamed)', 'unknown_tool', started);
|
|
586
|
-
if (isActionTool(name)) {
|
|
587
|
-
rejectedSeq += 1;
|
|
588
|
-
recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, name, 'failed', unknownToolMessage(name, registry));
|
|
589
|
-
}
|
|
590
|
-
return failed(unknownToolMessage(name, registry));
|
|
591
|
-
}
|
|
592
|
-
const targetSchema = tool.canonicalParameters ?? tool.parameters;
|
|
593
|
-
let normalized;
|
|
594
|
-
try {
|
|
595
|
-
normalized = normalizeToolParameters(payload.params ?? {}, targetSchema);
|
|
596
|
-
}
|
|
597
|
-
catch {
|
|
598
|
-
normalized = payload.params ?? {};
|
|
599
|
-
}
|
|
600
|
-
if (isZodToolParameterSchema(targetSchema)) {
|
|
601
|
-
const parsed = targetSchema.safeParse(normalized);
|
|
602
|
-
if (!parsed.success) {
|
|
603
|
-
record(name, 'invalid_params', started);
|
|
604
|
-
const issues = parsed.error.issues
|
|
605
|
-
.map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)
|
|
606
|
-
.join('; ');
|
|
607
|
-
if (isActionTool(name)) {
|
|
608
|
-
rejectedSeq += 1;
|
|
609
|
-
recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, name, 'failed', `Invalid parameters: ${issues}`);
|
|
610
|
-
}
|
|
611
|
-
return failed(`Invalid parameters for "${name}": ${issues}\nSignature: ${renderCompactSignature(tool)}`);
|
|
612
|
-
}
|
|
613
|
-
normalized = parsed.data;
|
|
614
|
-
}
|
|
615
|
-
const authorityRoot = getCwd();
|
|
616
|
-
const authority = await bindPreparedAuthority(name, normalized, authorityRoot, options.executionContext);
|
|
617
|
-
if (authority.kind === 'denied') {
|
|
618
|
-
record(name, 'approval_required', started, isDirectlyCallable(tool));
|
|
619
|
-
if (isActionTool(name)) {
|
|
620
|
-
rejectedSeq += 1;
|
|
621
|
-
recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, name, 'not_applied', authority.message);
|
|
622
|
-
}
|
|
623
|
-
return failed(authority.message);
|
|
624
|
-
}
|
|
625
|
-
const prepared = {
|
|
626
|
-
tool,
|
|
627
|
-
params: authority.params,
|
|
628
|
-
originalParams: normalized,
|
|
629
|
-
authorityRoot,
|
|
630
|
-
authorityMeaning: fingerprint(authority),
|
|
631
|
-
parallelSafe: await isParallelSafe(tool, normalized, context),
|
|
632
|
-
started,
|
|
633
|
-
};
|
|
634
|
-
return prepared;
|
|
635
|
-
},
|
|
636
|
-
// Mirrors the run loop: only a definition that declares itself
|
|
637
|
-
// parallel-safe may overlap another call, because tools such as
|
|
638
|
-
// enter_worktree mutate shared execution context.
|
|
639
|
-
lane: (prepared) => (prepared.parallelSafe ? 'default' : 'serial'),
|
|
640
|
-
invoke: async (prepared, callContext) => {
|
|
641
|
-
const decision = await approvalRegistry.evaluate({
|
|
642
|
-
toolName: prepared.tool.name,
|
|
643
|
-
args: prepared.params,
|
|
644
|
-
context,
|
|
645
|
-
});
|
|
646
|
-
if (decision.kind !== 'auto_approve') {
|
|
647
|
-
if (decision.kind === 'prompt' && nestedApprovalOwner) {
|
|
648
|
-
const nestedCallId = bridgeRunId + ':' + callContext.callId;
|
|
649
|
-
const nestedContext = withAbortSignal(context, mergeAbortSignals(callerSignal, callContext.signal), {
|
|
650
|
-
scripted: true,
|
|
651
|
-
});
|
|
652
|
-
tools.onWaiting?.(callContext);
|
|
653
|
-
try {
|
|
654
|
-
const resolution = await nestedApprovalOwner.request({
|
|
655
|
-
requestId: nestedCallId,
|
|
656
|
-
sessionId: sessionId ?? 'unknown',
|
|
657
|
-
graphIdentity: boundRegistry ?? registry,
|
|
658
|
-
outerRunId: bridgeRunId,
|
|
659
|
-
nestedCallId,
|
|
660
|
-
toolName: prepared.tool.name,
|
|
661
|
-
preparedArguments: prepared.params,
|
|
662
|
-
authorityContext: context,
|
|
663
|
-
approval: {
|
|
664
|
-
agentName: 'Nested run_code',
|
|
665
|
-
toolName: prepared.tool.name,
|
|
666
|
-
argumentsText: JSON.stringify(prepared.params),
|
|
667
|
-
rawInterruption: null,
|
|
668
|
-
callId: nestedCallId,
|
|
669
|
-
outsideWorkspaceEdit: resolveOutsideWorkspaceEdit(prepared.tool.name, prepared.params, prepared.authorityRoot),
|
|
670
|
-
},
|
|
671
|
-
signal: nestedContext.signal,
|
|
672
|
-
revalidateAuthority: async () => {
|
|
673
|
-
const currentRoot = getCwd();
|
|
674
|
-
const authority = await bindPreparedAuthority(prepared.tool.name, prepared.originalParams, currentRoot, options.executionContext);
|
|
675
|
-
return (authority.kind === 'bound' &&
|
|
676
|
-
currentRoot === prepared.authorityRoot &&
|
|
677
|
-
fingerprint(authority) === prepared.authorityMeaning);
|
|
678
|
-
},
|
|
679
|
-
revalidate: async () => {
|
|
680
|
-
const latest = await approvalRegistry.evaluate({
|
|
681
|
-
toolName: prepared.tool.name,
|
|
682
|
-
args: prepared.params,
|
|
683
|
-
context,
|
|
684
|
-
});
|
|
685
|
-
return latest.kind;
|
|
686
|
-
},
|
|
687
|
-
grant: (nestedDecision) => {
|
|
688
|
-
if (callContext.signal.aborted)
|
|
689
|
-
throw new Error('Tool execution was not approved.');
|
|
690
|
-
const applied = applyApprovalGrant({
|
|
691
|
-
sessionId: sessionId ?? 'unknown',
|
|
692
|
-
sessionAccess: options.sessionAccess,
|
|
693
|
-
nestedCompatibility: options.nestedCompatibility,
|
|
694
|
-
logger: loggingService,
|
|
695
|
-
}, {
|
|
696
|
-
answer: nestedDecision.answer,
|
|
697
|
-
toolName: prepared.tool.name,
|
|
698
|
-
rawArguments: prepared.params,
|
|
699
|
-
callId: nestedCallId,
|
|
700
|
-
});
|
|
701
|
-
if (!applied.isApproved)
|
|
702
|
-
throw new Error('Tool execution was not approved.');
|
|
703
|
-
},
|
|
704
|
-
dispatch: async () => prepared.tool.execute(prepared.params, nestedContext, { toolCall: { callId: nestedCallId } }),
|
|
705
|
-
});
|
|
706
|
-
if (resolution.kind === 'approved') {
|
|
707
|
-
record(prepared.tool.name, 'ok', prepared.started);
|
|
708
|
-
if (isActionTool(prepared.tool.name)) {
|
|
709
|
-
const semantic = ACTION_SEMANTICS[prepared.tool.name](resolution.result);
|
|
710
|
-
recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, semantic.outcome, semantic.reason);
|
|
711
|
-
}
|
|
712
|
-
const serialized = await serializeResult(mediaReferences.capture(resolution.result), RUN_CODE_LIMITS.maxResultChars, prepared.tool.name, calls.filter((c) => c.outcome !== 'describe').length);
|
|
713
|
-
return {
|
|
714
|
-
kind: 'result',
|
|
715
|
-
result: serialized,
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
if (resolution.kind === 'failed') {
|
|
719
|
-
record(prepared.tool.name, 'error', prepared.started);
|
|
720
|
-
const message = resolution.error instanceof Error ? resolution.error.message : String(resolution.error);
|
|
721
|
-
if (isActionTool(prepared.tool.name)) {
|
|
722
|
-
recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, 'failed', message);
|
|
723
|
-
}
|
|
724
|
-
return failed(message);
|
|
725
|
-
}
|
|
726
|
-
record(prepared.tool.name, 'approval_required', prepared.started, isDirectlyCallable(prepared.tool));
|
|
727
|
-
if (isActionTool(prepared.tool.name)) {
|
|
728
|
-
recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, 'not_applied', resolution.message);
|
|
729
|
-
}
|
|
730
|
-
return failed(resolution.message);
|
|
731
|
-
}
|
|
732
|
-
finally {
|
|
733
|
-
tools.onResumed?.(callContext);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
const outcome = decision.kind === 'unknown'
|
|
737
|
-
? 'unknown_policy'
|
|
738
|
-
: decision.kind === 'error'
|
|
739
|
-
? 'policy_error'
|
|
740
|
-
: decision.kind === 'interceptor_denied'
|
|
741
|
-
? 'interceptor_denied'
|
|
742
|
-
: 'approval_required';
|
|
743
|
-
const directlyCallable = isDirectlyCallable(prepared.tool);
|
|
744
|
-
record(prepared.tool.name, outcome, prepared.started, directlyCallable);
|
|
745
|
-
if (isActionTool(prepared.tool.name)) {
|
|
746
|
-
const denialReason = decision.kind === 'unknown'
|
|
747
|
-
? 'no registered approval policy'
|
|
748
|
-
: decision.kind === 'interceptor_denied'
|
|
749
|
-
? 'refused by an approval interceptor'
|
|
750
|
-
: decision.kind === 'error'
|
|
751
|
-
? 'approval policy failed'
|
|
752
|
-
: 'requires approval and is unavailable from inside a script';
|
|
753
|
-
recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, 'not_applied', denialReason);
|
|
754
|
-
}
|
|
755
|
-
return failed(decision.kind === 'unknown'
|
|
756
|
-
? `"${prepared.tool.name}" has no registered approval policy and is unavailable from inside a script.`
|
|
757
|
-
: decision.kind === 'interceptor_denied'
|
|
758
|
-
? `"${prepared.tool.name}" was refused by an approval interceptor and is unavailable from inside a script.`
|
|
759
|
-
: decision.kind === 'error'
|
|
760
|
-
? `"${prepared.tool.name}" approval policy failed and is unavailable from inside a script.`
|
|
761
|
-
: `"${prepared.tool.name}" requires approval and is unavailable from inside a script.`);
|
|
762
|
-
}
|
|
763
|
-
const started = Date.now();
|
|
764
|
-
const callId = `${bridgeRunId}:${callContext.callId}`;
|
|
765
|
-
try {
|
|
766
|
-
// Marks the call as originating inside a script: the result goes to the
|
|
767
|
-
// script, not into model context, so context-protection caps do not apply.
|
|
768
|
-
const nestedContext = withAbortSignal(context, mergeAbortSignals(callerSignal, callContext.signal), {
|
|
769
|
-
scripted: true,
|
|
770
|
-
});
|
|
771
|
-
const result = await prepared.tool.execute(prepared.params, nestedContext, { toolCall: { callId } });
|
|
772
|
-
record(prepared.tool.name, 'ok', started);
|
|
773
|
-
if (isActionTool(prepared.tool.name)) {
|
|
774
|
-
const semantic = ACTION_SEMANTICS[prepared.tool.name](result);
|
|
775
|
-
recordReceipt(callId, prepared.tool.name, semantic.outcome, semantic.reason);
|
|
776
|
-
}
|
|
777
|
-
const serialized = await serializeResult(mediaReferences.capture(result), RUN_CODE_LIMITS.maxResultChars, prepared.tool.name, calls.filter((c) => c.outcome !== 'describe').length);
|
|
778
|
-
return {
|
|
779
|
-
kind: 'result',
|
|
780
|
-
result: serialized,
|
|
781
|
-
};
|
|
782
|
-
}
|
|
783
|
-
catch (error) {
|
|
784
|
-
record(prepared.tool.name, 'error', started);
|
|
785
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
786
|
-
if (isActionTool(prepared.tool.name)) {
|
|
787
|
-
recordReceipt(callId, prepared.tool.name, 'failed', message);
|
|
788
|
-
}
|
|
789
|
-
return failed(message);
|
|
790
|
-
}
|
|
791
|
-
},
|
|
792
|
-
};
|
|
793
|
-
loggingService.debug('run_code execution started', {
|
|
794
|
-
cwd: getCwd(),
|
|
283
|
+
// The runtime is the single owner of the nested-call lifecycle. The
|
|
284
|
+
// definition remains responsible for model parameters and presentation;
|
|
285
|
+
// in particular, it must not expose a partially wrapped registry.
|
|
286
|
+
const runtime = createRuntime(registry);
|
|
287
|
+
const runtimeResult = await runtime.execute({
|
|
288
|
+
code,
|
|
289
|
+
inputs,
|
|
795
290
|
timeout,
|
|
796
|
-
exposedTools: registry.length,
|
|
797
291
|
description,
|
|
798
|
-
|
|
799
|
-
const result = await new SandboxedCodeHostImpl().run({
|
|
800
|
-
code,
|
|
801
|
-
capabilities: { tools },
|
|
802
|
-
limits: {
|
|
803
|
-
timeoutMs: timeout,
|
|
804
|
-
maxCodeBytes: RUN_CODE_LIMITS.maxCodeBytes,
|
|
805
|
-
maxOutputBytes: RUN_CODE_LIMITS.maxOutputBytes,
|
|
806
|
-
maxConsoleBytes: RUN_CODE_LIMITS.maxConsoleBytes,
|
|
807
|
-
},
|
|
808
|
-
subject: 'Script',
|
|
809
|
-
allowVoidOutput: true,
|
|
292
|
+
context,
|
|
810
293
|
signal: callerSignal,
|
|
811
|
-
onConsole: (values) => output.push(renderConsoleValues(values)),
|
|
812
|
-
});
|
|
813
|
-
const describeCalls = calls.filter((call) => call.outcome === 'describe');
|
|
814
|
-
const executionCalls = calls.filter((call) => call.outcome !== 'describe');
|
|
815
|
-
loggingService.debug('run_code execution finished', {
|
|
816
|
-
ok: result.ok,
|
|
817
|
-
toolCalls: executionCalls.length,
|
|
818
|
-
schemaLookups: describeCalls.length,
|
|
819
294
|
});
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
for (const [callId, index] of pendingReceiptByCallId) {
|
|
824
|
-
receipts[index] = {
|
|
825
|
-
...receipts[index],
|
|
826
|
-
outcome: 'unknown',
|
|
827
|
-
reason: 'did not settle before the script run ended',
|
|
828
|
-
};
|
|
829
|
-
pendingReceiptByCallId.delete(callId);
|
|
830
|
-
}
|
|
831
|
-
// Emitted before rendering: a script whose result cannot be rendered has
|
|
832
|
-
// still produced an outcome worth counting.
|
|
833
|
-
emitRunCodeCompletionTelemetry(loggingService, {
|
|
834
|
-
code,
|
|
835
|
-
result,
|
|
836
|
-
durationMs: Date.now() - startedAt,
|
|
837
|
-
timeoutMs: timeout,
|
|
838
|
-
sessionId,
|
|
839
|
-
runId: bridgeRunId,
|
|
840
|
-
calls,
|
|
841
|
-
receipts,
|
|
842
|
-
});
|
|
843
|
-
const resolvedResult = result.ok && !result.voidOutput
|
|
844
|
-
? { ...result, output: mediaReferences.resolve(result.output) }
|
|
845
|
-
: result;
|
|
846
|
-
return renderResult(resolvedResult, output, calls, receipts, include_console);
|
|
295
|
+
const runtimeRendered = await renderResult(runtimeResult.execution, runtimeResult.output, include_console);
|
|
296
|
+
const runtimeTransportCall = details && typeof details === 'object' && 'toolCall' in details && typeof details.toolCall === 'object';
|
|
297
|
+
return runtimeTransportCall ? attachRunCodeExecution(runtimeRendered, runtimeResult.execution) : runtimeRendered;
|
|
847
298
|
},
|
|
848
299
|
formatCommandMessage: formatRunCodeCommandMessage,
|
|
849
300
|
};
|
|
@@ -858,125 +309,6 @@ export function createRunCodeToolDefinition(options) {
|
|
|
858
309
|
};
|
|
859
310
|
return definition;
|
|
860
311
|
}
|
|
861
|
-
const PATH_TOOLS = new Set([
|
|
862
|
-
'read_file',
|
|
863
|
-
'create_file',
|
|
864
|
-
'search_replace',
|
|
865
|
-
'apply_patch',
|
|
866
|
-
'grep',
|
|
867
|
-
'glob',
|
|
868
|
-
'read_code_outline',
|
|
869
|
-
'code_context_search',
|
|
870
|
-
]);
|
|
871
|
-
async function bindPreparedAuthority(toolName, params, cwd, executionContext) {
|
|
872
|
-
const isRemote = executionContext?.isRemote() ?? false;
|
|
873
|
-
if (isRemote && PATH_TOOLS.has(toolName)) {
|
|
874
|
-
return { kind: 'denied', message: 'Cannot establish remote physical path authority for a nested tool call.' };
|
|
875
|
-
}
|
|
876
|
-
try {
|
|
877
|
-
const physicalRoot = isRemote ? cwd : await requirePhysicalPath(cwd, cwd);
|
|
878
|
-
return { kind: 'bound', physicalRoot, params: await bindPreparedArguments(toolName, params, cwd) };
|
|
879
|
-
}
|
|
880
|
-
catch (error) {
|
|
881
|
-
return {
|
|
882
|
-
kind: 'denied',
|
|
883
|
-
message: `Cannot establish physical path authority: ${error instanceof Error ? error.message : String(error)}`,
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
async function requirePhysicalPath(value, cwd, semantics = 'referent') {
|
|
888
|
-
const physicalPath = await resolveWorkspacePathPhysically(value, cwd);
|
|
889
|
-
if (physicalPath === undefined)
|
|
890
|
-
throw new Error(`Unresolved path: ${value}`);
|
|
891
|
-
if (semantics === 'unlink-source') {
|
|
892
|
-
// Move sources are both read and unlinked. Following a leaf symlink would
|
|
893
|
-
// preserve the read but delete its referent; reject rather than change meaning.
|
|
894
|
-
const lexicalPath = resolveWorkspacePath(value, cwd, { allowOutsideWorkspace: true });
|
|
895
|
-
const stats = await lstat(lexicalPath);
|
|
896
|
-
if (stats.isSymbolicLink())
|
|
897
|
-
throw new Error(`Symlink unlink source is unsupported: ${value}`);
|
|
898
|
-
}
|
|
899
|
-
return physicalPath;
|
|
900
|
-
}
|
|
901
|
-
async function bindPreparedArguments(toolName, params, cwd) {
|
|
902
|
-
if (!params || typeof params !== 'object' || Array.isArray(params) || !PATH_TOOLS.has(toolName))
|
|
903
|
-
return params;
|
|
904
|
-
const record = params;
|
|
905
|
-
const bindPath = async (value, semantics = 'referent') => typeof value === 'string' ? requirePhysicalPath(value, cwd, semantics) : value;
|
|
906
|
-
if (toolName === 'apply_patch' && typeof record.patch === 'string') {
|
|
907
|
-
return { ...record, patch: await bindPatchPaths(record.patch, bindPath) };
|
|
908
|
-
}
|
|
909
|
-
return 'path' in record ? { ...record, path: await bindPath(record.path) } : params;
|
|
910
|
-
}
|
|
911
|
-
async function bindPatchPaths(patch, bindPath) {
|
|
912
|
-
let parsed;
|
|
913
|
-
try {
|
|
914
|
-
parsed = parseUpstreamApplyPatch(patch);
|
|
915
|
-
}
|
|
916
|
-
catch {
|
|
917
|
-
return patch;
|
|
918
|
-
}
|
|
919
|
-
const targets = parsed.operations.flatMap((operation) => {
|
|
920
|
-
const moveTo = 'moveTo' in operation ? operation.moveTo : undefined;
|
|
921
|
-
const semantics = operation.type === 'delete_file' || moveTo ? 'unlink-source' : 'referent';
|
|
922
|
-
return [{ path: operation.path, semantics }, ...(moveTo ? [{ path: moveTo, semantics: 'referent' }] : [])];
|
|
923
|
-
});
|
|
924
|
-
let targetIndex = 0;
|
|
925
|
-
const lines = patch.replace(/\r\n?/g, '\n').split('\n');
|
|
926
|
-
const prefixes = ['*** Add File: ', '*** Update File: ', '*** Delete File: ', '*** Move to: '];
|
|
927
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
928
|
-
const prefix = prefixes.find((candidate) => lines[index].startsWith(candidate));
|
|
929
|
-
if (!prefix)
|
|
930
|
-
continue;
|
|
931
|
-
const target = targets[targetIndex++];
|
|
932
|
-
const bound = await bindPath(target.path, target.semantics);
|
|
933
|
-
lines[index] = prefix + String(bound);
|
|
934
|
-
}
|
|
935
|
-
return lines.join('\n');
|
|
936
|
-
}
|
|
937
|
-
function fingerprint(value) {
|
|
938
|
-
try {
|
|
939
|
-
return JSON.stringify(value) ?? String(value);
|
|
940
|
-
}
|
|
941
|
-
catch {
|
|
942
|
-
return String(value);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
function withAbortSignal(context, signal, extra = {}) {
|
|
946
|
-
return context && typeof context === 'object'
|
|
947
|
-
? { ...context, signal, ...extra }
|
|
948
|
-
: { signal, ...extra };
|
|
949
|
-
}
|
|
950
|
-
function mergeAbortSignals(callerSignal, hostSignal) {
|
|
951
|
-
if (!callerSignal || callerSignal === hostSignal)
|
|
952
|
-
return callerSignal ?? hostSignal;
|
|
953
|
-
const controller = new AbortController();
|
|
954
|
-
const abort = () => {
|
|
955
|
-
callerSignal.removeEventListener('abort', abort);
|
|
956
|
-
hostSignal.removeEventListener('abort', abort);
|
|
957
|
-
controller.abort();
|
|
958
|
-
};
|
|
959
|
-
if (callerSignal.aborted || hostSignal.aborted) {
|
|
960
|
-
controller.abort();
|
|
961
|
-
return controller.signal;
|
|
962
|
-
}
|
|
963
|
-
callerSignal.addEventListener('abort', abort, { once: true });
|
|
964
|
-
hostSignal.addEventListener('abort', abort, { once: true });
|
|
965
|
-
return controller.signal;
|
|
966
|
-
}
|
|
967
|
-
async function isParallelSafe(tool, params, context) {
|
|
968
|
-
const declared = tool.parallelSafe;
|
|
969
|
-
if (declared === undefined || declared === false)
|
|
970
|
-
return false;
|
|
971
|
-
if (declared === true)
|
|
972
|
-
return true;
|
|
973
|
-
try {
|
|
974
|
-
return (await declared(params, context)) === true;
|
|
975
|
-
}
|
|
976
|
-
catch {
|
|
977
|
-
return false;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
312
|
const formatActionOutcome = (outcome) => outcome === 'not_applied' ? 'not applied' : outcome;
|
|
981
313
|
/**
|
|
982
314
|
* Host-rendered action section. Present only when at least one covered action
|
|
@@ -1007,28 +339,32 @@ const renderActionReceipts = (receipts, includeDetails = true) => {
|
|
|
1007
339
|
'they describe tool behavior, not user-request or task outcomes.',
|
|
1008
340
|
].join('\n');
|
|
1009
341
|
};
|
|
1010
|
-
function renderResult(
|
|
342
|
+
function renderResult(execution, output, includeConsole) {
|
|
1011
343
|
const sections = [];
|
|
1012
|
-
const media =
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
344
|
+
const media = execution.attachments;
|
|
345
|
+
const calls = execution.calls;
|
|
346
|
+
const receipts = execution.actions;
|
|
347
|
+
if (execution.script.status === 'failed') {
|
|
348
|
+
const { code, message } = execution.script.diagnostic;
|
|
349
|
+
sections.push(code === 'timeout'
|
|
350
|
+
? `Script timed out. ${message}`
|
|
351
|
+
: code === 'deadline'
|
|
352
|
+
? `Script exceeded its deadline. ${message}`
|
|
353
|
+
: code === 'cancellation'
|
|
354
|
+
? `Script was cancelled. ${message}`
|
|
355
|
+
: `Script failed: ${message}`);
|
|
356
|
+
}
|
|
357
|
+
else if (execution.script.voidOutput) {
|
|
1023
358
|
sections.push('Script returned no result. Return a value from the script to send it to the model.');
|
|
1024
359
|
}
|
|
1025
360
|
else {
|
|
1026
|
-
const
|
|
361
|
+
const value = execution.script.value;
|
|
362
|
+
const stripped = containsMediaContent(value) ? stripMediaContent(value, media) : value;
|
|
1027
363
|
// A top-level content-part array already has a useful text projection;
|
|
1028
364
|
// wrappers (Promise.all, object fields, etc.) retain their shape in JSON,
|
|
1029
365
|
// with media replaced by markers so base64 never leaks into text.
|
|
1030
|
-
const rendered = media.length > 0 && isContentPartArray(
|
|
1031
|
-
?
|
|
366
|
+
const rendered = media.length > 0 && isContentPartArray(value)
|
|
367
|
+
? value
|
|
1032
368
|
.filter((part) => part.type === 'text' && typeof part.text === 'string')
|
|
1033
369
|
.map((part) => part.text)
|
|
1034
370
|
.join('\n')
|
|
@@ -1038,7 +374,7 @@ function renderResult(result, output, calls, receipts, includeConsole) {
|
|
|
1038
374
|
sections.push(`Result:\n${rendered}`);
|
|
1039
375
|
}
|
|
1040
376
|
const printed = output.join('\n').trim();
|
|
1041
|
-
if (printed && (
|
|
377
|
+
if (printed && (execution.script.status === 'failed' || includeConsole))
|
|
1042
378
|
sections.push(`Console trace (debug):\n${printed}`);
|
|
1043
379
|
const refused = calls.filter((call) => call.outcome === 'approval_required');
|
|
1044
380
|
const directlyRefused = refused.filter((call) => call.directlyCallable === true);
|