@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
package/src/sdk.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
Model,
|
|
18
18
|
ModelUsageHealth,
|
|
19
19
|
ProviderSessionState,
|
|
20
|
+
ServiceTier,
|
|
20
21
|
SimpleStreamOptions,
|
|
21
22
|
} from "@oh-my-pi/pi-ai";
|
|
22
23
|
import { resolveApiKeyOnce } from "@oh-my-pi/pi-ai/auth-retry";
|
|
@@ -66,6 +67,7 @@ import { CursorExecHandlers, type CursorMcpResourceAdapter } from "./cursor";
|
|
|
66
67
|
import { createBridgeEditTool, createBridgeGrepFactory } from "./cursor-bridge-tools";
|
|
67
68
|
import "./discovery";
|
|
68
69
|
import { initializeWithSettings } from "./discovery";
|
|
70
|
+
import { withOmpExtensionRootScope } from "./discovery/omp-extension-roots";
|
|
69
71
|
import { disposeAllJuliaKernelSessions, disposeJuliaKernelSessionsByOwner } from "./eval/jl/executor";
|
|
70
72
|
import { disposeVmContextsByOwner } from "./eval/js/context-manager";
|
|
71
73
|
import { disposeAllKernelSessions, disposeKernelSessionsByOwner } from "./eval/py/executor";
|
|
@@ -101,6 +103,7 @@ import {
|
|
|
101
103
|
import { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from "./extensibility/slash-commands";
|
|
102
104
|
import type { HindsightSessionState } from "./hindsight/state";
|
|
103
105
|
import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls";
|
|
106
|
+
import { setSharedLspEnabled } from "./lsp/client";
|
|
104
107
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events";
|
|
105
108
|
import {
|
|
106
109
|
deduplicateMCPToolsByName,
|
|
@@ -168,6 +171,7 @@ import {
|
|
|
168
171
|
} from "./system-prompt";
|
|
169
172
|
import { AgentOutputManager } from "./task/output-manager";
|
|
170
173
|
import { wrapStreamFnWithProviderConcurrency } from "./task/provider-concurrency";
|
|
174
|
+
import { isScoutSpawnable } from "./task/spawn-policy";
|
|
171
175
|
import type { StructuredSubagentSchemaMode } from "./task/types";
|
|
172
176
|
import {
|
|
173
177
|
AUTO_THINKING,
|
|
@@ -378,6 +382,8 @@ export interface CreateAgentSessionOptions {
|
|
|
378
382
|
thinkingLevel?: ConfiguredThinkingLevel;
|
|
379
383
|
/** Hard ceiling on the session's thinking effort (e.g. a task spawn's `task.maxEffort`-capped hint); retry-fallback recovery re-clamps to it. */
|
|
380
384
|
thinkingLevelCeiling?: Effort;
|
|
385
|
+
/** OpenAI service-tier override for this session. `null` omits `service_tier`. */
|
|
386
|
+
openAIServiceTier?: ServiceTier | null;
|
|
381
387
|
/** Models available for cycling (Ctrl+P in interactive mode) */
|
|
382
388
|
scopedModels?: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
|
|
383
389
|
/** Prewalk from the starting model to a fast/cheap target at the first edit/write once the todo list exists. */
|
|
@@ -695,12 +701,15 @@ export async function discoverSessionExtensionPaths(
|
|
|
695
701
|
cwd: string,
|
|
696
702
|
settings: Settings,
|
|
697
703
|
): Promise<string[]> {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
|
|
704
|
+
const configuredPaths = options.disableExtensionDiscovery
|
|
705
|
+
? (options.additionalExtensionPaths ?? [])
|
|
706
|
+
: [...(options.additionalExtensionPaths ?? []), ...(settings.get("extensions") ?? [])];
|
|
707
|
+
const disabledExtensionIds = options.disableExtensionDiscovery
|
|
708
|
+
? undefined
|
|
709
|
+
: (settings.get("disabledExtensions") ?? []);
|
|
710
|
+
return discoverExtensionPaths(configuredPaths, cwd, disabledExtensionIds, {
|
|
711
|
+
ambient: !options.disableExtensionDiscovery,
|
|
712
|
+
});
|
|
704
713
|
}
|
|
705
714
|
|
|
706
715
|
/**
|
|
@@ -778,9 +787,11 @@ export async function discoverSkills(
|
|
|
778
787
|
export async function discoverContextFiles(
|
|
779
788
|
cwd?: string,
|
|
780
789
|
_agentDir?: string,
|
|
790
|
+
disabledExtensions?: string[],
|
|
781
791
|
): Promise<Array<{ path: string; content: string; depth?: number }>> {
|
|
782
792
|
return await loadContextFilesInternal({
|
|
783
793
|
cwd: cwd ?? getProjectDir(),
|
|
794
|
+
disabledExtensions,
|
|
784
795
|
});
|
|
785
796
|
}
|
|
786
797
|
|
|
@@ -1214,6 +1225,13 @@ export function createAutoLearnCaptureRunner(
|
|
|
1214
1225
|
* ```
|
|
1215
1226
|
*/
|
|
1216
1227
|
export async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {
|
|
1228
|
+
const rootMode = options.disableExtensionDiscovery ? "explicit-only" : "merge";
|
|
1229
|
+
return await withOmpExtensionRootScope(options.additionalExtensionPaths ?? [], rootMode, () =>
|
|
1230
|
+
createAgentSessionScoped(options),
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
async function createAgentSessionScoped(options: CreateAgentSessionOptions): Promise<CreateAgentSessionResult> {
|
|
1217
1235
|
const cwd = options.cwd ?? getProjectDir();
|
|
1218
1236
|
const agentDir = options.agentDir ?? getAgentDir();
|
|
1219
1237
|
const eventBus = options.eventBus ?? new EventBus();
|
|
@@ -1277,14 +1295,15 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1277
1295
|
? Promise.resolve(options.contextFiles)
|
|
1278
1296
|
: logger.time("discoverContextFiles", discoverContextFiles, cwd, agentDir);
|
|
1279
1297
|
contextFilesPromise.catch(() => {});
|
|
1280
|
-
const
|
|
1298
|
+
const resolveRepoContext = async (repoCwd: string) => {
|
|
1281
1299
|
try {
|
|
1282
|
-
return await resolveActiveRepoContext(
|
|
1300
|
+
return await resolveActiveRepoContext(repoCwd);
|
|
1283
1301
|
} catch (err) {
|
|
1284
1302
|
logger.debug("Failed to resolve active repo context", { err: String(err) });
|
|
1285
1303
|
return null;
|
|
1286
1304
|
}
|
|
1287
|
-
}
|
|
1305
|
+
};
|
|
1306
|
+
const activeRepoContextPromise = logger.time("resolveActiveRepoContext", resolveRepoContext, cwd);
|
|
1288
1307
|
activeRepoContextPromise.catch(() => {});
|
|
1289
1308
|
const watchdogFilesPromise = logger.time("discoverWatchdogFiles", () => discoverWatchdogFiles(cwd, agentDir));
|
|
1290
1309
|
watchdogFilesPromise.catch(() => {});
|
|
@@ -1377,11 +1396,15 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1377
1396
|
// headless run on an unwritable default config root pays for a feature it
|
|
1378
1397
|
// does not use.
|
|
1379
1398
|
const needsPlaceholderKey = secretEntriesNeedPlaceholderKey([...envEntries, ...fileEntries]);
|
|
1399
|
+
const explicitAgentDir = options.agentDir;
|
|
1380
1400
|
const placeholderKey = needsPlaceholderKey
|
|
1381
|
-
? await getSecretPlaceholderKey(
|
|
1382
|
-
: await getExistingSecretPlaceholderKey(
|
|
1401
|
+
? await getSecretPlaceholderKey(explicitAgentDir)
|
|
1402
|
+
: await getExistingSecretPlaceholderKey(explicitAgentDir);
|
|
1383
1403
|
if (allEntries.length > 0) {
|
|
1384
|
-
obfuscator = new SecretObfuscator(
|
|
1404
|
+
obfuscator = new SecretObfuscator(
|
|
1405
|
+
allEntries,
|
|
1406
|
+
placeholderKey ?? (() => getSecretPlaceholderKeySync(explicitAgentDir)),
|
|
1407
|
+
);
|
|
1385
1408
|
}
|
|
1386
1409
|
if (obfuscator?.hasSecrets() !== true && placeholderKey !== undefined) {
|
|
1387
1410
|
// No configured entry produced an active secret (e.g. only ignored short
|
|
@@ -1591,7 +1614,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1591
1614
|
}
|
|
1592
1615
|
return result;
|
|
1593
1616
|
};
|
|
1594
|
-
const [
|
|
1617
|
+
const [initialContextFiles, resolvedWorkspaceTree, watchdogFiles, initialActiveRepoContext, discoveredAdvisors] =
|
|
1595
1618
|
await Promise.all([
|
|
1596
1619
|
contextFilesPromise,
|
|
1597
1620
|
raceWithDeadline("buildWorkspaceTree", workspaceTreePromise),
|
|
@@ -1599,6 +1622,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1599
1622
|
activeRepoContextPromise,
|
|
1600
1623
|
advisorConfigsPromise,
|
|
1601
1624
|
]);
|
|
1625
|
+
let contextFiles = initialContextFiles;
|
|
1602
1626
|
|
|
1603
1627
|
let agent: Agent;
|
|
1604
1628
|
let session!: AgentSession;
|
|
@@ -1633,14 +1657,19 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1633
1657
|
const agentKind = (options.taskDepth ?? 0) > 0 || options.parentTaskPrefix ? ("sub" as const) : ("main" as const);
|
|
1634
1658
|
let registeredAgentRef: AgentRef | undefined;
|
|
1635
1659
|
/**
|
|
1636
|
-
* Forget the agent ref on teardown — unless
|
|
1637
|
-
*
|
|
1638
|
-
*
|
|
1660
|
+
* Forget the agent ref on teardown — unless it is a retained terminal ref.
|
|
1661
|
+
* Parking disposes the session but keeps the ref addressable (history://,
|
|
1662
|
+
* revive); a hard kill leaves it as a terminal `aborted` tombstone. Both are
|
|
1663
|
+
* detached (session === null) by the time dispose runs, per the AgentRef
|
|
1664
|
+
* invariant, so preserving them never keeps a disposed session reachable — an
|
|
1665
|
+
* aborted ref that still holds a live session is a bug and is unregistered
|
|
1666
|
+
* rather than handed to ensureLive. Only process teardown / a plain release
|
|
1667
|
+
* unregisters.
|
|
1639
1668
|
*/
|
|
1640
1669
|
const unregisterUnlessParked = (): void => {
|
|
1641
1670
|
const ref = registeredAgentRef;
|
|
1642
1671
|
if (!ref || agentRegistry.get(resolvedAgentId) !== ref) return;
|
|
1643
|
-
if (ref.status === "parked") return;
|
|
1672
|
+
if (ref.status === "parked" || (ref.status === "aborted" && !ref.session)) return;
|
|
1644
1673
|
if (AgentLifecycleManager.global().isParking(resolvedAgentId, ref)) return;
|
|
1645
1674
|
agentRegistry.unregister(resolvedAgentId, ref);
|
|
1646
1675
|
};
|
|
@@ -2650,7 +2679,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2650
2679
|
// a real tool.
|
|
2651
2680
|
//
|
|
2652
2681
|
// It must be a `replace`-mode instance. `PiEditExecArgs` carries
|
|
2653
|
-
// `
|
|
2682
|
+
// `old_string`/`new_string` replacements, which is exactly `replace`'s schema and
|
|
2654
2683
|
// nothing else's — under the default `hashline` mode the frame's args do
|
|
2655
2684
|
// not match the tool's parameters at all. The registry instance follows
|
|
2656
2685
|
// the session's configured mode, so the bridge builds its own.
|
|
@@ -2704,10 +2733,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2704
2733
|
|
|
2705
2734
|
// Existing staged/device paths need write registered before active-set assembly.
|
|
2706
2735
|
// Deferred MCP also registers it now, but refresh activates it only after a server connects.
|
|
2736
|
+
// xd:// mounts never register write: xdev state only exists when the session
|
|
2737
|
+
// already granted a write tool (see createTools), so mounting rides that grant.
|
|
2707
2738
|
const hasDeferrableTools = Array.from(toolRegistry.values()).some(tool => tool.deferrable === true);
|
|
2708
|
-
const hasXdevTools = (toolSession.xdev?.mountedNames.size ?? 0) > 0;
|
|
2709
2739
|
const planModeAvailable = settings.get("plan.enabled");
|
|
2710
|
-
if (!restrictToolNames && (hasDeferrableTools ||
|
|
2740
|
+
if (!restrictToolNames && (hasDeferrableTools || planModeAvailable || deferMCPDiscoveryForUI)) {
|
|
2711
2741
|
await ensureWriteRegistered();
|
|
2712
2742
|
}
|
|
2713
2743
|
|
|
@@ -2783,6 +2813,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2783
2813
|
tools: Map<string, AgentTool>,
|
|
2784
2814
|
): Promise<BuildSystemPromptResult> => {
|
|
2785
2815
|
toolContextStore.setToolNames(toolNames);
|
|
2816
|
+
const promptCwd = sessionManager.getCwd();
|
|
2817
|
+
const activeRepoContext = hasSession
|
|
2818
|
+
? await logger.time("resolveActiveRepoContext", resolveRepoContext, promptCwd)
|
|
2819
|
+
: initialActiveRepoContext;
|
|
2820
|
+
if (hasSession && options.contextFiles === undefined) {
|
|
2821
|
+
contextFiles = await logger.time("discoverContextFiles", discoverContextFiles, promptCwd, agentDir, [
|
|
2822
|
+
...(settings.get("disabledExtensions") ?? []),
|
|
2823
|
+
]);
|
|
2824
|
+
toolSession.contextFiles = contextFiles;
|
|
2825
|
+
session.setAdvisorContextPrompt(formatAdvisorContextPrompt(contextFiles));
|
|
2826
|
+
}
|
|
2786
2827
|
const memoryBackend = restrictToolNames ? undefined : await resolveMemoryBackend(settings);
|
|
2787
2828
|
const memoryInstructions = memoryBackend
|
|
2788
2829
|
? await memoryBackend.buildDeveloperInstructions(agentDir, settings, session)
|
|
@@ -2839,8 +2880,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2839
2880
|
}
|
|
2840
2881
|
}
|
|
2841
2882
|
let appendPrompt: string | undefined = appendParts.length > 0 ? appendParts.join("\n\n") : undefined;
|
|
2842
|
-
// Owned/in-band tool dialects (non-native) require the
|
|
2843
|
-
//
|
|
2883
|
+
// Owned/in-band tool dialects (non-native) require the full functions-
|
|
2884
|
+
// namespace catalog; native tool calling lets the compact name list suffice.
|
|
2844
2885
|
const nativeTools = resolveDialect(settings.get("tools.format"), agent?.state.model ?? model) === undefined;
|
|
2845
2886
|
const promptTools = projectSystemPromptToolMetadata(
|
|
2846
2887
|
tools,
|
|
@@ -2852,7 +2893,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2852
2893
|
: options.appendSystemPrompt;
|
|
2853
2894
|
}
|
|
2854
2895
|
const defaultPrompt = await buildSystemPromptInternal({
|
|
2855
|
-
cwd,
|
|
2896
|
+
cwd: promptCwd,
|
|
2856
2897
|
additionalWorkspaceRoots: sessionManager.getAdditionalDirectories(),
|
|
2857
2898
|
xdevTools: toolSession.xdev ? xdevEntries(toolSession.xdev) : [],
|
|
2858
2899
|
xdevDocs: toolSession.xdev
|
|
@@ -2874,6 +2915,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2874
2915
|
eagerTasksAlways,
|
|
2875
2916
|
taskBatch: settings.get("task.batch"),
|
|
2876
2917
|
taskMaxConcurrency: settings.get("task.maxConcurrency"),
|
|
2918
|
+
scoutAvailable: isScoutSpawnable(
|
|
2919
|
+
settings.get("task.disabledAgents") as string[] | undefined,
|
|
2920
|
+
options.spawns ?? "*",
|
|
2921
|
+
),
|
|
2877
2922
|
taskIrcEnabled: !restrictToolNames && isIrcEnabled(settings, options.taskDepth ?? 0),
|
|
2878
2923
|
autoQaEnabled: !restrictToolNames && isAutoQaEnabled(settings),
|
|
2879
2924
|
secretsEnabled,
|
|
@@ -2953,6 +2998,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2953
2998
|
const xdevReadAvailable =
|
|
2954
2999
|
builtInRegistryToolNames.has("read") &&
|
|
2955
3000
|
(explicitlyRequestedToolNameSet === undefined || explicitlyRequestedToolNameSet.has("read"));
|
|
3001
|
+
const xdevWriteAvailable =
|
|
3002
|
+
builtInRegistryToolNames.has("write") &&
|
|
3003
|
+
(explicitlyRequestedToolNameSet === undefined || explicitlyRequestedToolNameSet.has("write"));
|
|
2956
3004
|
const initialRequestedActiveToolNames = options.toolNames
|
|
2957
3005
|
? requestedActiveToolNames
|
|
2958
3006
|
: requestedActiveToolNames.filter(name => !defaultInactiveToolNames.has(name));
|
|
@@ -2998,23 +3046,23 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2998
3046
|
|
|
2999
3047
|
// Partition the initial enabled set for the xd:// transport. Tool instances
|
|
3000
3048
|
// remain in the canonical map; only presentation names move between layers.
|
|
3049
|
+
// Mounting requires both transport halves in the granted set (`read xd://`
|
|
3050
|
+
// discovers, `write xd://<tool>` executes); a session without either keeps
|
|
3051
|
+
// every tool top-level instead of auto-granting the missing transport.
|
|
3001
3052
|
if (toolSession.xdev) {
|
|
3002
3053
|
const topLevelToolNames: string[] = [];
|
|
3003
3054
|
const mountedNames: string[] = [];
|
|
3004
3055
|
for (const name of initialToolNames) {
|
|
3005
3056
|
const tool = toolRegistry.get(name);
|
|
3006
3057
|
const explicitlyRequested = explicitlyRequestedToolNameSet?.has(name) === true;
|
|
3007
|
-
if (tool && xdevReadAvailable && !explicitlyRequested && isMountableUnderXdev(tool))
|
|
3058
|
+
if (tool && xdevReadAvailable && xdevWriteAvailable && !explicitlyRequested && isMountableUnderXdev(tool))
|
|
3008
3059
|
mountedNames.push(name);
|
|
3009
3060
|
else topLevelToolNames.push(name);
|
|
3010
3061
|
}
|
|
3011
|
-
const writeTransportAvailable = mountedNames.length === 0 || (await ensureWriteRegistered());
|
|
3012
3062
|
toolSession.xdev.mountedNames.clear();
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
if (mountedNames.length > 0 && !initialToolNames.includes("write")) initialToolNames.push("write");
|
|
3017
|
-
}
|
|
3063
|
+
for (const name of mountedNames) toolSession.xdev.mountedNames.add(name);
|
|
3064
|
+
initialToolNames = topLevelToolNames;
|
|
3065
|
+
if (mountedNames.length > 0 && !initialToolNames.includes("write")) initialToolNames.push("write");
|
|
3018
3066
|
}
|
|
3019
3067
|
|
|
3020
3068
|
setActiveToolNames(initialToolNames);
|
|
@@ -3104,13 +3152,19 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3104
3152
|
const openaiWebsocketSetting = settings.get("providers.openaiWebsockets") ?? "off";
|
|
3105
3153
|
const preferOpenAICodexWebsockets =
|
|
3106
3154
|
openaiWebsocketSetting === "on" ? true : openaiWebsocketSetting === "off" ? false : undefined;
|
|
3107
|
-
const
|
|
3155
|
+
const configuredServiceTierByFamily = hasServiceTierEntry
|
|
3108
3156
|
? (existingSession.serviceTier ?? {})
|
|
3109
3157
|
: buildServiceTierByFamily(
|
|
3110
3158
|
settings.get("tier.openai"),
|
|
3111
3159
|
settings.get("tier.anthropic"),
|
|
3112
3160
|
settings.get("tier.google"),
|
|
3113
3161
|
);
|
|
3162
|
+
const initialServiceTierByFamily = { ...configuredServiceTierByFamily };
|
|
3163
|
+
if (options.openAIServiceTier === null) {
|
|
3164
|
+
delete initialServiceTierByFamily.openai;
|
|
3165
|
+
} else if (options.openAIServiceTier !== undefined) {
|
|
3166
|
+
initialServiceTierByFamily.openai = options.openAIServiceTier;
|
|
3167
|
+
}
|
|
3114
3168
|
|
|
3115
3169
|
// One-shot launch-latency marker: fired the first time the loop dispatches
|
|
3116
3170
|
// a chat request to the provider transport. See onFirstChatDispatch.
|
|
@@ -3213,6 +3267,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3213
3267
|
// Restore messages if session has existing data
|
|
3214
3268
|
if (hasExistingSession) {
|
|
3215
3269
|
agent.replaceMessages(existingSession.messages);
|
|
3270
|
+
if (options.openAIServiceTier !== undefined) {
|
|
3271
|
+
sessionManager.appendServiceTierChange(
|
|
3272
|
+
Object.keys(initialServiceTierByFamily).length > 0 ? initialServiceTierByFamily : null,
|
|
3273
|
+
);
|
|
3274
|
+
}
|
|
3216
3275
|
} else {
|
|
3217
3276
|
// Save initial model, thinking level, and service tier for new sessions so they can be restored on resume.
|
|
3218
3277
|
if (model) {
|
|
@@ -3223,8 +3282,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3223
3282
|
// classification persists its concrete effort once a real user turn runs.
|
|
3224
3283
|
sessionManager.appendThinkingLevelChange(effectiveThinkingLevel);
|
|
3225
3284
|
}
|
|
3226
|
-
if (Object.keys(initialServiceTierByFamily).length > 0) {
|
|
3227
|
-
sessionManager.appendServiceTierChange(
|
|
3285
|
+
if (options.openAIServiceTier !== undefined || Object.keys(initialServiceTierByFamily).length > 0) {
|
|
3286
|
+
sessionManager.appendServiceTierChange(
|
|
3287
|
+
Object.keys(initialServiceTierByFamily).length > 0 ? initialServiceTierByFamily : null,
|
|
3288
|
+
);
|
|
3228
3289
|
}
|
|
3229
3290
|
}
|
|
3230
3291
|
|
|
@@ -3271,8 +3332,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3271
3332
|
.map(tool => new ExtensionToolWrapper(wrapToolWithMetaNotice(tool), extensionRunner) as Tool);
|
|
3272
3333
|
|
|
3273
3334
|
const advisorWatchdogPrompts = [...watchdogFiles];
|
|
3274
|
-
if (
|
|
3275
|
-
advisorWatchdogPrompts.push(formatActiveRepoWatchdogPrompt(
|
|
3335
|
+
if (initialActiveRepoContext) {
|
|
3336
|
+
advisorWatchdogPrompts.push(formatActiveRepoWatchdogPrompt(initialActiveRepoContext));
|
|
3276
3337
|
}
|
|
3277
3338
|
const advisorWatchdogPrompt = advisorWatchdogPrompts.length > 0 ? advisorWatchdogPrompts.join("\n\n") : undefined;
|
|
3278
3339
|
// Hand the advisor the same project context files (AGENTS.md, etc.) the
|
|
@@ -3302,6 +3363,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3302
3363
|
initialAdvisorCosts,
|
|
3303
3364
|
settings,
|
|
3304
3365
|
autoApprove: options.autoApprove,
|
|
3366
|
+
scoutAllowedBySpawnPolicy: isScoutSpawnable(undefined, options.spawns ?? "*"),
|
|
3305
3367
|
evalKernelOwnerId,
|
|
3306
3368
|
// Defined only for top-level sessions (creation is gated above).
|
|
3307
3369
|
// AgentSession uses this to decide whether it may dispose the global
|
|
@@ -3504,6 +3566,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3504
3566
|
}
|
|
3505
3567
|
}
|
|
3506
3568
|
|
|
3569
|
+
// Broker-shared language servers: one server per project, multiplexed
|
|
3570
|
+
// across omp instances by the LSP mux daemon. Session-level because the
|
|
3571
|
+
// flag lives in module state consulted on every client cold-start.
|
|
3572
|
+
setSharedLspEnabled(enableLsp && settings.get("lsp.shared"));
|
|
3573
|
+
|
|
3507
3574
|
// Start LSP warmup in the background so startup does not block on language server initialization.
|
|
3508
3575
|
// With `lsp.lazy` (the default) the warmup is skipped: recognized servers are still discovered and
|
|
3509
3576
|
// surfaced in the UI as "available", but cold-start on first use — the lsp tool or an edit/write
|
package/src/secrets/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as crypto from "node:crypto";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { SENSITIVE_TOKEN_RE } from "@oh-my-pi/pi-ai/providers/transform-messages";
|
|
5
|
-
import {
|
|
5
|
+
import { getSecretPlaceholderKeyPath, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import { YAML } from "bun";
|
|
7
7
|
import { regexHasUnresolvableShortMatchFallback, type SecretEntry, sanitizeSecretFriendlyName } from "./obfuscator";
|
|
8
8
|
import { compileSecretRegex } from "./regex";
|
|
@@ -11,17 +11,15 @@ const PLACEHOLDER_KEY_RE = /^[A-Za-z0-9_-]{43}$/;
|
|
|
11
11
|
const cachedPlaceholderKeys = new Map<string, string>();
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Per-install secret key for the placeholder digest. Persisted under
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* key file live sessions use, per `~/.omp/agent/secret-placeholder.key` in
|
|
21
|
-
* docs/secrets.md.
|
|
14
|
+
* Per-install secret key for the placeholder digest. Persisted under XDG state
|
|
15
|
+
* and never sent to a provider, so model-visible placeholders cannot be reversed
|
|
16
|
+
* by dictionary-hashing candidate secrets. Stable across sessions so persisted
|
|
17
|
+
* transcripts deobfuscate consistently. Defaults to `getSecretPlaceholderKeyPath()`
|
|
18
|
+
* — `$XDG_STATE_HOME/omp/secret-placeholder.key` (or `~/.omp/agent/secret-placeholder.key`
|
|
19
|
+
* without XDG), per docs/secrets.md.
|
|
22
20
|
*/
|
|
23
|
-
export async function getSecretPlaceholderKey(keyDir
|
|
24
|
-
const keyPath = path.join(keyDir, "secret-placeholder.key");
|
|
21
|
+
export async function getSecretPlaceholderKey(keyDir?: string): Promise<string> {
|
|
22
|
+
const keyPath = keyDir ? path.join(keyDir, "secret-placeholder.key") : getSecretPlaceholderKeyPath();
|
|
25
23
|
const cached = cachedPlaceholderKeys.get(keyPath);
|
|
26
24
|
if (cached !== undefined) return cached;
|
|
27
25
|
|
|
@@ -32,7 +30,7 @@ export async function getSecretPlaceholderKey(keyDir: string = getAgentDir()): P
|
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
const generated = crypto.randomBytes(32).toString("base64url");
|
|
35
|
-
await fs.promises.mkdir(
|
|
33
|
+
await fs.promises.mkdir(path.dirname(keyPath), { recursive: true });
|
|
36
34
|
try {
|
|
37
35
|
await fs.promises.writeFile(keyPath, generated, { flag: "wx", mode: 0o600 });
|
|
38
36
|
cachedPlaceholderKeys.set(keyPath, generated);
|
|
@@ -53,8 +51,8 @@ export async function getSecretPlaceholderKey(keyDir: string = getAgentDir()): P
|
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
/** Return an existing placeholder key for redaction without creating a new key file. */
|
|
56
|
-
export async function getExistingSecretPlaceholderKey(keyDir
|
|
57
|
-
const keyPath = path.join(keyDir, "secret-placeholder.key");
|
|
54
|
+
export async function getExistingSecretPlaceholderKey(keyDir?: string): Promise<string | undefined> {
|
|
55
|
+
const keyPath = keyDir ? path.join(keyDir, "secret-placeholder.key") : getSecretPlaceholderKeyPath();
|
|
58
56
|
const cached = cachedPlaceholderKeys.get(keyPath);
|
|
59
57
|
if (cached !== undefined) return cached;
|
|
60
58
|
// Redaction-only: this key is loaded solely to redact an existing key file from
|
|
@@ -85,8 +83,8 @@ let ephemeralSyncPlaceholderKey: string | undefined;
|
|
|
85
83
|
* throws: an unreadable or unwritable key file degrades to a process-ephemeral
|
|
86
84
|
* key (with a warning) instead of breaking the session.
|
|
87
85
|
*/
|
|
88
|
-
export function getSecretPlaceholderKeySync(keyDir
|
|
89
|
-
const keyPath = path.join(keyDir, "secret-placeholder.key");
|
|
86
|
+
export function getSecretPlaceholderKeySync(keyDir?: string): string {
|
|
87
|
+
const keyPath = keyDir ? path.join(keyDir, "secret-placeholder.key") : getSecretPlaceholderKeyPath();
|
|
90
88
|
const cached = cachedPlaceholderKeys.get(keyPath);
|
|
91
89
|
if (cached !== undefined) return cached;
|
|
92
90
|
try {
|
|
@@ -100,7 +98,7 @@ export function getSecretPlaceholderKeySync(keyDir: string = getAgentDir()): str
|
|
|
100
98
|
}
|
|
101
99
|
const generated = crypto.randomBytes(32).toString("base64url");
|
|
102
100
|
try {
|
|
103
|
-
fs.mkdirSync(
|
|
101
|
+
fs.mkdirSync(path.dirname(keyPath), { recursive: true });
|
|
104
102
|
fs.writeFileSync(keyPath, generated, { flag: "wx", mode: 0o600 });
|
|
105
103
|
cachedPlaceholderKeys.set(keyPath, generated);
|
|
106
104
|
return generated;
|
|
@@ -205,7 +203,7 @@ export function collectEnvSecrets(): SecretEntry[] {
|
|
|
205
203
|
* API keys) that are NOT configured via secrets.yml or the environment. Without
|
|
206
204
|
* these, such a token in a tool result falls through to pi-ai's irreversible
|
|
207
205
|
* provider-boundary redaction (`[openai_token_redacted]`); the model then echoes
|
|
208
|
-
* that placeholder into edit-tool `
|
|
206
|
+
* that placeholder into edit-tool `old_string`, which can never match the real
|
|
209
207
|
* bytes on disk (issue #6968). Routing the same shapes through the obfuscator
|
|
210
208
|
* mints reversible keyed placeholders that `deobfuscateToolArguments` restores
|
|
211
209
|
* before tool execution, keeping exact-match edits working while the credential
|
|
@@ -109,6 +109,8 @@ export interface AgentSessionConfig {
|
|
|
109
109
|
agent: Agent;
|
|
110
110
|
sessionManager: SessionManager;
|
|
111
111
|
settings: Settings;
|
|
112
|
+
/** Whether the session spawn policy permits the read-only `scout` subagent. Defaults to true. */
|
|
113
|
+
scoutAllowedBySpawnPolicy?: boolean;
|
|
112
114
|
/** Whether the caller explicitly requested yolo/auto-approve behavior for this session. */
|
|
113
115
|
autoApprove?: boolean;
|
|
114
116
|
/** Models to cycle through with Ctrl+P (from --models flag). */
|
|
@@ -232,7 +234,7 @@ export interface AgentSessionConfig {
|
|
|
232
234
|
/**
|
|
233
235
|
* Build the `replace`-mode `edit` a Cursor `pi_edit` frame needs, against the
|
|
234
236
|
* advisor-scoped tool session. The advisor's ordinary instance follows the
|
|
235
|
-
* configured `edit.mode` and rejects the frame's `
|
|
237
|
+
* configured `edit.mode` and rejects the frame's `old_string`/`new_string` args.
|
|
236
238
|
*/
|
|
237
239
|
advisorCreateEditTool?(): AgentTool | undefined;
|
|
238
240
|
/**
|
|
@@ -518,6 +518,7 @@ export class AgentSession {
|
|
|
518
518
|
// Agent identity (registry id) used for IRC routing and job ownership.
|
|
519
519
|
#agentId: string | undefined;
|
|
520
520
|
#agentKind: "main" | "sub" = "main";
|
|
521
|
+
#scoutAllowedBySpawnPolicy = true;
|
|
521
522
|
#providerSessionId: string | undefined;
|
|
522
523
|
#freshProviderSessionId: string | undefined;
|
|
523
524
|
#inheritedProviderPromptCacheKey: string | undefined;
|
|
@@ -1237,6 +1238,7 @@ export class AgentSession {
|
|
|
1237
1238
|
this.#loopGuards = new LoopGuards(streamGuardsHost);
|
|
1238
1239
|
this.#agentId = config.agentId;
|
|
1239
1240
|
this.#agentKind = config.agentKind ?? "main";
|
|
1241
|
+
this.#scoutAllowedBySpawnPolicy = config.scoutAllowedBySpawnPolicy ?? true;
|
|
1240
1242
|
this.#providerSessionId = config.providerSessionId;
|
|
1241
1243
|
this.#inheritedProviderPromptCacheKey =
|
|
1242
1244
|
config.providerPromptCacheKeySource === "fork" ? this.agent.promptCacheKey : undefined;
|
|
@@ -1382,6 +1384,7 @@ export class AgentSession {
|
|
|
1382
1384
|
extensionRunner: this.#extensionRunner,
|
|
1383
1385
|
sideStreamFn: this.#sideStreamFn,
|
|
1384
1386
|
providerSessionState: this.#providerSessionState,
|
|
1387
|
+
preferWebsockets: this.#preferWebsockets,
|
|
1385
1388
|
model: () => this.model,
|
|
1386
1389
|
thinkingLevel: () => this.thinkingLevel,
|
|
1387
1390
|
isDisposed: () => this.#isDisposed,
|
|
@@ -1417,6 +1420,7 @@ export class AgentSession {
|
|
|
1417
1420
|
syncTodoPhasesFromBranch: () => this.#todo.syncFromBranch(),
|
|
1418
1421
|
resetAdvisorRuntimes: () => this.#advisors.resetAllRuntimes(),
|
|
1419
1422
|
rebaseAfterCompaction: () => this.#stats.rebaseAfterCompaction(),
|
|
1423
|
+
recordAnchoredHistoryRewrite: tokensRemoved => this.#stats.recordAnchoredHistoryRewrite(tokensRemoved),
|
|
1420
1424
|
getContextBreakdown: options => this.getContextBreakdown(options),
|
|
1421
1425
|
getContextUsage: options => this.getContextUsage(options),
|
|
1422
1426
|
shake: (mode, options) => this.shake(mode, options),
|
|
@@ -4634,6 +4638,11 @@ export class AgentSession {
|
|
|
4634
4638
|
};
|
|
4635
4639
|
}
|
|
4636
4640
|
|
|
4641
|
+
#isScoutAvailable(): boolean {
|
|
4642
|
+
const disabledAgents = this.settings.get("task.disabledAgents") as string[] | undefined;
|
|
4643
|
+
return this.#scoutAllowedBySpawnPolicy && !disabledAgents?.includes("scout");
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4637
4646
|
async #buildPlanModeMessage(): Promise<CustomMessage | null> {
|
|
4638
4647
|
const state = this.#planModeState;
|
|
4639
4648
|
if (!state?.enabled) return null;
|
|
@@ -4657,6 +4666,7 @@ export class AgentSession {
|
|
|
4657
4666
|
isHashlineEditMode: this.#resolveActiveEditMode() === "hashline",
|
|
4658
4667
|
reentry: state.reentry ?? false,
|
|
4659
4668
|
iterative: state.workflow === "iterative",
|
|
4669
|
+
scoutAvailable: this.#isScoutAvailable(),
|
|
4660
4670
|
});
|
|
4661
4671
|
|
|
4662
4672
|
return {
|
|
@@ -4788,7 +4798,10 @@ export class AgentSession {
|
|
|
4788
4798
|
keywordNotices.push({
|
|
4789
4799
|
role: "custom",
|
|
4790
4800
|
customType: "workflow-notice",
|
|
4791
|
-
content: renderWorkflowNotice({
|
|
4801
|
+
content: renderWorkflowNotice({
|
|
4802
|
+
taskBatch: this.settings.get("task.batch"),
|
|
4803
|
+
scoutAvailable: this.#isScoutAvailable(),
|
|
4804
|
+
}),
|
|
4792
4805
|
display: false,
|
|
4793
4806
|
attribution: "user",
|
|
4794
4807
|
timestamp,
|
|
@@ -6333,7 +6346,6 @@ export class AgentSession {
|
|
|
6333
6346
|
selector?: string;
|
|
6334
6347
|
thinkingLevel?: ThinkingLevel;
|
|
6335
6348
|
persist?: boolean;
|
|
6336
|
-
currentContextTokens?: number;
|
|
6337
6349
|
},
|
|
6338
6350
|
): Promise<{ switched: boolean }> {
|
|
6339
6351
|
return this.#models.setModel(model, role, options);
|
|
@@ -8719,6 +8731,15 @@ export class AgentSession {
|
|
|
8719
8731
|
return this.#advisors.applyAdvisorConfigs(advisors, sharedInstructions);
|
|
8720
8732
|
}
|
|
8721
8733
|
|
|
8734
|
+
/**
|
|
8735
|
+
* Refresh the project context prompt advisor sessions run against after
|
|
8736
|
+
* context files change on `/reload-plugins`. Rebuilds live advisor runtimes so
|
|
8737
|
+
* they stop evaluating turns against stale `AGENTS.md` instructions.
|
|
8738
|
+
*/
|
|
8739
|
+
setAdvisorContextPrompt(contextPrompt: string | undefined): void {
|
|
8740
|
+
this.#advisors.setContextPrompt(contextPrompt);
|
|
8741
|
+
}
|
|
8742
|
+
|
|
8722
8743
|
/**
|
|
8723
8744
|
* Whether the advisor setting is enabled for this session.
|
|
8724
8745
|
*/
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
SqliteAuthCredentialStore,
|
|
9
9
|
type StoredAuthCredential,
|
|
10
10
|
} from "@oh-my-pi/pi-ai";
|
|
11
|
-
import { AsyncDrain, getAgentDbPath, getStatsDbPath, isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
11
|
+
import { AsyncDrain, getAgentDbPath, getDbBusyTimeoutMs, getStatsDbPath, isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
12
12
|
import type { RawSettings as Settings } from "../config/settings";
|
|
13
13
|
|
|
14
14
|
/** Row shape for settings table queries */
|
|
@@ -199,8 +199,10 @@ ON CONFLICT(model_key) DO UPDATE SET
|
|
|
199
199
|
// Install the busy handler BEFORE any lock-taking statement (incl.
|
|
200
200
|
// `PRAGMA journal_mode=WAL`, which acquires an exclusive lock during WAL
|
|
201
201
|
// recovery). Without this, concurrent omp startups can crash here with
|
|
202
|
-
// `SQLITE_BUSY` / `SQLITE_BUSY_RECOVERY`. See issue #2421.
|
|
203
|
-
|
|
202
|
+
// `SQLITE_BUSY` / `SQLITE_BUSY_RECOVERY`. See issue #2421. Headless
|
|
203
|
+
// hosts bound the wait so lock contention cannot freeze the protocol
|
|
204
|
+
// loop for the full interactive timeout.
|
|
205
|
+
this.#db.run(`PRAGMA busy_timeout = ${getDbBusyTimeoutMs()}`);
|
|
204
206
|
this.#db.run(`
|
|
205
207
|
PRAGMA journal_mode=WAL;
|
|
206
208
|
PRAGMA synchronous=NORMAL;
|
|
@@ -571,7 +573,7 @@ FROM model_usage_legacy
|
|
|
571
573
|
async backfillModelPerfFromStats(statsDbPath: string): Promise<number> {
|
|
572
574
|
const statsDb = new Database(statsDbPath, { readonly: true });
|
|
573
575
|
try {
|
|
574
|
-
statsDb.run(
|
|
576
|
+
statsDb.run(`PRAGMA busy_timeout = ${getDbBusyTimeoutMs()}`);
|
|
575
577
|
const select = statsDb.prepare(
|
|
576
578
|
`SELECT rowid, timestamp, provider, model, output_tokens, duration, ttft
|
|
577
579
|
FROM messages
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Database, type Statement } from "bun:sqlite";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { AsyncDrain, getHistoryDbPath, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { AsyncDrain, getDbBusyTimeoutMs, getHistoryDbPath, logger } from "@oh-my-pi/pi-utils";
|
|
5
5
|
|
|
6
6
|
export interface HistoryEntry {
|
|
7
7
|
id: number;
|
|
@@ -51,7 +51,9 @@ export class HistoryStorage {
|
|
|
51
51
|
this.#db = new Database(dbPath);
|
|
52
52
|
|
|
53
53
|
// Install the busy handler BEFORE any lock-taking statement. See #2421.
|
|
54
|
-
|
|
54
|
+
// Headless hosts bound the wait so lock contention cannot freeze the
|
|
55
|
+
// protocol loop for the full interactive timeout.
|
|
56
|
+
this.#db.run(`PRAGMA busy_timeout = ${getDbBusyTimeoutMs()}`);
|
|
55
57
|
|
|
56
58
|
const hasFts = this.#db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='history_fts'").get();
|
|
57
59
|
this.#db.run(`
|
|
@@ -511,6 +511,15 @@ class IndexedSessionStorageWriter implements SessionStorageWriter {
|
|
|
511
511
|
return next;
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
+
appendSync(line: string): void {
|
|
515
|
+
if (this.#closed) throw new Error("Writer closed");
|
|
516
|
+
if (this.#error) throw this.#error;
|
|
517
|
+
// Local index is updated immediately; remote publish stays ordered on the
|
|
518
|
+
// path queue. Callers that need remote durability still await append()/flush().
|
|
519
|
+
const mtimeMs = this.#storage._appendForWriter(this.#path, line);
|
|
520
|
+
void this.#trackPromise(this.#storage._queueAppend(this.#path, line, mtimeMs, () => this.#error));
|
|
521
|
+
}
|
|
522
|
+
|
|
514
523
|
async append(line: string): Promise<void> {
|
|
515
524
|
if (this.#closed) throw new Error("Writer closed");
|
|
516
525
|
if (this.#error) throw this.#error;
|