@oh-my-pi/pi-coding-agent 17.2.3 → 17.2.5
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 +92 -0
- package/dist/{CHANGELOG-c5hpqt9r.md → CHANGELOG-q2w43aw3.md} +92 -0
- package/dist/cli.js +3979 -3548
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/advisor/advise-tool.d.ts +6 -0
- package/dist/types/advisor/runtime.d.ts +4 -4
- package/dist/types/capability/mcp.d.ts +9 -0
- package/dist/types/cli/args.d.ts +4 -1
- package/dist/types/cli/browser-relay-cli.d.ts +15 -0
- package/dist/types/cli/command-help.d.ts +99 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- package/dist/types/cli/models-cli.d.ts +1 -1
- package/dist/types/cli/thinking-levels.d.ts +5 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/commands/browser-relay.d.ts +38 -0
- package/dist/types/commands/commit.d.ts +3 -0
- package/dist/types/commands/complete.d.ts +1 -1
- package/dist/types/commands/completions.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +3 -0
- package/dist/types/commands/join.d.ts +4 -0
- package/dist/types/commands/launch-help.d.ts +171 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/models.d.ts +3 -0
- package/dist/types/commands/say.d.ts +10 -0
- package/dist/types/commands/worktree.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-discovery.d.ts +2 -2
- package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/models-config.d.ts +1 -0
- package/dist/types/config/service-tier.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +70 -22
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/discovery/helpers.d.ts +6 -0
- package/dist/types/discovery/omp-extension-roots.d.ts +21 -2
- package/dist/types/edit/index.d.ts +3 -3
- package/dist/types/edit/modes/replace.d.ts +22 -15
- package/dist/types/edit/renderer.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/spawn-options.d.ts +12 -16
- package/dist/types/extensibility/extensions/loader.d.ts +6 -2
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +2 -2
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +6 -3
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +3 -2
- package/dist/types/launch/protocol.d.ts +2 -2
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/lsp/mux/daemon.d.ts +15 -0
- package/dist/types/lsp/mux/protocol.d.ts +57 -0
- package/dist/types/lsp/mux/server.d.ts +18 -0
- package/dist/types/lsp/types.d.ts +22 -2
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mcp/request-id.d.ts +19 -0
- package/dist/types/mcp/types.d.ts +14 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/messages.d.ts +15 -0
- package/dist/types/mnemopi/embed-client.d.ts +1 -1
- package/dist/types/mnemopi/state.d.ts +0 -23
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/model-browser.d.ts +7 -5
- package/dist/types/modes/components/model-picker.d.ts +9 -3
- package/dist/types/modes/components/read-tool-group.d.ts +11 -0
- package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/registry/agent-lifecycle.d.ts +14 -5
- package/dist/types/registry/agent-registry.d.ts +4 -3
- package/dist/types/sdk.d.ts +4 -2
- package/dist/types/secrets/index.d.ts +7 -9
- package/dist/types/session/agent-session-types.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +6 -1
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/model-controls.d.ts +0 -1
- package/dist/types/session/session-advisors.d.ts +8 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-maintenance.d.ts +2 -0
- package/dist/types/session/session-manager.d.ts +16 -5
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/system-prompt.d.ts +6 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/spawn-policy.d.ts +5 -0
- package/dist/types/thinking.d.ts +1 -7
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/browser/registry.d.ts +2 -1
- package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
- package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
- package/dist/types/tools/browser/relay/kind.d.ts +19 -0
- package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
- package/dist/types/tools/browser/relay/server.d.ts +35 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -0
- package/dist/types/tools/computer/exposure.d.ts +9 -7
- package/dist/types/tools/computer/protocol.d.ts +70 -17
- package/dist/types/tools/computer/supervisor.d.ts +23 -10
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +42 -7
- package/dist/types/tools/computer-renderer.d.ts +7 -5
- package/dist/types/tools/computer.d.ts +25 -44
- package/dist/types/tools/context.d.ts +3 -0
- package/dist/types/tools/default-renderer.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/render-utils.d.ts +2 -0
- package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/tools/xdev.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +2 -2
- package/dist/types/web/kagi.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +1 -0
- package/dist/types/web/search/providers/base.d.ts +2 -0
- package/dist/types/web/search/providers/brave.d.ts +1 -0
- package/dist/types/web/search/providers/browser-page.d.ts +1 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -0
- package/dist/types/web/search/providers/exa.d.ts +1 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/dist/types/web/search/providers/jina.d.ts +1 -0
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -0
- package/dist/types/web/search/providers/parallel.d.ts +1 -0
- package/dist/types/web/search/providers/perplexity.d.ts +1 -0
- package/dist/types/web/search/providers/searxng.d.ts +1 -0
- package/dist/types/web/search/providers/tavily.d.ts +1 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
- package/dist/types/web/search/providers/utils.d.ts +6 -9
- package/dist/types/web/search/providers/zai.d.ts +1 -0
- package/dist/types/web/search/types.d.ts +4 -0
- package/package.json +12 -12
- package/scripts/legacy-pi-virtual-module.ts +12 -2
- package/src/advisor/advise-tool.ts +18 -0
- package/src/advisor/runtime.ts +6 -6
- package/src/capability/mcp.ts +7 -0
- package/src/cli/args.ts +7 -87
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/command-help.ts +103 -0
- package/src/cli/completion-gen.ts +5 -5
- package/src/cli/flag-tables.ts +9 -0
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/models-cli.ts +13 -16
- package/src/cli/setup-cli.ts +13 -21
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/update-cli.ts +26 -7
- package/src/cli-commands.ts +170 -33
- package/src/cli.ts +17 -5
- package/src/collab/host.ts +1 -1
- package/src/commands/acp.ts +3 -1
- package/src/commands/agents.ts +3 -2
- package/src/commands/auth-broker.ts +3 -2
- package/src/commands/auth-gateway.ts +3 -2
- package/src/commands/bench.ts +2 -3
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +2 -2
- package/src/commands/commit.ts +3 -2
- package/src/commands/complete.ts +2 -1
- package/src/commands/completions.ts +3 -2
- package/src/commands/config.ts +3 -2
- package/src/commands/dry-balance.ts +2 -2
- package/src/commands/gallery.ts +3 -2
- package/src/commands/gc.ts +3 -2
- package/src/commands/grep.ts +3 -2
- package/src/commands/grievances.ts +3 -2
- package/src/commands/install.ts +2 -2
- package/src/commands/join.ts +3 -2
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +7 -191
- package/src/commands/models.ts +3 -2
- package/src/commands/plugin.ts +3 -2
- package/src/commands/read.ts +3 -2
- package/src/commands/say.ts +3 -2
- package/src/commands/setup.ts +3 -2
- package/src/commands/shell.ts +3 -2
- package/src/commands/ssh.ts +3 -2
- package/src/commands/stats.ts +3 -2
- package/src/commands/tiny-models.ts +2 -2
- package/src/commands/token.ts +2 -2
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/update.ts +3 -2
- package/src/commands/usage.ts +3 -2
- package/src/commands/web-search.ts +3 -2
- package/src/commands/worktree.ts +3 -2
- package/src/config/keybindings.ts +19 -9
- package/src/config/mcp-schema.json +5 -0
- package/src/config/model-discovery.ts +30 -13
- package/src/config/model-registry.ts +16 -6
- package/src/config/models-config-schema-bundle.ts +9 -0
- package/src/config/resolve-config-value.ts +2 -1
- package/src/config/service-tier.ts +5 -0
- package/src/config/settings-schema.ts +73 -21
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/discovery/builtin.ts +10 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/mcp-json.ts +11 -1
- package/src/discovery/omp-extension-roots.ts +79 -20
- package/src/discovery/omp-plugins.ts +10 -1
- package/src/edit/diff.ts +17 -8
- package/src/edit/index.ts +20 -7
- package/src/edit/modes/replace.ts +93 -40
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +14 -17
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/spawn-options.ts +24 -29
- package/src/export/html/template.js +8 -26
- package/src/extensibility/extensions/loader.ts +66 -28
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
- package/src/extensibility/plugins/marketplace/registry.ts +4 -8
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +1 -1
- package/src/launch/client.ts +32 -13
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +3 -6
- package/src/launch/protocol.ts +2 -2
- package/src/lsp/client.ts +23 -2
- package/src/lsp/index.ts +8 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/types.ts +28 -2
- package/src/main.ts +31 -24
- package/src/mcp/config.ts +1 -0
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mcp/request-id.ts +24 -0
- package/src/mcp/transports/http.ts +4 -2
- package/src/mcp/transports/sse.ts +4 -2
- package/src/mcp/transports/stdio.ts +4 -2
- package/src/mcp/types.ts +15 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/messages.ts +19 -0
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/agent-hub.ts +1 -1
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +10 -1
- package/src/modes/components/model-browser.ts +25 -17
- package/src/modes/components/model-picker.ts +10 -6
- package/src/modes/components/read-tool-group.ts +36 -0
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/tool-execution.ts +85 -20
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/command-controller.ts +2 -2
- package/src/modes/controllers/event-controller.ts +199 -10
- package/src/modes/controllers/input-controller.ts +39 -1
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +47 -6
- package/src/modes/interactive-mode.ts +2 -0
- package/src/modes/types.ts +6 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -10
- package/src/modes/workflow.ts +8 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +26 -52
- package/src/prompts/system/workflow-notice.md +3 -3
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/computer.md +21 -21
- package/src/prompts/tools/glob.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/replace.md +5 -4
- package/src/prompts/tools/task.md +4 -4
- package/src/registry/agent-lifecycle.ts +36 -11
- package/src/registry/agent-registry.ts +12 -5
- package/src/sdk.ts +102 -35
- package/src/secrets/index.ts +16 -18
- package/src/session/agent-session-types.ts +3 -1
- package/src/session/agent-session.ts +23 -2
- package/src/session/agent-storage.ts +6 -4
- package/src/session/history-storage.ts +4 -2
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/messages.ts +31 -7
- package/src/session/model-controls.ts +0 -1
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +21 -3
- package/src/session/session-context.ts +16 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-maintenance.ts +41 -4
- package/src/session/session-manager.ts +181 -94
- package/src/session/session-paths.ts +118 -55
- package/src/session/session-stats.ts +48 -3
- package/src/session/session-storage.ts +30 -22
- package/src/session/session-tools.ts +25 -23
- package/src/session/stream-guards.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +29 -26
- package/src/system-prompt.ts +14 -4
- package/src/task/executor.ts +8 -1
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tiny/text.ts +12 -0
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +5 -10
- package/src/tools/browser/cmux/rpc.ts +2 -8
- package/src/tools/browser/registry.ts +53 -2
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +4 -1
- package/src/tools/browser/shared-daemon.ts +7 -58
- package/src/tools/browser/tab-supervisor.ts +5 -4
- package/src/tools/browser/tab-worker.ts +33 -12
- package/src/tools/browser.ts +26 -1
- package/src/tools/computer/exposure.ts +11 -35
- package/src/tools/computer/protocol.ts +51 -10
- package/src/tools/computer/supervisor.ts +227 -124
- package/src/tools/computer/worker-entry.ts +11 -6
- package/src/tools/computer/worker.ts +695 -81
- package/src/tools/computer-renderer.ts +104 -65
- package/src/tools/computer.ts +134 -428
- package/src/tools/context.ts +3 -0
- package/src/tools/default-renderer.ts +19 -4
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/index.ts +10 -6
- package/src/tools/inspect-image.ts +32 -6
- package/src/tools/render-utils.ts +2 -0
- package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/xdev.ts +29 -2
- package/src/utils/clipboard.ts +40 -14
- package/src/utils/command-args.ts +26 -28
- package/src/utils/tool-choice.ts +0 -13
- package/src/web/kagi.ts +2 -1
- package/src/web/search/index.ts +18 -2
- package/src/web/search/providers/anthropic.ts +7 -2
- package/src/web/search/providers/base.ts +2 -0
- package/src/web/search/providers/brave.ts +3 -1
- package/src/web/search/providers/browser-page.ts +6 -4
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/duckduckgo.ts +2 -1
- package/src/web/search/providers/ecosia.ts +2 -1
- package/src/web/search/providers/exa.ts +4 -2
- package/src/web/search/providers/firecrawl.ts +3 -1
- package/src/web/search/providers/gemini.ts +8 -2
- package/src/web/search/providers/google.ts +2 -1
- package/src/web/search/providers/jina.ts +12 -2
- package/src/web/search/providers/kagi.ts +3 -0
- package/src/web/search/providers/kimi.ts +5 -1
- package/src/web/search/providers/mojeek.ts +2 -1
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +6 -3
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/searxng.ts +11 -5
- package/src/web/search/providers/startpage.ts +10 -4
- package/src/web/search/providers/synthetic.ts +11 -5
- package/src/web/search/providers/tavily.ts +3 -1
- package/src/web/search/providers/tinyfish.ts +3 -1
- package/src/web/search/providers/utils.ts +12 -10
- package/src/web/search/providers/xai.ts +2 -2
- package/src/web/search/providers/zai.ts +18 -3
- package/src/web/search/types.ts +6 -0
|
@@ -14,13 +14,25 @@ export interface SessionStorageStat {
|
|
|
14
14
|
|
|
15
15
|
export interface SessionStorageWriter {
|
|
16
16
|
/**
|
|
17
|
-
* Append one newline-terminated line.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Append one newline-terminated line.
|
|
18
|
+
*
|
|
19
|
+
* File and memory storage apply the line synchronously before the returned
|
|
20
|
+
* promise settles, so a software crash after `append` returns (or after a
|
|
21
|
+
* fire-and-forget call begins) still sees the entry on disk / in body. No
|
|
22
|
+
* `fsync` — power loss may still drop the last page. Indexed backends update
|
|
23
|
+
* the local index immediately and queue the remote publish in call order.
|
|
20
24
|
*
|
|
21
25
|
* `line` MUST include the trailing newline.
|
|
22
26
|
*/
|
|
23
27
|
append(line: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Synchronous append when the backend can apply the line before return.
|
|
30
|
+
* File and memory implement this so {@link SessionManager} can latch the
|
|
31
|
+
* first write failure before the appending call returns (surfaced by a later
|
|
32
|
+
* flushSync/close/next append — the turn loop does not throw from append).
|
|
33
|
+
* Indexed backends update the local index immediately and queue remote I/O.
|
|
34
|
+
*/
|
|
35
|
+
appendSync?(line: string): void;
|
|
24
36
|
/** Resolve once all queued appends complete. No fsync. */
|
|
25
37
|
flush(): Promise<void>;
|
|
26
38
|
/** Drain synchronously flushable queued work when the backend supports it. No fsync. */
|
|
@@ -93,8 +105,6 @@ class FileSessionStorageWriter implements SessionStorageWriter {
|
|
|
93
105
|
#closed = false;
|
|
94
106
|
#error: Error | undefined;
|
|
95
107
|
#onError: ((err: Error) => void) | undefined;
|
|
96
|
-
#pending = "";
|
|
97
|
-
#flushScheduled = false;
|
|
98
108
|
|
|
99
109
|
constructor(fpath: string, options?: { flags?: "a" | "w"; onError?: (err: Error) => void }) {
|
|
100
110
|
this.#onError = options?.onError;
|
|
@@ -129,34 +139,29 @@ class FileSessionStorageWriter implements SessionStorageWriter {
|
|
|
129
139
|
}
|
|
130
140
|
}
|
|
131
141
|
|
|
132
|
-
|
|
133
|
-
this.#
|
|
134
|
-
if (this.#
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
appendSync(line: string): void {
|
|
143
|
+
if (this.#closed) throw new Error("Writer closed");
|
|
144
|
+
if (this.#error) throw this.#error;
|
|
145
|
+
// Write in-body so software crash after the call still sees the entry.
|
|
146
|
+
// Microtask batching used to leave completed transcript lines only in
|
|
147
|
+
// memory until the next event-loop turn; process crash then lost every
|
|
148
|
+
// post-checkpoint event. flush/flushSync remain no-op drains (no fsync).
|
|
137
149
|
try {
|
|
138
|
-
this.#writeNow(
|
|
150
|
+
this.#writeNow(line);
|
|
139
151
|
} catch (err) {
|
|
140
|
-
this.#recordError(err);
|
|
152
|
+
throw this.#recordError(err);
|
|
141
153
|
}
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
async append(line: string): Promise<void> {
|
|
145
|
-
|
|
146
|
-
if (this.#error) throw this.#error;
|
|
147
|
-
this.#pending += line;
|
|
148
|
-
if (this.#flushScheduled) return;
|
|
149
|
-
this.#flushScheduled = true;
|
|
150
|
-
queueMicrotask(() => this.#flushPendingNow());
|
|
157
|
+
this.appendSync(line);
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
async flush(): Promise<void> {
|
|
154
|
-
this.#flushPendingNow();
|
|
155
161
|
if (this.#error) throw this.#error;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
flushSync(): void {
|
|
159
|
-
this.#flushPendingNow();
|
|
160
165
|
if (this.#error) throw this.#error;
|
|
161
166
|
}
|
|
162
167
|
|
|
@@ -166,7 +171,6 @@ class FileSessionStorageWriter implements SessionStorageWriter {
|
|
|
166
171
|
|
|
167
172
|
async close(): Promise<void> {
|
|
168
173
|
if (this.#closed) return;
|
|
169
|
-
this.#flushPendingNow();
|
|
170
174
|
this.#closed = true;
|
|
171
175
|
// Unregister from finalization - we're closing properly
|
|
172
176
|
writerRegistry.unregister(this);
|
|
@@ -487,7 +491,7 @@ class MemorySessionStorageWriter implements SessionStorageWriter {
|
|
|
487
491
|
return error;
|
|
488
492
|
}
|
|
489
493
|
|
|
490
|
-
|
|
494
|
+
appendSync(line: string): void {
|
|
491
495
|
if (this.#closed) throw new Error("Writer closed");
|
|
492
496
|
if (this.#error) throw this.#error;
|
|
493
497
|
try {
|
|
@@ -498,6 +502,10 @@ class MemorySessionStorageWriter implements SessionStorageWriter {
|
|
|
498
502
|
}
|
|
499
503
|
}
|
|
500
504
|
|
|
505
|
+
async append(line: string): Promise<void> {
|
|
506
|
+
this.appendSync(line);
|
|
507
|
+
}
|
|
508
|
+
|
|
501
509
|
async flush(): Promise<void> {
|
|
502
510
|
if (this.#error) throw this.#error;
|
|
503
511
|
}
|
|
@@ -574,24 +574,28 @@ export class SessionTools {
|
|
|
574
574
|
/** Applies an enabled tool set and reconciles its `xd://` partition. */
|
|
575
575
|
async applyActiveToolsByName(toolNames: string[]): Promise<void> {
|
|
576
576
|
toolNames = normalizeToolNames(toolNames);
|
|
577
|
+
let builtInWriteAvailable = this.#builtInToolNames.has("write");
|
|
578
|
+
if (toolNames.includes("write") && !builtInWriteAvailable) {
|
|
579
|
+
builtInWriteAvailable = (await this.#ensureWriteRegistered?.()) === true;
|
|
580
|
+
if (builtInWriteAvailable) this.#builtInToolNames.add("write");
|
|
581
|
+
}
|
|
577
582
|
const selectedTools = toolNames.flatMap(name => {
|
|
578
583
|
const tool = this.#toolRegistry.get(name);
|
|
579
584
|
return tool ? [{ name, tool }] : [];
|
|
580
585
|
});
|
|
581
586
|
const xdevReadAvailable = this.#builtInToolNames.has("read") && selectedTools.some(({ name }) => name === "read");
|
|
587
|
+
const xdevWriteAvailable = builtInWriteAvailable && selectedTools.some(({ name }) => name === "write");
|
|
582
588
|
const isPresentationPinned = (name: string): boolean =>
|
|
583
589
|
this.#presentationPinnedToolNames?.has(name) === true || this.#runtimeSelectedToolNames?.has(name) === true;
|
|
584
590
|
const mountCandidates = selectedTools.filter(
|
|
585
591
|
({ name, tool }) =>
|
|
586
|
-
this.#xdev !== undefined &&
|
|
592
|
+
this.#xdev !== undefined &&
|
|
593
|
+
xdevReadAvailable &&
|
|
594
|
+
xdevWriteAvailable &&
|
|
595
|
+
!isPresentationPinned(name) &&
|
|
596
|
+
isMountableUnderXdev(tool),
|
|
587
597
|
);
|
|
588
|
-
|
|
589
|
-
let builtInWriteAvailable = this.#builtInToolNames.has("write");
|
|
590
|
-
if (mountCandidates.length > 0 && !builtInWriteAvailable) {
|
|
591
|
-
builtInWriteAvailable = (await this.#ensureWriteRegistered?.()) === true;
|
|
592
|
-
if (builtInWriteAvailable) this.#builtInToolNames.add("write");
|
|
593
|
-
}
|
|
594
|
-
const mountNames = builtInWriteAvailable ? new Set(mountCandidates.map(({ name }) => name)) : new Set<string>();
|
|
598
|
+
const mountNames = new Set(mountCandidates.map(({ name }) => name));
|
|
595
599
|
const tools: AgentTool[] = [];
|
|
596
600
|
const validToolNames: string[] = [];
|
|
597
601
|
for (const { name, tool } of selectedTools) {
|
|
@@ -831,23 +835,21 @@ export class SessionTools {
|
|
|
831
835
|
|
|
832
836
|
/** Rediscovers reloadable skills and refreshes prompt metadata. */
|
|
833
837
|
async refreshSkills(): Promise<void> {
|
|
834
|
-
if (!this.#skillsReloadable) {
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
838
|
resetCapabilities();
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
839
|
+
if (this.#skillsReloadable) {
|
|
840
|
+
const skillsSettings = this.#host.settings.getGroup("skills");
|
|
841
|
+
const discovered = await loadSkills({
|
|
842
|
+
...skillsSettings,
|
|
843
|
+
cwd: this.#host.sessionManager.getCwd(),
|
|
844
|
+
disabledExtensions: this.#host.settings.get("disabledExtensions") ?? [],
|
|
845
|
+
});
|
|
846
|
+
this.#skills = discovered.skills;
|
|
847
|
+
this.#skillWarnings = discovered.warnings;
|
|
848
|
+
this.#skillsSettings = skillsSettings;
|
|
848
849
|
|
|
849
|
-
|
|
850
|
-
|
|
850
|
+
if (this.#host.agentKind() === "main") {
|
|
851
|
+
setActiveSkills(this.#skills);
|
|
852
|
+
}
|
|
851
853
|
}
|
|
852
854
|
await this.refreshBaseSystemPrompt();
|
|
853
855
|
this.#host.notifyCommandMetadataChanged();
|
|
@@ -164,7 +164,7 @@ export class StreamingEditGuard {
|
|
|
164
164
|
const toolCall = messageContent[contentIndex] as ToolCall;
|
|
165
165
|
if (toolCall.name !== "edit") return undefined;
|
|
166
166
|
const args = toolCall.arguments;
|
|
167
|
-
if (!args || typeof args !== "object" || Array.isArray(args) || "
|
|
167
|
+
if (!args || typeof args !== "object" || Array.isArray(args) || "old_string" in args || "new_string" in args) {
|
|
168
168
|
return undefined;
|
|
169
169
|
}
|
|
170
170
|
const filePath = typeof args.path === "string" ? args.path : undefined;
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
MarketplaceManager,
|
|
33
33
|
} from "../extensibility/plugins/marketplace";
|
|
34
34
|
import { readMCPConfigFile } from "../mcp/config-writer";
|
|
35
|
-
import { resolveMemoryBackend } from "../memory-backend";
|
|
35
|
+
import { memoryStatsUnavailableMessage, resolveMemoryBackend } from "../memory-backend";
|
|
36
36
|
import { runPauseScreen } from "../modes/components/pause-screen";
|
|
37
37
|
import { collectMcpServerNames, MCPCommandController } from "../modes/controllers/mcp-command-controller";
|
|
38
38
|
import { describeLoopLimitRuntime } from "../modes/loop-limit";
|
|
@@ -102,39 +102,42 @@ function formatFastModeStatus(session: AgentSession): string {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/** Detailed, session-effective `/computer status` diagnostics. */
|
|
105
|
-
function formatComputerUseStatus(session: AgentSession): string {
|
|
105
|
+
async function formatComputerUseStatus(session: AgentSession): Promise<string> {
|
|
106
106
|
const enabled = session.settings.get("computer.enabled");
|
|
107
107
|
const active = session.getEnabledToolNames().includes("computer");
|
|
108
108
|
const model = session.model;
|
|
109
109
|
const modelName = model ? formatModelString(model) : "none";
|
|
110
|
-
const exposure = !enabled
|
|
111
|
-
|
|
110
|
+
const exposure = !enabled
|
|
111
|
+
? "not exposed (disabled)"
|
|
112
|
+
: !active
|
|
113
|
+
? "not exposed (tool inactive)"
|
|
114
|
+
: computerExposureMode(model);
|
|
112
115
|
const configured = {
|
|
113
|
-
backend: session.settings.get("computer.backend"),
|
|
114
116
|
display: session.settings.get("computer.display"),
|
|
115
117
|
maxWidth: session.settings.get("computer.maxWidth"),
|
|
116
118
|
maxHeight: session.settings.get("computer.maxHeight"),
|
|
117
119
|
};
|
|
118
|
-
const computerTool =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
120
|
+
const computerTool = active
|
|
121
|
+
? (session.getToolByName("computer") as Pick<ComputerTool, "capabilities"> | undefined)
|
|
122
|
+
: undefined;
|
|
123
|
+
const capabilities = await computerTool?.capabilities();
|
|
124
|
+
const capabilityStatus = capabilities
|
|
125
|
+
? [
|
|
126
|
+
`backend=${capabilities.backend}${capabilities.displayServer ? `/${capabilities.displayServer}` : ""}`,
|
|
127
|
+
`capture=${capabilities.capture} (${capabilities.capturePermission})`,
|
|
128
|
+
`input=${capabilities.input} (${capabilities.inputPermission})`,
|
|
129
|
+
`ax=${capabilities.ax} (${capabilities.axPermission})`,
|
|
130
|
+
`backgroundWindowInput=${capabilities.backgroundWindowInput}`,
|
|
131
|
+
`deliveryModes=${capabilities.deliveryModes.join(",") || "none"}`,
|
|
132
|
+
].join(", ")
|
|
133
|
+
: "session not started";
|
|
125
134
|
return [
|
|
126
135
|
`Computer use: ${enabled ? "enabled" : "disabled"}`,
|
|
127
|
-
`tool: ${
|
|
128
|
-
`backend: ${effective.backend}`,
|
|
129
|
-
`display: ${effective.display}`,
|
|
130
|
-
`capture: ${effective.maxWidth}×${effective.maxHeight}`,
|
|
131
|
-
...(configurationChanged
|
|
132
|
-
? [
|
|
133
|
-
`next-session settings: backend=${configured.backend}, display=${configured.display}, capture=${configured.maxWidth}×${configured.maxHeight}`,
|
|
134
|
-
]
|
|
135
|
-
: []),
|
|
136
|
-
`model: ${modelName}`,
|
|
136
|
+
`tool: ${active ? "active" : "inactive"}`,
|
|
137
137
|
`exposure: ${exposure}`,
|
|
138
|
+
`model: ${modelName}`,
|
|
139
|
+
`configured: display=${configured.display}, maxWidth=${configured.maxWidth}, maxHeight=${configured.maxHeight}`,
|
|
140
|
+
`capabilities: ${capabilityStatus}`,
|
|
138
141
|
].join(" · ");
|
|
139
142
|
}
|
|
140
143
|
|
|
@@ -151,7 +154,7 @@ async function applyComputerUseToggle(session: AgentSession, enable: boolean): P
|
|
|
151
154
|
}
|
|
152
155
|
session.settings.override("computer.enabled", enable);
|
|
153
156
|
return enable
|
|
154
|
-
? `Computer use enabled for this session. ${formatComputerUseStatus(session)}`
|
|
157
|
+
? `Computer use enabled for this session. ${await formatComputerUseStatus(session)}`
|
|
155
158
|
: "Computer use disabled for this session.";
|
|
156
159
|
}
|
|
157
160
|
|
|
@@ -673,7 +676,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
673
676
|
handle: async (command, runtime) => {
|
|
674
677
|
const arg = command.args.trim().toLowerCase();
|
|
675
678
|
if (arg === "status") {
|
|
676
|
-
await runtime.output(formatComputerUseStatus(runtime.session));
|
|
679
|
+
await runtime.output(await formatComputerUseStatus(runtime.session));
|
|
677
680
|
return commandConsumed();
|
|
678
681
|
}
|
|
679
682
|
if (!arg || arg === "toggle" || arg === "on" || arg === "off") {
|
|
@@ -686,7 +689,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
686
689
|
handleTui: async (command, runtime) => {
|
|
687
690
|
const arg = command.args.trim().toLowerCase();
|
|
688
691
|
if (arg === "status") {
|
|
689
|
-
runtime.ctx.showStatus(formatComputerUseStatus(runtime.ctx.session));
|
|
692
|
+
runtime.ctx.showStatus(await formatComputerUseStatus(runtime.ctx.session));
|
|
690
693
|
runtime.ctx.editor.setText("");
|
|
691
694
|
return;
|
|
692
695
|
}
|
|
@@ -1947,7 +1950,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
1947
1950
|
case "diagnose": {
|
|
1948
1951
|
const hook = verb === "stats" ? backend.stats : backend.diagnose;
|
|
1949
1952
|
const payload = await hook?.(runtime.settings.getAgentDir(), runtime.cwd, runtime.session);
|
|
1950
|
-
await runtime.output(payload ??
|
|
1953
|
+
await runtime.output(payload ?? memoryStatsUnavailableMessage(backend.id, verb));
|
|
1951
1954
|
return commandConsumed();
|
|
1952
1955
|
}
|
|
1953
1956
|
case "mm":
|
package/src/system-prompt.ts
CHANGED
|
@@ -332,6 +332,8 @@ export async function resolvePromptInput(input: string | undefined, description:
|
|
|
332
332
|
export interface LoadContextFilesOptions {
|
|
333
333
|
/** Working directory to start walking up from. Default: getProjectDir() */
|
|
334
334
|
cwd?: string;
|
|
335
|
+
/** Disabled extension IDs to honor instead of the process-global settings. */
|
|
336
|
+
disabledExtensions?: string[];
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
function dedupeExactContextFiles(
|
|
@@ -356,7 +358,10 @@ export async function loadProjectContextFiles(
|
|
|
356
358
|
): Promise<Array<{ path: string; content: string; depth?: number }>> {
|
|
357
359
|
const resolvedCwd = options.cwd ?? getProjectDir();
|
|
358
360
|
|
|
359
|
-
const result = await loadCapability(contextFileCapability.id, {
|
|
361
|
+
const result = await loadCapability(contextFileCapability.id, {
|
|
362
|
+
cwd: resolvedCwd,
|
|
363
|
+
disabledExtensions: options.disabledExtensions,
|
|
364
|
+
});
|
|
360
365
|
|
|
361
366
|
// Materialize ContextFile items, expanding any `@path/to/file` includes
|
|
362
367
|
// in their content. The expansion uses the file's own directory as the
|
|
@@ -493,7 +498,8 @@ export interface BuildSystemPromptOptions {
|
|
|
493
498
|
/**
|
|
494
499
|
* Whether provider-native tool calling is active (no owned/in-band syntax).
|
|
495
500
|
* When true and `inlineToolDescriptors` is false, the inventory renders as a
|
|
496
|
-
* compact tool-name list; otherwise it renders full
|
|
501
|
+
* compact tool-name list; otherwise it renders the full Harmony-style
|
|
502
|
+
* `namespace functions { … }` catalog. Default: true
|
|
497
503
|
*/
|
|
498
504
|
nativeTools?: boolean;
|
|
499
505
|
/** Skills settings for discovery. */
|
|
@@ -520,6 +526,9 @@ export interface BuildSystemPromptOptions {
|
|
|
520
526
|
taskMaxConcurrency?: number;
|
|
521
527
|
/** Whether IRC-backed parallel coordination can be included in delegation policy. */
|
|
522
528
|
taskIrcEnabled?: boolean;
|
|
529
|
+
/** Whether the read-only `scout` subagent is spawnable (not disabled, allowed by spawn policy). Defaults to true. */
|
|
530
|
+
scoutAvailable?: boolean;
|
|
531
|
+
|
|
523
532
|
/** Rules with alwaysApply=true — their full content is injected into the prompt. */
|
|
524
533
|
alwaysApplyRules?: AlwaysApplyRule[];
|
|
525
534
|
/** Whether secret obfuscation is active. When true, explains the redaction format in the prompt. */
|
|
@@ -594,6 +603,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
594
603
|
taskIrcEnabled = false,
|
|
595
604
|
secretsEnabled = false,
|
|
596
605
|
workspaceTree: providedWorkspaceTree,
|
|
606
|
+
scoutAvailable = true,
|
|
597
607
|
memoryRootEnabled = false,
|
|
598
608
|
securityEnabled = false,
|
|
599
609
|
model,
|
|
@@ -788,7 +798,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
788
798
|
|
|
789
799
|
// List mode shows a compact tool-name list; it only applies when descriptors
|
|
790
800
|
// stay in provider-native tool schemas AND native tool calling is active.
|
|
791
|
-
// Otherwise render full
|
|
801
|
+
// Otherwise render the full functions-namespace catalog in the system prompt.
|
|
792
802
|
const toolListMode = !inlineToolDescriptors && nativeTools;
|
|
793
803
|
// Build tool descriptions for system prompt rendering.
|
|
794
804
|
const toolPromptNames = new Map<string, string>(toolNames.map(name => [name, tools?.get(name)?.wireName ?? name]));
|
|
@@ -821,7 +831,6 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
821
831
|
examples: meta?.examples,
|
|
822
832
|
};
|
|
823
833
|
}),
|
|
824
|
-
model ?? "",
|
|
825
834
|
);
|
|
826
835
|
|
|
827
836
|
// Filter skills for the rendered system prompt:
|
|
@@ -874,6 +883,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
874
883
|
eagerTasksAlways,
|
|
875
884
|
taskBatch,
|
|
876
885
|
MAX_CONCURRENCY: normalizeConcurrencyLimit(taskMaxConcurrency),
|
|
886
|
+
scoutAvailable,
|
|
877
887
|
taskIrcEnabled,
|
|
878
888
|
secretsEnabled,
|
|
879
889
|
hasMemoryRoot: memoryRootEnabled,
|
package/src/task/executor.ts
CHANGED
|
@@ -2364,7 +2364,14 @@ export async function finalizeSubagentLifecycle(args: {
|
|
|
2364
2364
|
const resumableAbort =
|
|
2365
2365
|
args.abortKind === "budget" && args.keepAlive && !args.isolated && args.reviveSession !== null;
|
|
2366
2366
|
if (args.aborted && !resumableAbort) {
|
|
2367
|
-
if (ref && ownsRef)
|
|
2367
|
+
if (ref && ownsRef) {
|
|
2368
|
+
// Terminal hard kill: mark `aborted` and detach the session before
|
|
2369
|
+
// disposing so the ref satisfies the AgentRef invariant (session null
|
|
2370
|
+
// when aborted) — ensureLive/hub focus must treat it as terminal, never
|
|
2371
|
+
// route into the disposed session.
|
|
2372
|
+
registry.setStatus(args.id, "aborted", ref);
|
|
2373
|
+
registry.detachSession(args.id, ref);
|
|
2374
|
+
}
|
|
2368
2375
|
await disposeSession();
|
|
2369
2376
|
return;
|
|
2370
2377
|
}
|
package/src/task/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ import { TASK_EFFORTS, type TaskEffort } from "../thinking";
|
|
|
27
27
|
import { truncateForPrompt } from "../tools/approval";
|
|
28
28
|
import { isIrcEnabled } from "../tools/hub";
|
|
29
29
|
import { formatBytes, formatDuration } from "../tools/render-utils";
|
|
30
|
-
import { resolveSpawnPolicy } from "./spawn-policy";
|
|
30
|
+
import { isScoutSpawnable, resolveSpawnPolicy } from "./spawn-policy";
|
|
31
31
|
import {
|
|
32
32
|
type AgentDefinition,
|
|
33
33
|
type AgentProgress,
|
|
@@ -188,8 +188,10 @@ function renderDescription(options: TaskDescriptionOptions): string {
|
|
|
188
188
|
readOnly: isReadOnlyAgent(agent),
|
|
189
189
|
blocking: agent.blocking === true,
|
|
190
190
|
}));
|
|
191
|
+
const scoutAvailable = isScoutSpawnable(options.disabledAgents, options.parentSpawns);
|
|
191
192
|
return prompt.render(taskDescriptionTemplate, {
|
|
192
193
|
agents: renderedAgents,
|
|
194
|
+
scoutAvailable,
|
|
193
195
|
spawningDisabled,
|
|
194
196
|
defaultAgent: spawnPolicy.defaultAgent,
|
|
195
197
|
isolationEnabled: options.isolationEnabled,
|
|
@@ -398,15 +400,19 @@ const GENERIC_SPAWN_AGENTS: ReadonlySet<string> = new Set(["task", "sonic"]);
|
|
|
398
400
|
* (DepthCapacity: it currently has the `task` tool). `agentNames` are the
|
|
399
401
|
* per-item resolved agent types. Returns undefined when no nudge applies.
|
|
400
402
|
*/
|
|
401
|
-
export function buildSpecializationAdvisory(
|
|
403
|
+
export function buildSpecializationAdvisory(
|
|
404
|
+
agentNames: string[],
|
|
405
|
+
depthCapacity: boolean,
|
|
406
|
+
scoutAvailable = true,
|
|
407
|
+
): string | undefined {
|
|
402
408
|
if (!depthCapacity) return undefined;
|
|
403
409
|
const generics = agentNames.filter(name => GENERIC_SPAWN_AGENTS.has(name));
|
|
404
410
|
if (generics.length < 2) return undefined;
|
|
405
|
-
|
|
406
|
-
`
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
411
|
+
const specialist = scoutAvailable
|
|
412
|
+
? `Check the agent list for a closer specialist type — e.g. read-only research belongs on ` +
|
|
413
|
+
`\`agent: "scout"\`, which runs on a faster model.`
|
|
414
|
+
: `Check the agent list for a closer specialist type.`;
|
|
415
|
+
return `Tip: this call spawned ${generics.length} generic \`${generics[0]}\` workers. ${specialist}`;
|
|
410
416
|
}
|
|
411
417
|
|
|
412
418
|
/**
|
|
@@ -443,10 +449,11 @@ export function composeSpawnAdvisory(args: {
|
|
|
443
449
|
depthCapacity: boolean;
|
|
444
450
|
ircEnabled: boolean;
|
|
445
451
|
willRunAsync: boolean;
|
|
452
|
+
scoutAvailable?: boolean;
|
|
446
453
|
}): string | undefined {
|
|
447
454
|
return (
|
|
448
455
|
[
|
|
449
|
-
buildSpecializationAdvisory(args.agents, args.depthCapacity),
|
|
456
|
+
buildSpecializationAdvisory(args.agents, args.depthCapacity, args.scoutAvailable),
|
|
450
457
|
args.willRunAsync ? buildCoordinationAdvisory(args.items, args.depthCapacity, args.ircEnabled) : undefined,
|
|
451
458
|
]
|
|
452
459
|
.filter(Boolean)
|
|
@@ -751,6 +758,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
751
758
|
depthCapacity,
|
|
752
759
|
ircEnabled,
|
|
753
760
|
willRunAsync: false,
|
|
761
|
+
scoutAvailable: isScoutSpawnable(
|
|
762
|
+
this.session.settings.get("task.disabledAgents") as string[] | undefined,
|
|
763
|
+
this.session.getSessionSpawns?.() ?? "*",
|
|
764
|
+
),
|
|
754
765
|
});
|
|
755
766
|
const result = await this.#executeSyncFanout(
|
|
756
767
|
toolCallId,
|
|
@@ -784,6 +795,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
784
795
|
depthCapacity,
|
|
785
796
|
ircEnabled,
|
|
786
797
|
willRunAsync: asyncItems.length > 0,
|
|
798
|
+
scoutAvailable: isScoutSpawnable(
|
|
799
|
+
this.session.settings.get("task.disabledAgents") as string[] | undefined,
|
|
800
|
+
this.session.getSessionSpawns?.() ?? "*",
|
|
801
|
+
),
|
|
787
802
|
});
|
|
788
803
|
// Returns a fresh result (copied content array, copied text part) rather
|
|
789
804
|
// than mutating the caller's — task results are short-lived here, but an
|
package/src/task/spawn-policy.ts
CHANGED
|
@@ -56,3 +56,17 @@ export function resolveSpawnPolicy(parentSpawns: string | boolean | null | undef
|
|
|
56
56
|
allowedPromptText: allowedAgents.map(agent => `\`${agent}\``).join(", "),
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether the `scout` agent is spawnable in a session: not disabled via
|
|
62
|
+
* `task.disabledAgents`, and permitted by the session spawn policy.
|
|
63
|
+
*/
|
|
64
|
+
export function isScoutSpawnable(
|
|
65
|
+
disabledAgents: readonly string[] | undefined,
|
|
66
|
+
spawns: string | boolean | null | undefined,
|
|
67
|
+
): boolean {
|
|
68
|
+
if (disabledAgents?.includes("scout")) return false;
|
|
69
|
+
const policy = resolveSpawnPolicy(spawns);
|
|
70
|
+
if (!policy.enabled) return false;
|
|
71
|
+
return policy.allowedAgents === null || policy.allowedAgents.includes("scout");
|
|
72
|
+
}
|
package/src/thinking.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { Effort, type Model, THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
|
3
3
|
import { clampThinkingLevelForModel, getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
4
4
|
import { modelsAreEqual } from "@oh-my-pi/pi-catalog/models";
|
|
5
5
|
|
|
6
|
+
export { CLI_THINKING_LEVELS } from "./cli/thinking-levels";
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* Metadata used to render thinking selector values in the coding-agent UI.
|
|
8
10
|
*/
|
|
@@ -209,14 +211,6 @@ export function getConfiguredThinkingLevelMetadata(level: ConfiguredThinkingLeve
|
|
|
209
211
|
return level === AUTO_THINKING ? AUTO_THINKING_METADATA : getThinkingLevelMetadata(level);
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
/**
|
|
213
|
-
* Thinking selectors accepted by the `--thinking` CLI flag, in display order:
|
|
214
|
-
* `off`, every concrete effort (`minimal`..`max`), then `auto`. Single source
|
|
215
|
-
* for the flag's `options` list, shell completions, and the "invalid level"
|
|
216
|
-
* warning so all three stay in sync.
|
|
217
|
-
*/
|
|
218
|
-
export const CLI_THINKING_LEVELS: readonly string[] = [ThinkingLevel.Off, ...THINKING_EFFORTS, AUTO_THINKING];
|
|
219
|
-
|
|
220
214
|
/**
|
|
221
215
|
* Parses a `--thinking` CLI value. Accepts every {@link parseConfiguredThinkingLevel}
|
|
222
216
|
* selector (`off`, `auto`, `minimal`..`max`) but rejects
|
package/src/tiny/text.ts
CHANGED
|
@@ -142,6 +142,17 @@ export function isLowSignalTitleInput(message: string): boolean {
|
|
|
142
142
|
*/
|
|
143
143
|
export const NO_TITLE_SENTINEL = "none";
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Upper bounds on an accepted title. Titling is a 3-7 word task, so any output
|
|
147
|
+
* past these limits is a model that ignored the task and answered the user's
|
|
148
|
+
* message instead — its whole reply must not become the session title (issue
|
|
149
|
+
* #7303). Rejecting (return null) lets the caller defer titling to the next
|
|
150
|
+
* user turn; truncating would keep half an assistant blob, which is still an
|
|
151
|
+
* assistant blob.
|
|
152
|
+
*/
|
|
153
|
+
const MAX_TITLE_CHARS = 80;
|
|
154
|
+
const MAX_TITLE_WORDS = 12;
|
|
155
|
+
|
|
145
156
|
export function normalizeGeneratedTitle(value: string | null | undefined, sourceText?: string): string | null {
|
|
146
157
|
const firstLine = value?.trim().split(/\r?\n/, 1)[0]?.trim();
|
|
147
158
|
if (!firstLine) return null;
|
|
@@ -154,6 +165,7 @@ export function normalizeGeneratedTitle(value: string | null | undefined, source
|
|
|
154
165
|
.replace(/[.!?]$/, "")
|
|
155
166
|
.trim();
|
|
156
167
|
if (!title || title.toLowerCase() === NO_TITLE_SENTINEL) return null;
|
|
168
|
+
if (title.length > MAX_TITLE_CHARS || (title.match(TITLE_WORD)?.length ?? 0) > MAX_TITLE_WORDS) return null;
|
|
157
169
|
return sourceText === undefined ? title : reconcileTitleCasing(title, sourceText);
|
|
158
170
|
}
|
|
159
171
|
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { recordFileSnapshot, recordSeenLinesFromBody } from "../edit/file-snapsh
|
|
|
11
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
12
|
import type { Theme } from "../modes/theme/theme";
|
|
13
13
|
import astGrepDescription from "../prompts/tools/ast-grep.md" with { type: "text" };
|
|
14
|
+
import { isScoutSpawnable } from "../task/spawn-policy";
|
|
14
15
|
import { Ellipsis, fileHyperlink, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
15
16
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
16
17
|
import type { ToolSession } from ".";
|
|
@@ -150,7 +151,14 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
150
151
|
readonly approval = "read" as const;
|
|
151
152
|
readonly label = "AST Grep";
|
|
152
153
|
readonly summary = "Search code with AST patterns (structural grep)";
|
|
153
|
-
|
|
154
|
+
get description(): string {
|
|
155
|
+
return prompt.render(astGrepDescription, {
|
|
156
|
+
scoutAvailable: isScoutSpawnable(
|
|
157
|
+
this.session.settings.get("task.disabledAgents") as string[] | undefined,
|
|
158
|
+
this.session.getSessionSpawns?.() ?? "*",
|
|
159
|
+
),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
154
162
|
readonly parameters = astGrepSchema;
|
|
155
163
|
readonly strict = true;
|
|
156
164
|
|
|
@@ -178,9 +186,7 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
178
186
|
];
|
|
179
187
|
readonly loadMode = "discoverable";
|
|
180
188
|
|
|
181
|
-
constructor(private readonly session: ToolSession) {
|
|
182
|
-
this.description = prompt.render(astGrepDescription);
|
|
183
|
-
}
|
|
189
|
+
constructor(private readonly session: ToolSession) {}
|
|
184
190
|
|
|
185
191
|
async execute(
|
|
186
192
|
_toolCallId: string,
|
|
@@ -8,16 +8,11 @@ import { resizeImage } from "../../../utils/image-resize";
|
|
|
8
8
|
import type { ToolSession } from "../../index";
|
|
9
9
|
import { resolveToCwd } from "../../path-utils";
|
|
10
10
|
import { formatScreenshot } from "../../render-utils";
|
|
11
|
+
import { bindRunFacade, resolvePredicateTimeout, type WaitPredicateOptions, waitForRun } from "../../run-scope";
|
|
11
12
|
import { ToolAbortError, ToolError, throwIfAborted } from "../../tool-errors";
|
|
12
13
|
import { type AriaSnapshotOptions, assertSelectorString, buildAriaSnapshotScript } from "../aria/aria-snapshot";
|
|
13
14
|
import { DEFAULT_VIEWPORT } from "../launch";
|
|
14
15
|
import { extractReadableFromHtml, type ReadableFormat } from "../readable";
|
|
15
|
-
import {
|
|
16
|
-
bindBrowserRunFacade,
|
|
17
|
-
resolvePredicateTimeout,
|
|
18
|
-
type WaitPredicateOptions,
|
|
19
|
-
waitForBrowserRun,
|
|
20
|
-
} from "../run-cancellation";
|
|
21
16
|
import { cloneSafe, RunOutput } from "../run-output";
|
|
22
17
|
import type { Observation, ReadyInfo, RunResultOk, ScreenshotResult, SessionSnapshot } from "../tab-protocol";
|
|
23
18
|
import {
|
|
@@ -1345,16 +1340,16 @@ export async function runCmuxCode(tab: CmuxTab, opts: RunCmuxCodeOptions): Promi
|
|
|
1345
1340
|
// Keep both inside try so a concurrent in-process eval/browser run surfaces as
|
|
1346
1341
|
// a rejected promise the supervisor can report, never an unhandled rejection.
|
|
1347
1342
|
runtime.setCwd(opts.snapshot.cwd);
|
|
1348
|
-
const runTab =
|
|
1343
|
+
const runTab = bindRunFacade(tab, signal);
|
|
1349
1344
|
runtime.setRunScope({
|
|
1350
|
-
page:
|
|
1351
|
-
browser:
|
|
1345
|
+
page: bindRunFacade(tab.page, signal),
|
|
1346
|
+
browser: bindRunFacade(tab.browser, signal),
|
|
1352
1347
|
tab: runTab,
|
|
1353
1348
|
assert: (cond: unknown, text?: string): void => {
|
|
1354
1349
|
if (!cond) throw new ToolError(text ?? "Assertion failed");
|
|
1355
1350
|
},
|
|
1356
1351
|
wait: (msOrPredicate: number | (() => unknown), waitOpts?: WaitPredicateOptions): Promise<unknown> =>
|
|
1357
|
-
|
|
1352
|
+
waitForRun(
|
|
1358
1353
|
msOrPredicate,
|
|
1359
1354
|
signal,
|
|
1360
1355
|
typeof msOrPredicate === "number"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseFlag } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import { ToolError } from "../../tool-errors";
|
|
2
3
|
import type { Observation, ObservationEntry } from "../tab-protocol";
|
|
3
4
|
|
|
@@ -174,13 +175,6 @@ export function mapWaitUntil(waitUntil: string | undefined): "interactive" | "co
|
|
|
174
175
|
return waitUntil === "domcontentloaded" ? "interactive" : "complete";
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
const TRUTHY_ENV_VALUES = new Set(["1", "Y", "y", "TRUE", "true", "YES", "yes", "ON", "on"]);
|
|
178
|
-
|
|
179
|
-
function resolveCmuxEnabled(envValue: string | undefined, settingEnabled: boolean): boolean {
|
|
180
|
-
if (!envValue) return settingEnabled;
|
|
181
|
-
return TRUTHY_ENV_VALUES.has(envValue);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
178
|
export interface ResolveCmuxKindOptions {
|
|
185
179
|
surface?: string;
|
|
186
180
|
settingEnabled?: boolean;
|
|
@@ -190,7 +184,7 @@ export function resolveCmuxKind(
|
|
|
190
184
|
options?: ResolveCmuxKindOptions | null,
|
|
191
185
|
env: Record<string, string | undefined> = process.env,
|
|
192
186
|
): CmuxKind | null {
|
|
193
|
-
if (!
|
|
187
|
+
if (!parseFlag(env.PI_BROWSER_CMUX, options?.settingEnabled ?? true)) {
|
|
194
188
|
return null;
|
|
195
189
|
}
|
|
196
190
|
const socketPath = env.CMUX_SOCKET_PATH;
|