@oh-my-pi/pi-coding-agent 17.0.8 → 17.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -1
- package/README.md +1 -1
- package/dist/cli.js +5495 -5021
- package/dist/types/async/job-manager.d.ts +37 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/bench-cli.d.ts +41 -0
- package/dist/types/commands/bench.d.ts +15 -3
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/__tests__/model-registry.test.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +30 -1
- package/dist/types/config/models-config-schema.d.ts +18 -6
- package/dist/types/config/models-config.d.ts +14 -5
- package/dist/types/config/provider-globals.d.ts +2 -2
- package/dist/types/config/service-tier.d.ts +5 -1
- package/dist/types/config/settings-schema.d.ts +350 -50
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/dap/client.d.ts +20 -0
- package/dist/types/exec/bash-executor.d.ts +38 -0
- package/dist/types/exec/direnv.d.ts +33 -0
- package/dist/types/export/html/args.d.ts +15 -0
- package/dist/types/export/html/index.d.ts +11 -26
- package/dist/types/export/html/web-palette.d.ts +55 -116
- package/dist/types/extensibility/extensions/loader.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -2
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -0
- package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +10 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +14 -1
- package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
- package/dist/types/live/controller.d.ts +40 -0
- package/dist/types/live/protocol.d.ts +85 -0
- package/dist/types/live/protocol.test.d.ts +1 -0
- package/dist/types/live/transport.d.ts +48 -0
- package/dist/types/live/visualizer.d.ts +33 -0
- package/dist/types/lsp/client.d.ts +18 -1
- package/dist/types/mcp/config-writer.test.d.ts +1 -0
- package/dist/types/mcp/manager.d.ts +6 -2
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/render.d.ts +2 -2
- package/dist/types/mcp/smithery-auth.d.ts +1 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
- package/dist/types/mcp/tool-bridge.d.ts +7 -3
- package/dist/types/mcp/types.d.ts +6 -0
- package/dist/types/memory-backend/tool-names.d.ts +2 -0
- package/dist/types/modes/components/login-dialog.d.ts +2 -2
- package/dist/types/modes/components/oauth-selector.d.ts +8 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
- package/dist/types/modes/components/settings-defs.d.ts +8 -1
- package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +6 -1
- package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +10 -1
- package/dist/types/modes/rpc/rpc-frame.d.ts +16 -0
- package/dist/types/modes/rpc/rpc-messages.d.ts +26 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +40 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +9 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +3 -1
- package/dist/types/modes/utils/context-usage.d.ts +12 -2
- package/dist/types/plan-mode/plan-files.d.ts +10 -0
- package/dist/types/registry/agent-lifecycle.d.ts +21 -9
- package/dist/types/registry/agent-registry.d.ts +11 -4
- package/dist/types/sdk.d.ts +15 -1
- package/dist/types/secrets/index.d.ts +15 -2
- package/dist/types/secrets/obfuscator.d.ts +113 -15
- package/dist/types/session/acp-permission-gate.d.ts +19 -0
- package/dist/types/session/agent-session-events.d.ts +84 -0
- package/dist/types/session/agent-session-types.d.ts +314 -0
- package/dist/types/session/agent-session.d.ts +120 -750
- package/dist/types/session/async-job-delivery.d.ts +28 -0
- package/dist/types/session/bash-runner.d.ts +75 -0
- package/dist/types/session/blob-store.d.ts +11 -1
- package/dist/types/session/blob-store.test.d.ts +1 -0
- package/dist/types/session/checkpoint-entries.d.ts +28 -0
- package/dist/types/session/eval-runner.d.ts +49 -0
- package/dist/types/session/irc-bridge.d.ts +46 -0
- package/dist/types/session/messages.d.ts +22 -0
- package/dist/types/session/model-controls.d.ts +180 -0
- package/dist/types/session/prewalk.d.ts +46 -0
- package/dist/types/session/queued-messages.d.ts +22 -0
- package/dist/types/session/redis-session-storage.d.ts +1 -0
- package/dist/types/session/retry-fallback-chains.d.ts +74 -0
- package/dist/types/session/role-models.d.ts +15 -0
- package/dist/types/session/session-advisors.d.ts +228 -0
- package/dist/types/session/session-entries.d.ts +8 -0
- package/dist/types/session/session-handoff.d.ts +70 -0
- package/dist/types/session/session-history-format.d.ts +6 -1
- package/dist/types/session/session-loader.d.ts +6 -4
- package/dist/types/session/session-maintenance.d.ts +246 -0
- package/dist/types/session/session-manager.d.ts +41 -0
- package/dist/types/session/session-memory.d.ts +56 -0
- package/dist/types/session/session-provider-boundary.d.ts +62 -0
- package/dist/types/session/session-stats.d.ts +48 -0
- package/dist/types/session/session-tools.d.ts +143 -0
- package/dist/types/session/session-workspace.d.ts +32 -0
- package/dist/types/session/stream-guards.d.ts +44 -0
- package/dist/types/session/todo-tracker.d.ts +56 -0
- package/dist/types/session/ttsr-coordinator.d.ts +51 -0
- package/dist/types/session/turn-recovery.d.ts +225 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +4 -1
- package/dist/types/task/output-manager.d.ts +3 -1
- package/dist/types/task/types.d.ts +14 -0
- package/dist/types/tools/approval.d.ts +1 -0
- package/dist/types/tools/browser/launch.d.ts +5 -0
- package/dist/types/tools/hub/jobs.d.ts +1 -1
- package/dist/types/tools/image-gen.d.ts +4 -4
- package/dist/types/tools/image-providers.d.ts +38 -0
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/report-tool-issue.d.ts +24 -9
- package/dist/types/tools/todo.d.ts +10 -4
- package/dist/types/tools/xdev.d.ts +5 -1
- package/dist/types/tts/streaming-player.d.ts +14 -0
- package/dist/types/tts/vocalizer.d.ts +5 -0
- package/dist/types/utils/jj.d.ts +29 -0
- package/dist/types/utils/lang-from-path.d.ts +1 -0
- package/dist/types/utils/title-generator.d.ts +30 -0
- package/dist/types/vibe/runtime.d.ts +36 -8
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +15 -5
- package/dist/types/web/search/providers/firecrawl.d.ts +9 -0
- package/dist/types/web/search/types.d.ts +95 -1
- package/package.json +13 -12
- package/scripts/generate-share-viewer.ts +4 -6
- package/scripts/legacy-pi-virtual-module.ts +1 -1
- package/src/advisor/__tests__/advisor.test.ts +643 -0
- package/src/advisor/runtime.ts +144 -43
- package/src/async/job-manager.ts +90 -2
- package/src/cli/args.ts +2 -0
- package/src/cli/auth-gateway-cli.ts +18 -3
- package/src/cli/bench-cli.ts +395 -29
- package/src/cli/flag-tables.ts +3 -0
- package/src/cli/gc-cli.ts +2 -2
- package/src/cli/grievances-cli.ts +2 -2
- package/src/cli/usage-cli.ts +11 -2
- package/src/collab/host.ts +3 -2
- package/src/commands/bench.ts +18 -4
- package/src/commands/launch.ts +4 -0
- package/src/config/__tests__/model-registry.test.ts +147 -0
- package/src/config/model-registry.ts +50 -2
- package/src/config/model-resolver.ts +0 -1
- package/src/config/models-config-schema.ts +15 -4
- package/src/config/provider-globals.ts +9 -9
- package/src/config/service-tier.ts +26 -1
- package/src/config/settings-schema.ts +250 -54
- package/src/config/settings.ts +81 -2
- package/src/dap/client.ts +37 -4
- package/src/edit/index.ts +49 -12
- package/src/eval/py/executor.ts +103 -33
- package/src/exec/bash-executor.ts +89 -6
- package/src/exec/direnv.ts +145 -0
- package/src/export/html/args.ts +20 -0
- package/src/export/html/index.ts +45 -47
- package/src/export/html/template.css +19 -1
- package/src/export/html/template.html +6 -0
- package/src/export/html/template.js +21 -0
- package/src/export/html/tool-views.generated.js +31 -31
- package/src/export/html/web-palette.ts +116 -132
- package/src/export/share.ts +249 -49
- package/src/extensibility/extensions/loader.ts +29 -1
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +33 -2
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +1 -0
- package/src/extensibility/legacy-pi-tui-shim.ts +10 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +870 -311
- package/src/hindsight/state.ts +64 -6
- package/src/internal-urls/local-protocol.ts +2 -1
- package/src/internal-urls/memory-protocol.ts +2 -2
- package/src/internal-urls/registry-helpers.ts +40 -0
- package/src/internal-urls/skill-protocol.ts +2 -2
- package/src/internal-urls/ssh-protocol.ts +2 -1
- package/src/internal-urls/vault-protocol.ts +2 -1
- package/src/live/audio-worklet.txt +59 -0
- package/src/live/browser-runtime.txt +221 -0
- package/src/live/controller.ts +464 -0
- package/src/live/prompts/agent-final-message.md +3 -0
- package/src/live/prompts/live-instructions.md +23 -0
- package/src/live/protocol.test.ts +140 -0
- package/src/live/protocol.ts +233 -0
- package/src/live/transport.ts +490 -0
- package/src/live/visualizer.ts +234 -0
- package/src/lsp/client.ts +52 -9
- package/src/lsp/clients/biome-client.ts +3 -4
- package/src/lsp/index.ts +44 -11
- package/src/main.ts +9 -1
- package/src/mcp/config-writer.test.ts +43 -0
- package/src/mcp/config-writer.ts +109 -82
- package/src/mcp/manager.ts +39 -8
- package/src/mcp/oauth-discovery.ts +10 -2
- package/src/mcp/render.ts +94 -35
- package/src/mcp/smithery-auth.test.ts +29 -0
- package/src/mcp/smithery-auth.ts +3 -2
- package/src/mcp/tool-bridge.ts +107 -11
- package/src/mcp/types.ts +7 -0
- package/src/memories/index.ts +40 -20
- package/src/memory-backend/tool-names.ts +2 -0
- package/src/mnemopi/backend.ts +24 -7
- package/src/modes/acp/acp-agent.ts +56 -10
- package/src/modes/acp/acp-event-mapper.ts +8 -1
- package/src/modes/components/agent-hub.ts +27 -10
- package/src/modes/components/login-dialog.ts +14 -4
- package/src/modes/components/oauth-selector.ts +24 -7
- package/src/modes/components/plan-review-overlay.ts +350 -35
- package/src/modes/components/settings-defs.ts +28 -3
- package/src/modes/components/settings-selector.ts +178 -6
- package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
- package/src/modes/components/status-line/component.ts +123 -2
- package/src/modes/components/tool-execution.test.ts +63 -2
- package/src/modes/components/tool-execution.ts +11 -2
- package/src/modes/controllers/command-controller.ts +70 -22
- package/src/modes/controllers/event-controller.ts +111 -16
- package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +20 -4
- package/src/modes/controllers/live-command-controller.ts +178 -0
- package/src/modes/controllers/mcp-command-controller.ts +80 -41
- package/src/modes/controllers/omfg-controller.ts +44 -40
- package/src/modes/controllers/selector-controller.ts +18 -10
- package/src/modes/controllers/session-focus-controller.ts +6 -1
- package/src/modes/interactive-mode.ts +160 -38
- package/src/modes/rpc/rpc-client.ts +94 -3
- package/src/modes/rpc/rpc-frame.ts +164 -4
- package/src/modes/rpc/rpc-messages.ts +127 -0
- package/src/modes/rpc/rpc-mode.ts +79 -7
- package/src/modes/rpc/rpc-types.ts +34 -2
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/setup-wizard/scenes/model.ts +5 -7
- package/src/modes/setup-wizard/scenes/providers.ts +3 -2
- package/src/modes/setup-wizard/scenes/sign-in.ts +8 -2
- package/src/modes/setup-wizard/scenes/theme.ts +13 -3
- package/src/modes/setup-wizard/scenes/types.ts +9 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +23 -10
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +3 -1
- package/src/modes/utils/context-usage.ts +23 -7
- package/src/modes/utils/ui-helpers.ts +10 -5
- package/src/plan-mode/plan-files.ts +40 -0
- package/src/prompts/bench/cache-prefix-chunk.md +1 -0
- package/src/prompts/bench/cache-prefix.md +3 -0
- package/src/prompts/bench/cache-suffix.md +1 -0
- package/src/prompts/goals/guided-goal-system.md +24 -3
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/project-prompt.md +8 -1
- package/src/prompts/system/subagent-async-pending.md +6 -0
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/workflow-notice.md +48 -40
- package/src/prompts/system/xdev-mount-notice.md +4 -0
- package/src/prompts/tools/task.md +12 -2
- package/src/prompts/tools/todo.md +3 -1
- package/src/registry/agent-lifecycle.ts +116 -46
- package/src/registry/agent-registry.ts +35 -8
- package/src/registry/persisted-agents.ts +26 -2
- package/src/sdk.ts +255 -139
- package/src/secrets/index.ts +127 -4
- package/src/secrets/obfuscator.ts +2328 -105
- package/src/session/acp-permission-gate.ts +165 -0
- package/src/session/agent-session-error-log.test.ts +1 -1
- package/src/session/agent-session-events.ts +66 -0
- package/src/session/agent-session-types.ts +334 -0
- package/src/session/agent-session.ts +1910 -12213
- package/src/session/artifacts.ts +6 -5
- package/src/session/async-job-delivery.ts +74 -0
- package/src/session/bash-runner.ts +326 -0
- package/src/session/blob-store.test.ts +56 -0
- package/src/session/blob-store.ts +18 -2
- package/src/session/checkpoint-entries.ts +81 -0
- package/src/session/eval-runner.ts +212 -0
- package/src/session/indexed-session-storage.ts +9 -2
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/messages.ts +263 -1
- package/src/session/model-controls.ts +714 -0
- package/src/session/prewalk.ts +252 -0
- package/src/session/queued-messages.ts +93 -0
- package/src/session/redis-session-storage.ts +51 -11
- package/src/session/retry-fallback-chains.ts +455 -0
- package/src/session/role-models.ts +85 -0
- package/src/session/session-advisors.ts +1679 -0
- package/src/session/session-context.test.ts +224 -1
- package/src/session/session-context.ts +47 -5
- package/src/session/session-entries.ts +8 -0
- package/src/session/session-handoff.ts +308 -0
- package/src/session/session-history-format.ts +20 -9
- package/src/session/session-loader.ts +10 -51
- package/src/session/session-maintenance.ts +2983 -0
- package/src/session/session-manager.ts +390 -30
- package/src/session/session-memory.ts +222 -0
- package/src/session/session-provider-boundary.ts +307 -0
- package/src/session/session-stats.ts +293 -0
- package/src/session/session-tools.ts +943 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/todo-tracker.ts +380 -0
- package/src/session/ttsr-coordinator.ts +496 -0
- package/src/session/turn-recovery.ts +1629 -0
- package/src/slash-commands/builtin-registry.ts +92 -11
- package/src/slash-commands/helpers/usage-report.ts +25 -4
- package/src/system-prompt.ts +41 -17
- package/src/task/executor.ts +288 -70
- package/src/task/index.ts +148 -111
- package/src/task/output-manager.ts +25 -3
- package/src/task/persisted-revive.ts +4 -3
- package/src/task/structured-subagent.ts +4 -1
- package/src/task/types.ts +16 -0
- package/src/tools/approval.ts +55 -10
- package/src/tools/bash-interactive.ts +26 -0
- package/src/tools/bash-skill-urls.ts +28 -2
- package/src/tools/bash.ts +339 -123
- package/src/tools/browser/launch.ts +9 -1
- package/src/tools/browser/tab-supervisor.ts +8 -5
- package/src/tools/browser.ts +94 -47
- package/src/tools/hub/index.ts +1 -1
- package/src/tools/hub/jobs.ts +67 -8
- package/src/tools/image-gen.ts +20 -28
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +12 -0
- package/src/tools/path-utils.ts +49 -2
- package/src/tools/read.ts +156 -88
- package/src/tools/renderers.ts +7 -1
- package/src/tools/report-tool-issue.ts +79 -28
- package/src/tools/todo.ts +101 -11
- package/src/tools/vibe.ts +1 -2
- package/src/tools/write.ts +51 -1
- package/src/tools/xdev.ts +67 -3
- package/src/tts/streaming-player.ts +62 -4
- package/src/tts/vocalizer.ts +18 -1
- package/src/utils/jj.ts +125 -4
- package/src/utils/lang-from-path.ts +7 -0
- package/src/utils/title-generator.ts +137 -1
- package/src/vibe/runtime.ts +852 -72
- package/src/web/search/index.ts +3 -6
- package/src/web/search/provider.ts +31 -16
- package/src/web/search/providers/firecrawl.ts +46 -13
- package/src/web/search/providers/xai.ts +7 -1
- package/src/web/search/types.ts +8 -1
package/src/tools/browser.ts
CHANGED
|
@@ -7,9 +7,24 @@ import type { ToolSession } from "../sdk";
|
|
|
7
7
|
import { enforceInlineByteCap } from "../session/streaming-output";
|
|
8
8
|
import { truncateForPrompt } from "./approval";
|
|
9
9
|
import { resolveCmuxKind } from "./browser/cmux/rpc";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
acquireBrowser,
|
|
12
|
+
type BrowserHandle,
|
|
13
|
+
type BrowserKind,
|
|
14
|
+
type BrowserKindTag,
|
|
15
|
+
holdBrowser,
|
|
16
|
+
releaseBrowser,
|
|
17
|
+
} from "./browser/registry";
|
|
11
18
|
import type { Observation, ScreenshotResult } from "./browser/tab-protocol";
|
|
12
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
type AcquireTabResult,
|
|
21
|
+
acquireTab,
|
|
22
|
+
dropHeadlessTabs,
|
|
23
|
+
getTab,
|
|
24
|
+
releaseAllTabs,
|
|
25
|
+
releaseTab,
|
|
26
|
+
runInTab,
|
|
27
|
+
} from "./browser/tab-supervisor";
|
|
13
28
|
import type { OutputMeta } from "./output-meta";
|
|
14
29
|
import { resolveToCwd } from "./path-utils";
|
|
15
30
|
import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
|
|
@@ -232,52 +247,84 @@ export class BrowserTool implements AgentTool<typeof browserSchema, BrowserToolD
|
|
|
232
247
|
);
|
|
233
248
|
}
|
|
234
249
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
250
|
+
// The requested timeout must cover the *entire* open — browser
|
|
251
|
+
// acquisition (CDP discovery/connect), queued tab acquisition, worker
|
|
252
|
+
// creation, and navigation — not only `acquireTab`. Compose one deadline
|
|
253
|
+
// from the caller signal and `params.timeout` and thread it through both
|
|
254
|
+
// stages so a stalled acquisition rejects at the requested boundary.
|
|
255
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
256
|
+
const openSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
257
|
+
try {
|
|
258
|
+
const browser = await untilAborted(openSignal, () =>
|
|
259
|
+
acquireBrowser(kind, {
|
|
260
|
+
cwd: this.session.cwd,
|
|
261
|
+
viewport: params.viewport
|
|
262
|
+
? {
|
|
263
|
+
width: params.viewport.width,
|
|
264
|
+
height: params.viewport.height,
|
|
265
|
+
deviceScaleFactor: params.viewport.scale,
|
|
266
|
+
}
|
|
267
|
+
: undefined,
|
|
268
|
+
appArgs: params.app?.args,
|
|
269
|
+
signal: openSignal,
|
|
270
|
+
}),
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// Hold one open-acquisition lease across the whole tab acquisition.
|
|
274
|
+
// A freshly-created browser sits in the registry at refCount 0 until a
|
|
275
|
+
// tab takes a hold; without this lease an abort/timeout mid-acquisition
|
|
276
|
+
// (or a sibling open of a different tab name on the same browser that
|
|
277
|
+
// fails) could dispose it out from under this operation. The lease is
|
|
278
|
+
// released exactly once — the success and failure paths are mutually
|
|
279
|
+
// exclusive — transferring ownership to the published tab on success or
|
|
280
|
+
// rolling the fresh browser back on failure.
|
|
281
|
+
holdBrowser(browser);
|
|
282
|
+
let result: AcquireTabResult;
|
|
283
|
+
try {
|
|
284
|
+
result = await untilAborted(openSignal, () =>
|
|
285
|
+
acquireTab(name, browser, {
|
|
286
|
+
url: params.url,
|
|
287
|
+
waitUntil: params.wait_until,
|
|
288
|
+
viewport: params.viewport
|
|
289
|
+
? {
|
|
290
|
+
width: params.viewport.width,
|
|
291
|
+
height: params.viewport.height,
|
|
292
|
+
deviceScaleFactor: params.viewport.scale,
|
|
293
|
+
}
|
|
294
|
+
: undefined,
|
|
295
|
+
target: params.app?.target,
|
|
296
|
+
timeoutMs,
|
|
297
|
+
dialogs: params.dialogs,
|
|
298
|
+
signal: openSignal,
|
|
299
|
+
ownerSessionId: this.session.getSessionId?.() ?? undefined,
|
|
300
|
+
}),
|
|
301
|
+
);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
await releaseBrowser(browser, { kill: false });
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
await releaseBrowser(browser, { kill: false });
|
|
249
307
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const title = tab.info.title ?? "";
|
|
271
|
-
details.url = url;
|
|
272
|
-
details.viewport = tab.info.viewport;
|
|
273
|
-
const verb = result.created ? "Opened" : "Reused";
|
|
274
|
-
const lines = [
|
|
275
|
-
`${verb} tab ${JSON.stringify(name)} on ${describeBrowser(browser)}`,
|
|
276
|
-
`URL: ${url}`,
|
|
277
|
-
title ? `Title: ${title}` : null,
|
|
278
|
-
].filter((l): l is string => typeof l === "string");
|
|
279
|
-
details.result = lines.join("\n");
|
|
280
|
-
return toolResult(details).text(lines.join("\n")).done();
|
|
308
|
+
const tab = result.tab;
|
|
309
|
+
const url = tab.info.url;
|
|
310
|
+
const title = tab.info.title ?? "";
|
|
311
|
+
details.url = url;
|
|
312
|
+
details.viewport = tab.info.viewport;
|
|
313
|
+
const verb = result.created ? "Opened" : "Reused";
|
|
314
|
+
const lines = [
|
|
315
|
+
`${verb} tab ${JSON.stringify(name)} on ${describeBrowser(browser)}`,
|
|
316
|
+
`URL: ${url}`,
|
|
317
|
+
title ? `Title: ${title}` : null,
|
|
318
|
+
].filter((l): l is string => typeof l === "string");
|
|
319
|
+
details.result = lines.join("\n");
|
|
320
|
+
return toolResult(details).text(lines.join("\n")).done();
|
|
321
|
+
} catch (error) {
|
|
322
|
+
// Caller cancellation stays a ToolAbortError; the requested timeout
|
|
323
|
+
// becomes a timeout ToolError; anything else passes through unchanged.
|
|
324
|
+
if (signal?.aborted) throw error instanceof ToolAbortError ? error : new ToolAbortError();
|
|
325
|
+
if (timeoutSignal.aborted) throw new ToolError(`Browser open timed out after ${timeoutMs}ms`);
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
281
328
|
}
|
|
282
329
|
|
|
283
330
|
async #close(
|
package/src/tools/hub/index.ts
CHANGED
|
@@ -283,7 +283,7 @@ export class HubTool implements AgentTool<typeof hubSchema, HubDetails> {
|
|
|
283
283
|
if (!params.ids?.length) {
|
|
284
284
|
return hubErrorResult('`ids` is required for op="cancel".', { op: "cancel", jobs: [] });
|
|
285
285
|
}
|
|
286
|
-
return executeCancel(this.session, manager, this.#ownerId(), params.ids);
|
|
286
|
+
return await executeCancel(this.session, manager, this.#ownerId(), params.ids);
|
|
287
287
|
}
|
|
288
288
|
case "jobs": {
|
|
289
289
|
const manager = this.session.asyncJobManager;
|
package/src/tools/hub/jobs.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { settings } from "../../config/settings";
|
|
|
12
12
|
import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
|
|
13
13
|
import { shimmerEnabled, shimmerText } from "../../modes/theme/shimmer";
|
|
14
14
|
import type { Theme } from "../../modes/theme/theme";
|
|
15
|
+
import { USER_INTERRUPT_LABEL } from "../../session/messages";
|
|
15
16
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../../tui";
|
|
16
17
|
import type { ToolSession } from "..";
|
|
17
18
|
import {
|
|
@@ -304,26 +305,38 @@ export function nothingToWaitForResult(session: ToolSession): AgentToolResult<Co
|
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
/** `cancel`: kill the named jobs; returns immediately with outcomes + snapshots. */
|
|
307
|
-
export function executeCancel(
|
|
308
|
+
export async function executeCancel(
|
|
308
309
|
session: ToolSession,
|
|
309
310
|
manager: AsyncJobManager,
|
|
310
311
|
ownerId: string | undefined,
|
|
311
312
|
ids: string[],
|
|
312
|
-
): AgentToolResult<CoordinationDetails
|
|
313
|
+
): Promise<AgentToolResult<CoordinationDetails>> {
|
|
313
314
|
const ownerFilter = ownerId ? { ownerId } : undefined;
|
|
314
315
|
const cancelOutcomes: CancelOutcome[] = [];
|
|
315
316
|
for (const id of ids) {
|
|
316
317
|
const existing = manager.getJob(id);
|
|
317
318
|
if (!existing || (ownerId && existing.ownerId !== ownerId)) {
|
|
318
|
-
|
|
319
|
+
// No job by this id (or it belongs to another agent): a budget-aborted
|
|
320
|
+
// keep-alive subagent lives on as a jobless registration long after its
|
|
321
|
+
// job row is reaped, so let cancel reach the agent registration too.
|
|
322
|
+
cancelOutcomes.push(await cancelAgentRegistration(session, ownerId, id));
|
|
319
323
|
continue;
|
|
320
324
|
}
|
|
321
325
|
if (existing.status !== "running") {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
326
|
+
// The job row settled but may still be inside the retention window.
|
|
327
|
+
// The agent registration behind it (job id == agent id for task
|
|
328
|
+
// spawns) can outlive the row as an idle/parked zombie — try the
|
|
329
|
+
// registration kill before reporting the row as already done.
|
|
330
|
+
const regOutcome = await cancelAgentRegistration(session, ownerId, id);
|
|
331
|
+
cancelOutcomes.push(
|
|
332
|
+
regOutcome.status === "cancelled"
|
|
333
|
+
? regOutcome
|
|
334
|
+
: {
|
|
335
|
+
id,
|
|
336
|
+
status: "already_completed",
|
|
337
|
+
message: `Background job ${id} is already ${existing.status}.`,
|
|
338
|
+
},
|
|
339
|
+
);
|
|
327
340
|
continue;
|
|
328
341
|
}
|
|
329
342
|
const cancelled = manager.cancel(id, ownerFilter);
|
|
@@ -336,6 +349,52 @@ export function executeCancel(
|
|
|
336
349
|
return buildJobResult(session, manager, "cancel", visibleJobs(manager, ids, ownerId), cancelOutcomes);
|
|
337
350
|
}
|
|
338
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Kill a non-job-backed agent registration named by `id`: abort any in-flight
|
|
354
|
+
* turn, then release it from the lifecycle (dispose session + unregister). This
|
|
355
|
+
* is the only kill path for a keep-alive subagent that was budget-aborted, went
|
|
356
|
+
* `idle`/`parked`, and outlived its job row — otherwise it is unstoppable short
|
|
357
|
+
* of a broker restart (issue #6315). Scoped to the caller's own descendants so
|
|
358
|
+
* cross-agent kills stay impossible; a bare test/SDK caller (no owner id) may
|
|
359
|
+
* target any sub. Never touches Main, the caller, or advisor transcripts.
|
|
360
|
+
*/
|
|
361
|
+
async function cancelAgentRegistration(
|
|
362
|
+
session: ToolSession,
|
|
363
|
+
ownerId: string | undefined,
|
|
364
|
+
id: string,
|
|
365
|
+
): Promise<CancelOutcome> {
|
|
366
|
+
const registry = session.agentRegistry;
|
|
367
|
+
const ref = registry?.get(id);
|
|
368
|
+
if (ref?.kind !== "sub") {
|
|
369
|
+
return { id, status: "not_found", message: `Background job not found: ${id}` };
|
|
370
|
+
}
|
|
371
|
+
if (id === ownerId) {
|
|
372
|
+
return { id, status: "not_found", message: `Cannot cancel yourself (${id}).` };
|
|
373
|
+
}
|
|
374
|
+
if (ownerId && ref.parentId !== ownerId) {
|
|
375
|
+
return { id, status: "not_found", message: `Agent ${id} was not spawned by you and cannot be cancelled.` };
|
|
376
|
+
}
|
|
377
|
+
const lifecycle = session.agentLifecycle?.();
|
|
378
|
+
try {
|
|
379
|
+
if (ref.status === "running" && ref.session) {
|
|
380
|
+
await ref.session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
381
|
+
}
|
|
382
|
+
if (lifecycle) {
|
|
383
|
+
await lifecycle.release(id);
|
|
384
|
+
} else {
|
|
385
|
+
await ref.session?.dispose();
|
|
386
|
+
registry?.unregister(id);
|
|
387
|
+
}
|
|
388
|
+
} catch (error) {
|
|
389
|
+
return {
|
|
390
|
+
id,
|
|
391
|
+
status: "already_completed",
|
|
392
|
+
message: `Agent ${id} could not be fully cancelled: ${error instanceof Error ? error.message : String(error)}.`,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return { id, status: "cancelled", message: `Cancelled agent ${id} (killed session, dropped registration).` };
|
|
396
|
+
}
|
|
397
|
+
|
|
339
398
|
/** `jobs`: read-only snapshot of every job plus the jobless running-agent roster. */
|
|
340
399
|
export function executeJobsSnapshot(
|
|
341
400
|
session: ToolSession,
|
package/src/tools/image-gen.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { settings } from "../config/settings";
|
|
|
27
27
|
import type { CustomTool } from "../extensibility/custom-tools/types";
|
|
28
28
|
import { ohMyPiXAIUserAgent, resolveXAIHttpCredentials } from "../lib/xai-http";
|
|
29
29
|
import imageGenDescription from "../prompts/tools/image-gen.md" with { type: "text" };
|
|
30
|
+
import { AUTO_IMAGE_PROVIDER_ORDER, type ImageProvider, isImageProviderId } from "./image-providers";
|
|
30
31
|
import { resolveReadPath } from "./path-utils";
|
|
31
32
|
|
|
32
33
|
const DEFAULT_MODEL = "gemini-3-pro-image-preview";
|
|
@@ -44,7 +45,7 @@ const DEFAULT_ANTIGRAVITY_ENDPOINT_SANDBOX = "https://daily-cloudcode-pa.sandbox
|
|
|
44
45
|
const IMAGE_SYSTEM_INSTRUCTION =
|
|
45
46
|
"You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request.";
|
|
46
47
|
|
|
47
|
-
export type ImageProvider
|
|
48
|
+
export type { ImageProvider } from "./image-providers";
|
|
48
49
|
export type ImageProviderPreference = ImageProvider | "auto";
|
|
49
50
|
|
|
50
51
|
interface ImageApiKey {
|
|
@@ -57,17 +58,8 @@ interface ImageApiKey {
|
|
|
57
58
|
const COMMON_IMAGE_ASPECT_RATIOS = ["1:1", "3:4", "4:3", "9:16", "16:9"] as const;
|
|
58
59
|
const XAI_IMAGE_ASPECT_RATIOS = [...COMMON_IMAGE_ASPECT_RATIOS, "3:2", "2:3"] as const;
|
|
59
60
|
const COMMON_IMAGE_ASPECT_RATIO_SET = new Set<string>(COMMON_IMAGE_ASPECT_RATIOS);
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
"antigravity",
|
|
63
|
-
"gemini",
|
|
64
|
-
"openai",
|
|
65
|
-
"openai-codex",
|
|
66
|
-
"openrouter",
|
|
67
|
-
"xai",
|
|
68
|
-
] as const;
|
|
69
|
-
const IMAGE_PROVIDER_PREFERENCES = new Set<string>(IMAGE_PROVIDER_CHOICES);
|
|
70
|
-
const AUTO_IMAGE_PROVIDER_ORDER = ["openai", "openai-codex", "antigravity", "xai", "openrouter", "gemini"] as const;
|
|
61
|
+
const IMAGE_PROVIDER_REQUEST_CHOICES = ["auto", ...AUTO_IMAGE_PROVIDER_ORDER] as const;
|
|
62
|
+
const IMAGE_PROVIDER_PREFERENCES = new Set<string>(IMAGE_PROVIDER_REQUEST_CHOICES);
|
|
71
63
|
|
|
72
64
|
const responseModalitySchema = type('"IMAGE" | "TEXT"');
|
|
73
65
|
|
|
@@ -81,8 +73,8 @@ const inputImageSchema = type({
|
|
|
81
73
|
});
|
|
82
74
|
|
|
83
75
|
const imageProviderSchema = type
|
|
84
|
-
.enumerated(...
|
|
85
|
-
.describe("image provider for this request; overrides the providers.
|
|
76
|
+
.enumerated(...IMAGE_PROVIDER_REQUEST_CHOICES)
|
|
77
|
+
.describe("image provider for this request; overrides the providers.imageOrder setting (default: use the setting)");
|
|
86
78
|
|
|
87
79
|
export const imageGenSchema = type({
|
|
88
80
|
subject: type("string").describe("main subject"),
|
|
@@ -447,16 +439,16 @@ function extractOpenRouterImageUrls(message: OpenRouterMessage | undefined): str
|
|
|
447
439
|
return urls;
|
|
448
440
|
}
|
|
449
441
|
|
|
450
|
-
/**
|
|
451
|
-
let
|
|
442
|
+
/** Configured provider priority set via `providers.imageOrder` (default: none). */
|
|
443
|
+
let configuredImageProviderOrder: readonly ImageProvider[] = [];
|
|
452
444
|
|
|
453
445
|
export function isImageProviderPreference(value: unknown): value is ImageProviderPreference {
|
|
454
446
|
return typeof value === "string" && IMAGE_PROVIDER_PREFERENCES.has(value);
|
|
455
447
|
}
|
|
456
448
|
|
|
457
|
-
/** Set the
|
|
458
|
-
export function
|
|
459
|
-
|
|
449
|
+
/** Set the configured image-provider priority from settings; invalid IDs are dropped. */
|
|
450
|
+
export function setImageProviderOrder(providers: readonly string[]): void {
|
|
451
|
+
configuredImageProviderOrder = providers.filter(isImageProviderId);
|
|
460
452
|
}
|
|
461
453
|
function assertImageAspectRatioSupported(provider: ImageProvider, aspectRatio: ImageGenParams["aspect_ratio"]): void {
|
|
462
454
|
if (!aspectRatio || provider === "xai" || COMMON_IMAGE_ASPECT_RATIO_SET.has(aspectRatio)) {
|
|
@@ -624,19 +616,19 @@ function activeImageProvider(model: Model | undefined): Exclude<ImageProviderPre
|
|
|
624
616
|
}
|
|
625
617
|
}
|
|
626
618
|
|
|
627
|
-
function imageProviderOrder(
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
):
|
|
631
|
-
const providers: Array<Exclude<ImageProviderPreference, "auto">> = [];
|
|
632
|
-
const added = new Set<Exclude<ImageProviderPreference, "auto">>();
|
|
633
|
-
const add = (provider: Exclude<ImageProviderPreference, "auto"> | null): void => {
|
|
619
|
+
function imageProviderOrder(activeModel: Model | undefined, requested?: ImageProviderPreference): ImageProvider[] {
|
|
620
|
+
const providers: ImageProvider[] = [];
|
|
621
|
+
const added = new Set<ImageProvider>();
|
|
622
|
+
const add = (provider: ImageProvider | null): void => {
|
|
634
623
|
if (!provider || added.has(provider)) return;
|
|
635
624
|
added.add(provider);
|
|
636
625
|
providers.push(provider);
|
|
637
626
|
};
|
|
638
627
|
|
|
639
|
-
|
|
628
|
+
// Per-request provider wins, then the configured priority list, then the
|
|
629
|
+
// active session's provider, then the built-in auto order.
|
|
630
|
+
if (requested !== undefined && requested !== "auto") add(requested);
|
|
631
|
+
for (const provider of configuredImageProviderOrder) add(provider);
|
|
640
632
|
add(activeImageProvider(activeModel));
|
|
641
633
|
for (const provider of AUTO_IMAGE_PROVIDER_ORDER) add(provider);
|
|
642
634
|
return providers;
|
|
@@ -1109,7 +1101,7 @@ export const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails
|
|
|
1109
1101
|
async execute(_toolCallId, params, _onUpdate, ctx, signal) {
|
|
1110
1102
|
return untilAborted(signal, async () => {
|
|
1111
1103
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1112
|
-
const providerOrder = imageProviderOrder(ctx.model, params.provider
|
|
1104
|
+
const providerOrder = imageProviderOrder(ctx.model, params.provider);
|
|
1113
1105
|
const cwd = ctx.sessionManager.getCwd();
|
|
1114
1106
|
const requestSignal = ptree.combineSignals(signal, IMAGE_TIMEOUT);
|
|
1115
1107
|
const fetchImpl = ctx.fetch ?? fetch;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Generation Providers
|
|
3
|
+
*
|
|
4
|
+
* Leaf module (no runtime deps) shared by the image_gen tool, the settings
|
|
5
|
+
* schema, and settings migrations — mirrors `web/search/types.ts` so the
|
|
6
|
+
* provider list, auto order, and settings choices never drift apart.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Image generation backends, in settings/tool vocabulary. */
|
|
10
|
+
export type ImageProvider = "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter" | "xai";
|
|
11
|
+
|
|
12
|
+
/** Auto-resolution fallback order when no configured entry or session provider matches. */
|
|
13
|
+
export const AUTO_IMAGE_PROVIDER_ORDER: readonly ImageProvider[] = [
|
|
14
|
+
"openai",
|
|
15
|
+
"openai-codex",
|
|
16
|
+
"antigravity",
|
|
17
|
+
"xai",
|
|
18
|
+
"openrouter",
|
|
19
|
+
"gemini",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
/** Settings choices for `providers.imageOrder` (labels shared with the retired single-preference enum). */
|
|
23
|
+
export const IMAGE_PROVIDER_CHOICES = [
|
|
24
|
+
{
|
|
25
|
+
value: "openai",
|
|
26
|
+
label: "OpenAI",
|
|
27
|
+
description: "OPENAI_API_KEY (gpt-image-2) or active GPT model; falls back to a connected Codex subscription",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: "openai-codex",
|
|
31
|
+
label: "OpenAI Codex (ChatGPT)",
|
|
32
|
+
description: "Uses a connected Codex / ChatGPT subscription — no OPENAI_API_KEY needed",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
value: "antigravity",
|
|
36
|
+
label: "Antigravity",
|
|
37
|
+
description: "Requires google-antigravity OAuth",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: "xai",
|
|
41
|
+
label: "xAI Grok Imagine",
|
|
42
|
+
description: "Requires xAI Grok OAuth or XAI_API_KEY",
|
|
43
|
+
},
|
|
44
|
+
{ value: "gemini", label: "Gemini", description: "Requires GEMINI_API_KEY" },
|
|
45
|
+
{ value: "openrouter", label: "OpenRouter", description: "Requires OPENROUTER_API_KEY" },
|
|
46
|
+
] as const satisfies ReadonlyArray<{ value: ImageProvider; label: string; description: string }>;
|
|
47
|
+
|
|
48
|
+
export function isImageProviderId(value: unknown): value is ImageProvider {
|
|
49
|
+
return typeof value === "string" && AUTO_IMAGE_PROVIDER_ORDER.includes(value as ImageProvider);
|
|
50
|
+
}
|
package/src/tools/index.ts
CHANGED
|
@@ -20,11 +20,13 @@ import { LspTool } from "../lsp";
|
|
|
20
20
|
import type { MCPManager } from "../mcp";
|
|
21
21
|
import type { MnemopiSessionState } from "../mnemopi/state";
|
|
22
22
|
import type { PlanModeState } from "../plan-mode/state";
|
|
23
|
+
import type { AgentLifecycleManager } from "../registry/agent-lifecycle";
|
|
23
24
|
import type { AgentRegistry } from "../registry/agent-registry";
|
|
24
25
|
import type { ArtifactManager } from "../session/artifacts";
|
|
25
26
|
import type { ClientBridge } from "../session/client-bridge";
|
|
26
27
|
import type { CustomMessage } from "../session/messages";
|
|
27
28
|
import type { UsageStatistics } from "../session/session-entries";
|
|
29
|
+
import type { SessionManager } from "../session/session-manager";
|
|
28
30
|
import type { ToolChoiceQueue } from "../session/tool-choice-queue";
|
|
29
31
|
import { TaskTool } from "../task";
|
|
30
32
|
import type { AgentOutputManager } from "../task/output-manager";
|
|
@@ -143,6 +145,8 @@ export interface DeferredDiagnosticsEntry {
|
|
|
143
145
|
export interface ToolSession {
|
|
144
146
|
/** Current working directory */
|
|
145
147
|
cwd: string;
|
|
148
|
+
/** Additional workspace directories beyond cwd (multi-root), forwarded to subagents. */
|
|
149
|
+
additionalDirectories?: string[];
|
|
146
150
|
/** Whether UI is available */
|
|
147
151
|
hasUI: boolean;
|
|
148
152
|
/**
|
|
@@ -214,6 +218,8 @@ export interface ToolSession {
|
|
|
214
218
|
getEvalSessionId?: () => string | null;
|
|
215
219
|
/** Get session file */
|
|
216
220
|
getSessionFile: () => string | null;
|
|
221
|
+
/** Parent session journal used by tools that persist runtime lifecycle state. */
|
|
222
|
+
sessionManager?: Pick<SessionManager, "appendCustomEntry" | "ensureOnDisk" | "flush" | "getBranch" | "getEntries">;
|
|
217
223
|
/** Get eval kernel owner ID for session-scoped retained-kernel cleanup. */
|
|
218
224
|
getEvalKernelOwnerId?: () => string | null;
|
|
219
225
|
/** Reject new eval work once session disposal has started. */
|
|
@@ -238,6 +244,8 @@ export interface ToolSession {
|
|
|
238
244
|
xdevRegistry?: XdevRegistry;
|
|
239
245
|
/** Agent registry for IRC routing across live sessions. */
|
|
240
246
|
agentRegistry?: AgentRegistry;
|
|
247
|
+
/** Idle→parked→revive lifecycle owner; lets the hub kill a non-job-backed agent registration. Default: AgentLifecycleManager.global(). */
|
|
248
|
+
agentLifecycle?: () => AgentLifecycleManager;
|
|
241
249
|
/** Get artifacts directory for artifact:// URLs */
|
|
242
250
|
getArtifactsDir?: () => string | null;
|
|
243
251
|
/** Get the ArtifactManager backing this session (shared across parent + subagents). */
|
|
@@ -510,6 +518,9 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
510
518
|
if (!requestedTools.includes(name)) requestedTools.push(name);
|
|
511
519
|
}
|
|
512
520
|
}
|
|
521
|
+
if (session.settings.get("memory.backend") === "mnemopi" && !requestedTools.includes("memory_edit")) {
|
|
522
|
+
requestedTools.push("memory_edit");
|
|
523
|
+
}
|
|
513
524
|
// Auto-learn tools are gated by `autolearn.enabled` but, like the memory
|
|
514
525
|
// tools above, must also be force-included into an explicit requestedTools
|
|
515
526
|
// list so a restricted top-level session whose controller/guidance is
|
|
@@ -553,6 +564,7 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
553
564
|
if (name === "retain" || name === "recall" || name === "reflect") {
|
|
554
565
|
return ["hindsight", "mnemopi"].includes(session.settings.get("memory.backend") ?? "");
|
|
555
566
|
}
|
|
567
|
+
if (name === "memory_edit") return session.settings.get("memory.backend") === "mnemopi";
|
|
556
568
|
if (name === "manage_skill") return session.settings.get("autolearn.enabled") && (session.taskDepth ?? 0) === 0;
|
|
557
569
|
if (name === "learn") {
|
|
558
570
|
return (
|
package/src/tools/path-utils.ts
CHANGED
|
@@ -2,10 +2,11 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import * as url from "node:url";
|
|
5
|
-
import {
|
|
5
|
+
import { glob } from "@oh-my-pi/pi-natives";
|
|
6
|
+
import { isEnoent, isEnotdir, stripWindowsExtendedLengthPathPrefix, untilAborted } from "@oh-my-pi/pi-utils";
|
|
6
7
|
import type { Skill } from "../extensibility/skills";
|
|
7
8
|
import { InternalUrlRouter, type LocalProtocolOptions } from "../internal-urls";
|
|
8
|
-
import { ToolError } from "./tool-errors";
|
|
9
|
+
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
9
10
|
|
|
10
11
|
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
11
12
|
// A single line-range chunk: `N`, `N-M`, `N+K`, or open-ended `N-`. `..` is
|
|
@@ -1132,6 +1133,52 @@ export function resolveReadPath(filePath: string, cwd: string): string {
|
|
|
1132
1133
|
return resolved;
|
|
1133
1134
|
}
|
|
1134
1135
|
|
|
1136
|
+
const WORKSPACE_SUFFIX_TIMEOUT_MS = 5000;
|
|
1137
|
+
|
|
1138
|
+
function escapeGlobMetachars(value: string): string {
|
|
1139
|
+
return value.replace(/[*?[{]/g, "[$&]");
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Find a unique workspace entry whose trailing path matches a missing authored path.
|
|
1144
|
+
* Returns `null` for no match, ambiguity, timeout, or scan failure.
|
|
1145
|
+
*/
|
|
1146
|
+
export async function findUniqueWorkspaceSuffix(
|
|
1147
|
+
rawPath: string,
|
|
1148
|
+
cwd: string,
|
|
1149
|
+
signal?: AbortSignal,
|
|
1150
|
+
): Promise<{ absolutePath: string; displayPath: string } | null> {
|
|
1151
|
+
const normalized = rawPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
1152
|
+
if (!normalized) return null;
|
|
1153
|
+
|
|
1154
|
+
const timeoutSignal = AbortSignal.timeout(WORKSPACE_SUFFIX_TIMEOUT_MS);
|
|
1155
|
+
const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
1156
|
+
|
|
1157
|
+
let matches: string[];
|
|
1158
|
+
try {
|
|
1159
|
+
const result = await untilAborted(combinedSignal, () =>
|
|
1160
|
+
glob({
|
|
1161
|
+
pattern: `**/${escapeGlobMetachars(normalized)}`,
|
|
1162
|
+
path: cwd,
|
|
1163
|
+
hidden: true,
|
|
1164
|
+
}),
|
|
1165
|
+
);
|
|
1166
|
+
matches = result.matches.map(match => match.path);
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1169
|
+
if (!signal?.aborted) return null;
|
|
1170
|
+
throw new ToolAbortError();
|
|
1171
|
+
}
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if (matches.length !== 1) return null;
|
|
1176
|
+
return {
|
|
1177
|
+
absolutePath: path.resolve(cwd, matches[0]),
|
|
1178
|
+
displayPath: matches[0],
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1135
1182
|
// =============================================================================
|
|
1136
1183
|
// Tool-scope resolution (search/ast tools)
|
|
1137
1184
|
// =============================================================================
|