@oh-my-pi/pi-coding-agent 17.2.9 → 17.2.11
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 +83 -0
- package/dist/{CHANGELOG-8yy8h3bc.md → CHANGELOG-d9xenpn9.md} +83 -0
- package/dist/cli.js +10208 -12596
- package/dist/types/capability/mcp.d.ts +11 -0
- package/dist/types/capability/skill.d.ts +6 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/commands/share.d.ts +25 -0
- package/dist/types/commit/agentic/index.d.ts +3 -1
- package/dist/types/commit/execute.d.ts +32 -0
- package/dist/types/commit/index.d.ts +2 -1
- package/dist/types/commit/pipeline.d.ts +7 -1
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +13 -0
- package/dist/types/config/settings-schema.d.ts +1 -34
- package/dist/types/discovery/agent-plugin-format.d.ts +143 -0
- package/dist/types/discovery/agent-plugins.d.ts +1 -0
- package/dist/types/discovery/contained-path.d.ts +34 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +5 -5
- package/dist/types/extensibility/custom-tools/types.d.ts +3 -3
- package/dist/types/extensibility/extensions/loader.d.ts +9 -2
- package/dist/types/extensibility/extensions/types.d.ts +45 -8
- package/dist/types/extensibility/hooks/types.d.ts +5 -5
- package/dist/types/extensibility/shared-events.d.ts +3 -2
- package/dist/types/extensibility/skills.d.ts +5 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/main.d.ts +1 -1
- package/dist/types/mcp/transports/header-policy.d.ts +45 -0
- package/dist/types/mcp/types.d.ts +15 -0
- package/dist/types/modes/acp/acp-agent.d.ts +1 -1
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -1
- package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -1
- package/dist/types/modes/acp/acp-mode.d.ts +1 -1
- package/dist/types/modes/components/agent-hub-projection.d.ts +38 -0
- package/dist/types/modes/components/agent-hub-renderer.d.ts +41 -0
- package/dist/types/modes/components/agent-hub.d.ts +14 -5
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -2
- package/dist/types/modes/components/model-browser.d.ts +9 -1
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +8 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
- package/dist/types/registry/agent-registry.d.ts +47 -0
- package/dist/types/registry/persisted-agents.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +23 -1
- package/dist/types/session/agent-session-events.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/prewalk.d.ts +3 -1
- package/dist/types/session/session-entries.d.ts +10 -0
- package/dist/types/session/session-loader.d.ts +11 -1
- package/dist/types/session/session-manager.d.ts +9 -1
- package/dist/types/session/session-tools.d.ts +18 -1
- package/dist/types/session/turn-recovery.d.ts +7 -2
- package/dist/types/slash-commands/acp-builtins.d.ts +1 -1
- package/dist/types/slash-commands/available-commands.d.ts +1 -1
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/index.d.ts +4 -3
- package/dist/types/task/read-only-policy.d.ts +3 -0
- package/dist/types/task/structured-subagent.d.ts +2 -0
- package/dist/types/task/types.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +3 -3
- package/dist/types/tools/browser/launch.d.ts +2 -1
- package/dist/types/tools/browser/tab-worker.d.ts +2 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +1 -5
- package/dist/types/tools/run-scope.d.ts +27 -1
- package/dist/types/tools/shell-tokenize.d.ts +16 -0
- package/dist/types/tools/terminal-output.d.ts +1 -1
- package/dist/types/utils/turndown.d.ts +1 -1
- package/dist/types/vibe/runtime.d.ts +2 -3
- package/dist/types/web/scrapers/readthedocs.d.ts +0 -3
- package/dist/types/web/search/providers/browser-headers.d.ts +2 -3
- package/examples/custom-tools/README.md +1 -1
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/api-demo.ts +5 -6
- package/examples/extensions/chalk-logger.ts +1 -1
- package/examples/extensions/hello.ts +2 -2
- package/examples/extensions/reload-runtime.ts +1 -1
- package/examples/extensions/tools.ts +2 -2
- package/examples/extensions/with-deps/index.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/package.json +15 -31
- package/scripts/bundle-dist.ts +1 -11
- package/scripts/legacy-pi-virtual-module.ts +4 -1
- package/src/advisor/runtime.ts +54 -0
- package/src/capability/mcp.ts +11 -0
- package/src/capability/skill.ts +6 -0
- package/src/cli/agents-cli.ts +1 -1
- package/src/cli/args.ts +24 -2
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/claude-trace-cli.ts +1 -1
- package/src/cli/command-help.ts +4 -0
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/flag-tables.ts +4 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/help-extra.ts +1 -1
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/read-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +1 -1
- package/src/cli/tiny-models-cli.ts +1 -1
- package/src/cli/ttsr-cli.ts +1 -1
- package/src/cli/update-cli.ts +1 -1
- package/src/cli/usage-cli.ts +1 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli/worktree-cli.ts +1 -1
- package/src/cli-commands.ts +5 -0
- package/src/commands/commit.ts +16 -3
- package/src/commands/say.ts +1 -1
- package/src/commands/share.ts +71 -0
- package/src/commands/token.ts +1 -1
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/agentic/index.ts +39 -21
- package/src/commit/cli.ts +1 -1
- package/src/commit/execute.ts +56 -0
- package/src/commit/index.ts +2 -1
- package/src/commit/pipeline.ts +20 -7
- package/src/config/model-discovery.ts +1 -1
- package/src/config/model-registry.ts +21 -1
- package/src/config/model-resolver.ts +54 -7
- package/src/config/settings-schema.ts +2 -33
- package/src/config/settings.ts +46 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/agents.ts +4 -2
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +5 -4
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +1 -1
- package/src/discovery/claude-plugins.ts +21 -5
- package/src/discovery/contained-path.ts +78 -0
- package/src/discovery/helpers.ts +23 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/omp-plugins.ts +20 -7
- package/src/eval/py/runner.py +38 -1
- package/src/exec/non-interactive-env.ts +1 -0
- package/src/extensibility/custom-commands/loader.ts +4 -4
- package/src/extensibility/custom-commands/types.ts +5 -5
- package/src/extensibility/custom-tools/loader.ts +4 -4
- package/src/extensibility/custom-tools/types.ts +3 -3
- package/src/extensibility/extensions/loader.ts +85 -20
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +51 -8
- package/src/extensibility/hooks/loader.ts +4 -5
- package/src/extensibility/hooks/types.ts +5 -5
- package/src/extensibility/plugins/legacy-pi-compat.ts +53 -0
- package/src/extensibility/plugins/marketplace/manager.ts +2 -1
- package/src/extensibility/shared-events.ts +3 -2
- package/src/extensibility/skills.ts +9 -0
- package/src/index.ts +2 -2
- package/src/internal-urls/memory-protocol.ts +5 -1
- package/src/internal-urls/skill-protocol.ts +14 -0
- package/src/internal-urls/vault-protocol.ts +2 -2
- package/src/launch/client.ts +11 -1
- package/src/launch/protocol.ts +7 -2
- package/src/launch/terminal-output.ts +1 -1
- package/src/main.ts +88 -23
- package/src/markit/converters/docx.ts +1 -1
- package/src/markit/converters/epub.ts +1 -1
- package/src/markit/converters/pptx.ts +1 -1
- package/src/markit/converters/xlsx.ts +1 -1
- package/src/mcp/config.ts +3 -0
- package/src/mcp/manager.ts +12 -9
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +35 -52
- package/src/mcp/transports/sse.ts +20 -27
- package/src/mcp/types.ts +15 -0
- package/src/modes/acp/acp-agent.ts +20 -9
- package/src/modes/acp/acp-client-bridge.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/acp/acp-mode.ts +1 -1
- package/src/modes/components/agent-dashboard.ts +2 -0
- package/src/modes/components/agent-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +674 -207
- package/src/modes/components/agent-transcript-viewer.ts +3 -0
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/chat-transcript-builder.ts +3 -0
- package/src/modes/components/custom-editor.ts +0 -9
- package/src/modes/components/extensions/inspector-panel.ts +11 -6
- package/src/modes/components/footer.ts +1 -3
- package/src/modes/components/model-browser.ts +11 -3
- package/src/modes/components/model-hub.ts +4 -1
- package/src/modes/components/status-line/component.ts +1 -0
- package/src/modes/components/status-line/segments.ts +10 -7
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/tool-execution.ts +13 -16
- package/src/modes/components/tree-selector.ts +62 -3
- package/src/modes/controllers/command-controller.ts +4 -1
- package/src/modes/controllers/event-controller.ts +44 -20
- package/src/modes/controllers/extension-ui-controller.ts +2 -2
- package/src/modes/controllers/input-controller.ts +20 -2
- package/src/modes/controllers/mcp-command-controller.ts +81 -20
- package/src/modes/controllers/selector-controller.ts +41 -49
- package/src/modes/controllers/streaming-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/utils/transcript-render-helpers.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/tools/computer.md +1 -1
- package/src/registry/agent-lifecycle.ts +14 -7
- package/src/registry/agent-registry.ts +65 -2
- package/src/registry/persisted-agents.ts +341 -16
- package/src/sdk.ts +6 -49
- package/src/secrets/index.ts +52 -1
- package/src/session/agent-session-events.ts +2 -2
- package/src/session/agent-session.ts +54 -16
- package/src/session/messages.ts +1 -0
- package/src/session/prewalk.ts +57 -17
- package/src/session/session-context.ts +3 -5
- package/src/session/session-entries.ts +10 -0
- package/src/session/session-handoff.ts +5 -1
- package/src/session/session-listing.ts +1 -1
- package/src/session/session-loader.ts +74 -8
- package/src/session/session-manager.ts +22 -2
- package/src/session/session-paths.ts +57 -9
- package/src/session/session-tools.ts +65 -4
- package/src/session/todo-tracker.ts +11 -1
- package/src/session/turn-recovery.ts +96 -74
- package/src/slash-commands/acp-builtins.ts +1 -1
- package/src/slash-commands/available-commands.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +12 -8
- package/src/task/executor.ts +70 -20
- package/src/task/index.ts +30 -34
- package/src/task/isolation-runner.ts +24 -11
- package/src/task/persisted-revive.ts +12 -5
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/structured-subagent.ts +14 -4
- package/src/task/types.ts +4 -0
- package/src/tools/auto-generated-guard.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash-skill-urls.ts +15 -0
- package/src/tools/bash.ts +16 -17
- package/src/tools/browser/cmux/cmux-tab.ts +66 -18
- package/src/tools/browser/launch.ts +41 -12
- package/src/tools/browser/readable.ts +9 -9
- package/src/tools/browser/tab-supervisor.ts +12 -3
- package/src/tools/browser/tab-worker-entry.ts +1 -1
- package/src/tools/browser/tab-worker.ts +101 -12
- package/src/tools/debug.ts +1 -1
- package/src/tools/fetch.ts +1 -1
- package/src/tools/jtd-to-json-schema.ts +123 -21
- package/src/tools/path-utils.ts +9 -2
- package/src/tools/read.ts +21 -9
- package/src/tools/run-scope.ts +290 -4
- package/src/tools/shell-tokenize.ts +98 -0
- package/src/tools/terminal-output.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/utils/clipboard.ts +10 -2
- package/src/utils/external-editor.ts +4 -2
- package/src/utils/jj.ts +1 -1
- package/src/utils/turndown.ts +1 -2
- package/src/vibe/runtime.ts +5 -5
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +2 -1
- package/src/web/scrapers/twitter.ts +2 -2
- package/src/web/scrapers/types.ts +1 -1
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/search/providers/browser-headers.ts +12 -39
- package/src/web/search/providers/codex.ts +3 -26
- package/src/web/search/providers/ecosia.ts +1 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/google.ts +1 -1
- package/src/web/search/providers/mojeek.ts +1 -1
- package/src/web/search/providers/startpage.ts +1 -1
- package/src/markit/converters/mammoth.d.ts +0 -24
|
@@ -44,6 +44,7 @@ import type { SessionOAuthAccountList } from "../session/agent-session-types";
|
|
|
44
44
|
import { COMPACT_MODES, parseCompactArgs } from "../session/compact-modes";
|
|
45
45
|
import { resolveResumableSession } from "../session/session-listing";
|
|
46
46
|
import { formatShakeSummary, type ShakeMode } from "../session/shake-types";
|
|
47
|
+
import { refreshAgentDiscovery } from "../task";
|
|
47
48
|
import type { ComputerTool } from "../tools/computer";
|
|
48
49
|
import { computerExposureMode } from "../tools/computer/exposure";
|
|
49
50
|
import { expandTilde, resolveToCwd } from "../tools/path-utils";
|
|
@@ -762,10 +763,12 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
762
763
|
if (!runtime.session.modelRegistry.hasConfiguredAuth(resolved.model)) {
|
|
763
764
|
return usage(`No API key for ${resolved.model.provider}/${resolved.model.id}`, runtime);
|
|
764
765
|
}
|
|
765
|
-
runtime.session.armPrewalk(resolved.model, resolved.thinkingLevel);
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
766
|
+
const armed = runtime.session.armPrewalk(resolved.model, resolved.thinkingLevel);
|
|
767
|
+
if (armed) {
|
|
768
|
+
await runtime.output(
|
|
769
|
+
`Prewalk on: switching to ${resolved.model.provider}/${resolved.model.id} at the next edit/write (todo-gated).`,
|
|
770
|
+
);
|
|
771
|
+
}
|
|
769
772
|
return commandConsumed();
|
|
770
773
|
},
|
|
771
774
|
},
|
|
@@ -3067,14 +3070,15 @@ export const BUILTIN_SLASH_COMMANDS_INTERNAL: ReadonlyArray<SlashCommandSpec> =
|
|
|
3067
3070
|
|
|
3068
3071
|
/**
|
|
3069
3072
|
* Reload the interactive session's plugin runtime: invalidate fs/plugin-root
|
|
3070
|
-
* caches, rediscover skills
|
|
3071
|
-
* cache, and reconnect MCP servers (rebinding the session's MCP
|
|
3072
|
-
* by `/reload-plugins`'s TUI handler and the `handle`-adapter's
|
|
3073
|
-
* hook so both honor the command's documented
|
|
3073
|
+
* caches, rediscover skills, file slash commands, and task agents, reset the
|
|
3074
|
+
* capability cache, and reconnect MCP servers (rebinding the session's MCP
|
|
3075
|
+
* tools). Shared by `/reload-plugins`'s TUI handler and the `handle`-adapter's
|
|
3076
|
+
* `reloadPlugins` hook so both honor the command's documented reload scope.
|
|
3074
3077
|
*/
|
|
3075
3078
|
async function reloadTuiPluginState(ctx: InteractiveModeContext): Promise<void> {
|
|
3076
3079
|
const projectPath = await resolveActiveProjectRegistryPath(ctx.sessionManager.getCwd());
|
|
3077
3080
|
clearPluginRootsAndCaches(projectPath ? [projectPath] : undefined);
|
|
3081
|
+
await refreshAgentDiscovery(ctx.sessionManager.getCwd());
|
|
3078
3082
|
await ctx.refreshSkillState();
|
|
3079
3083
|
await ctx.refreshSlashCommandState();
|
|
3080
3084
|
resetCapabilities();
|
package/src/task/executor.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
formatModelStringWithRouting,
|
|
18
18
|
resolveAgentPrewalkPattern,
|
|
19
19
|
resolveConfiguredModelPatterns,
|
|
20
|
+
resolveExplicitModelRole,
|
|
20
21
|
resolveModelOverride,
|
|
21
22
|
resolveModelOverrideWithAuthFallback,
|
|
22
23
|
} from "../config/model-resolver";
|
|
@@ -59,6 +60,7 @@ import { buildNamedToolChoice } from "../utils/tool-choice";
|
|
|
59
60
|
import type { WorkspaceTree } from "../workspace-tree";
|
|
60
61
|
import { generateTaskLabel } from "./label";
|
|
61
62
|
import { resolveAgentPrewalkDefault } from "./prewalk";
|
|
63
|
+
import { isReadOnlyAgent } from "./read-only-policy";
|
|
62
64
|
import { subprocessToolRegistry } from "./subprocess-tool-registry";
|
|
63
65
|
import {
|
|
64
66
|
type AgentDefinition,
|
|
@@ -183,11 +185,26 @@ function resolveSubagentRetryFallbackCandidates(
|
|
|
183
185
|
return candidates;
|
|
184
186
|
}
|
|
185
187
|
|
|
186
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Chain a single-model subagent inherits when its own model patterns supply no
|
|
190
|
+
* fallbacks of their own. The child is pinned to a `subagent:<id>` role whose
|
|
191
|
+
* chain shadows every configured role chain (see
|
|
192
|
+
* {@link installSubagentRetryFallbackChain}), so a role-alias request (`@smol`)
|
|
193
|
+
* MUST inherit that role's chain — otherwise the pin silently re-routes the
|
|
194
|
+
* child onto the `default` role's chain. Explicit model selectors keep
|
|
195
|
+
* inheriting `default`: they carry no role identity, and a role that happens to
|
|
196
|
+
* be assigned the same model must not capture the child's fallback routing.
|
|
197
|
+
*/
|
|
198
|
+
function resolveSubagentInheritedRetryFallbackChain(
|
|
187
199
|
settings: Settings,
|
|
188
200
|
modelRegistry: ModelRegistry,
|
|
201
|
+
modelPatterns: string[],
|
|
189
202
|
): string[] | undefined {
|
|
190
|
-
const
|
|
203
|
+
const configuredChains = settings.get("retry.fallbackChains");
|
|
204
|
+
const role = resolveExplicitModelRole(modelPatterns, settings);
|
|
205
|
+
// An explicitly emptied role chain means "no fallbacks", not "inherit
|
|
206
|
+
// default" — mirrors expandDefaultRetryFallbackChains.
|
|
207
|
+
const fallbackChain = (role !== undefined ? configuredChains?.[role] : undefined) ?? configuredChains?.default;
|
|
191
208
|
if (
|
|
192
209
|
!Array.isArray(fallbackChain) ||
|
|
193
210
|
fallbackChain.length === 0 ||
|
|
@@ -206,11 +223,11 @@ function installSubagentRetryFallbackChain(args: {
|
|
|
206
223
|
settings: Settings;
|
|
207
224
|
id: string;
|
|
208
225
|
candidates: SubagentRetryFallbackCandidate[];
|
|
209
|
-
|
|
226
|
+
inheritedFallbackChain: string[] | undefined;
|
|
210
227
|
model: Model<Api> | undefined;
|
|
211
228
|
authFallbackUsed: boolean;
|
|
212
229
|
}): string | undefined {
|
|
213
|
-
const { settings, id, candidates,
|
|
230
|
+
const { settings, id, candidates, inheritedFallbackChain, model, authFallbackUsed } = args;
|
|
214
231
|
if (!model || authFallbackUsed || candidates.length === 0) return undefined;
|
|
215
232
|
|
|
216
233
|
const selectedIndex = candidates.findIndex(
|
|
@@ -219,8 +236,8 @@ function installSubagentRetryFallbackChain(args: {
|
|
|
219
236
|
if (selectedIndex < 0) return undefined;
|
|
220
237
|
const fallbackSelectors = candidates.slice(selectedIndex + 1).map(candidate => candidate.selector);
|
|
221
238
|
const existingFallbackChains = settings.get("retry.fallbackChains");
|
|
222
|
-
// A single
|
|
223
|
-
const fallbackChain = fallbackSelectors.length > 0 ? fallbackSelectors :
|
|
239
|
+
// A single configured model may reuse its role's (or the default) configured chain, but never an implicit parent fallback.
|
|
240
|
+
const fallbackChain = fallbackSelectors.length > 0 ? fallbackSelectors : inheritedFallbackChain;
|
|
224
241
|
if (
|
|
225
242
|
!Array.isArray(fallbackChain) ||
|
|
226
243
|
fallbackChain.length === 0 ||
|
|
@@ -344,6 +361,8 @@ export interface ExecutorOptions {
|
|
|
344
361
|
*/
|
|
345
362
|
detached?: boolean;
|
|
346
363
|
modelOverride?: string | string[];
|
|
364
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
365
|
+
modelRole?: string;
|
|
347
366
|
/**
|
|
348
367
|
* Active model selector of the parent session, used as an auth-aware fallback
|
|
349
368
|
* if the resolved subagent model has no working credentials. See #985.
|
|
@@ -890,6 +909,8 @@ interface RunMonitorArgs {
|
|
|
890
909
|
/** Parent settings for tiny-model label generation. */
|
|
891
910
|
settings?: Settings;
|
|
892
911
|
modelOverride?: string | string[];
|
|
912
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
913
|
+
modelRole?: string;
|
|
893
914
|
signal?: AbortSignal;
|
|
894
915
|
onProgress?: (progress: AgentProgress) => void;
|
|
895
916
|
eventBus?: EventBus;
|
|
@@ -1005,6 +1026,7 @@ function createSubagentRunMonitor(args: RunMonitorArgs): SubagentRunMonitor {
|
|
|
1005
1026
|
cost: 0,
|
|
1006
1027
|
durationMs: 0,
|
|
1007
1028
|
modelOverride: args.modelOverride,
|
|
1029
|
+
modelRole: args.modelRole,
|
|
1008
1030
|
};
|
|
1009
1031
|
|
|
1010
1032
|
const outputChunks: string[] = [];
|
|
@@ -2055,6 +2077,8 @@ interface FinalizeRunArgs {
|
|
|
2055
2077
|
task: string;
|
|
2056
2078
|
assignment?: string;
|
|
2057
2079
|
modelOverride?: string | string[];
|
|
2080
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
2081
|
+
modelRole?: string;
|
|
2058
2082
|
outputSchema?: unknown;
|
|
2059
2083
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
2060
2084
|
outputSchemaSource?: StructuredSubagentSchemaSource;
|
|
@@ -2074,7 +2098,7 @@ interface FinalizeRunArgs {
|
|
|
2074
2098
|
* event.
|
|
2075
2099
|
*/
|
|
2076
2100
|
async function finalizeRunResult(args: FinalizeRunArgs): Promise<SingleResult> {
|
|
2077
|
-
const { monitor, done, index, id, agent, task, assignment, signal, modelOverride } = args;
|
|
2101
|
+
const { monitor, done, index, id, agent, task, assignment, signal, modelOverride, modelRole } = args;
|
|
2078
2102
|
const progress = monitor.progress;
|
|
2079
2103
|
let exitCode = done.exitCode;
|
|
2080
2104
|
let stderr = done.error ?? "";
|
|
@@ -2201,6 +2225,7 @@ async function finalizeRunResult(args: FinalizeRunArgs): Promise<SingleResult> {
|
|
|
2201
2225
|
contextTokens: progress.contextTokens,
|
|
2202
2226
|
contextWindow: progress.contextWindow,
|
|
2203
2227
|
modelOverride,
|
|
2228
|
+
modelRole,
|
|
2204
2229
|
resolvedModel: progress.resolvedModel,
|
|
2205
2230
|
resolvedModelIsFallback: progress.resolvedModelIsFallback,
|
|
2206
2231
|
error: exitCode !== 0 && stderr ? stderr : undefined,
|
|
@@ -2222,6 +2247,8 @@ export interface IrcWakeTurnMonitorOptions {
|
|
|
2222
2247
|
agent: AgentDefinition;
|
|
2223
2248
|
description?: string;
|
|
2224
2249
|
modelOverride?: string | string[];
|
|
2250
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
2251
|
+
modelRole?: string;
|
|
2225
2252
|
eventBus?: EventBus;
|
|
2226
2253
|
parentToolCallId?: string;
|
|
2227
2254
|
/** Fallback session file when the registry ref carries none. */
|
|
@@ -2266,6 +2293,7 @@ export function attachIrcWakeTurnMonitor(session: AgentSession, options: IrcWake
|
|
|
2266
2293
|
task: ircTask,
|
|
2267
2294
|
description: options.description,
|
|
2268
2295
|
modelOverride: options.modelOverride,
|
|
2296
|
+
modelRole: options.modelRole,
|
|
2269
2297
|
eventBus: options.eventBus,
|
|
2270
2298
|
parentToolCallId: options.parentToolCallId,
|
|
2271
2299
|
detached: true,
|
|
@@ -2323,6 +2351,7 @@ export function attachIrcWakeTurnMonitor(session: AgentSession, options: IrcWake
|
|
|
2323
2351
|
agent,
|
|
2324
2352
|
task: ircTask,
|
|
2325
2353
|
modelOverride: options.modelOverride,
|
|
2354
|
+
modelRole: options.modelRole,
|
|
2326
2355
|
outputSchema: options.outputSchema,
|
|
2327
2356
|
outputSchemaMode: options.outputSchemaMode,
|
|
2328
2357
|
outputSchemaSource: options.outputSchemaSource,
|
|
@@ -2391,14 +2420,20 @@ export async function finalizeSubagentLifecycle(args: {
|
|
|
2391
2420
|
args.abortKind === "budget" && args.keepAlive && !args.isolated && args.reviveSession !== null;
|
|
2392
2421
|
if (args.aborted && !resumableAbort) {
|
|
2393
2422
|
if (ref && ownsRef) {
|
|
2394
|
-
//
|
|
2395
|
-
//
|
|
2396
|
-
//
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2423
|
+
// Route hard kills through the lifecycle owner so the terminal
|
|
2424
|
+
// decision is durable and a restart cannot rediscover the transcript
|
|
2425
|
+
// as a revivable parked agent.
|
|
2426
|
+
try {
|
|
2427
|
+
await AgentLifecycleManager.global().release(args.id, ref, { tombstone: true });
|
|
2428
|
+
} catch (error) {
|
|
2429
|
+
logger.warn("runSubagent: failed to persist kill tombstone", { id: args.id, error: String(error) });
|
|
2430
|
+
registry.setStatus(args.id, "aborted", ref);
|
|
2431
|
+
registry.detachSession(args.id, ref);
|
|
2432
|
+
await disposeSession();
|
|
2433
|
+
}
|
|
2434
|
+
} else {
|
|
2435
|
+
await disposeSession();
|
|
2400
2436
|
}
|
|
2401
|
-
await disposeSession();
|
|
2402
2437
|
return;
|
|
2403
2438
|
}
|
|
2404
2439
|
|
|
@@ -2447,6 +2482,8 @@ export interface FollowUpTurnOptions {
|
|
|
2447
2482
|
message: string;
|
|
2448
2483
|
index?: number;
|
|
2449
2484
|
description?: string;
|
|
2485
|
+
/** Explicit pre-expansion model role alias retained from the original run. */
|
|
2486
|
+
modelRole?: string;
|
|
2450
2487
|
/** Structured-output state retained from the original invocation. */
|
|
2451
2488
|
outputSchema?: unknown;
|
|
2452
2489
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
@@ -2486,6 +2523,7 @@ export async function runSubagentFollowUpTurn(options: FollowUpTurnOptions): Pro
|
|
|
2486
2523
|
agent,
|
|
2487
2524
|
task: message,
|
|
2488
2525
|
description: options.description,
|
|
2526
|
+
modelRole: options.modelRole,
|
|
2489
2527
|
signal,
|
|
2490
2528
|
onProgress: options.onProgress,
|
|
2491
2529
|
eventBus: options.eventBus,
|
|
@@ -2535,6 +2573,7 @@ export async function runSubagentFollowUpTurn(options: FollowUpTurnOptions): Pro
|
|
|
2535
2573
|
id,
|
|
2536
2574
|
agent,
|
|
2537
2575
|
task: message,
|
|
2576
|
+
modelRole: options.modelRole,
|
|
2538
2577
|
outputSchema: options.outputSchema,
|
|
2539
2578
|
outputSchemaMode: options.outputSchemaMode,
|
|
2540
2579
|
outputSchemaSource: options.outputSchemaSource,
|
|
@@ -2561,6 +2600,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2561
2600
|
id,
|
|
2562
2601
|
worktree,
|
|
2563
2602
|
modelOverride,
|
|
2603
|
+
modelRole,
|
|
2564
2604
|
thinkingLevel,
|
|
2565
2605
|
outputSchema,
|
|
2566
2606
|
enableLsp,
|
|
@@ -2590,6 +2630,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2590
2630
|
tokens: 0,
|
|
2591
2631
|
requests: 0,
|
|
2592
2632
|
modelOverride,
|
|
2633
|
+
modelRole,
|
|
2593
2634
|
error: "Cancelled before start",
|
|
2594
2635
|
aborted: true,
|
|
2595
2636
|
abortReason: "Cancelled before start",
|
|
@@ -2680,6 +2721,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2680
2721
|
modelRegistry: options.modelRegistry,
|
|
2681
2722
|
settings,
|
|
2682
2723
|
modelOverride,
|
|
2724
|
+
modelRole,
|
|
2683
2725
|
signal,
|
|
2684
2726
|
onProgress,
|
|
2685
2727
|
eventBus: options.eventBus,
|
|
@@ -2713,6 +2755,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2713
2755
|
agent,
|
|
2714
2756
|
description: options.description,
|
|
2715
2757
|
modelOverride,
|
|
2758
|
+
modelRole,
|
|
2716
2759
|
eventBus: options.eventBus,
|
|
2717
2760
|
parentToolCallId: options.parentToolCallId,
|
|
2718
2761
|
sessionFile: subtaskSessionFile,
|
|
@@ -2790,9 +2833,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2790
2833
|
checkAbort();
|
|
2791
2834
|
|
|
2792
2835
|
const configuredModelPatterns = resolveConfiguredModelPatterns(modelPatterns, settings);
|
|
2793
|
-
const
|
|
2836
|
+
const inheritedRetryFallbackChain =
|
|
2794
2837
|
configuredModelPatterns.length === 1
|
|
2795
|
-
?
|
|
2838
|
+
? resolveSubagentInheritedRetryFallbackChain(subagentSettings, modelRegistry, modelPatterns)
|
|
2796
2839
|
: undefined;
|
|
2797
2840
|
const {
|
|
2798
2841
|
model,
|
|
@@ -2827,7 +2870,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2827
2870
|
settings: subagentSettings,
|
|
2828
2871
|
id,
|
|
2829
2872
|
candidates: resolveSubagentRetryFallbackCandidates(modelPatterns, modelRegistry, subagentSettings),
|
|
2830
|
-
|
|
2873
|
+
inheritedFallbackChain: inheritedRetryFallbackChain,
|
|
2831
2874
|
model,
|
|
2832
2875
|
authFallbackUsed,
|
|
2833
2876
|
});
|
|
@@ -2970,7 +3013,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2970
3013
|
modelPatternFallbackRole:
|
|
2971
3014
|
model || modelOverride === undefined ? undefined : `${SUBAGENT_RETRY_FALLBACK_ROLE_PREFIX}${id}`,
|
|
2972
3015
|
modelPatternDefaultFallbackChain:
|
|
2973
|
-
model || modelOverride === undefined ? undefined :
|
|
3016
|
+
model || modelOverride === undefined ? undefined : inheritedRetryFallbackChain,
|
|
2974
3017
|
thinkingLevel: effectiveThinkingLevel,
|
|
2975
3018
|
thinkingLevelCeiling: spawnEffortCeiling,
|
|
2976
3019
|
toolNames,
|
|
@@ -3098,6 +3141,10 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3098
3141
|
systemPrompt: session.agent.state.systemPrompt.join("\n\n"),
|
|
3099
3142
|
task,
|
|
3100
3143
|
tools: session.getActiveToolNames(),
|
|
3144
|
+
agent: agent.name,
|
|
3145
|
+
modelRole: modelRole ?? resolveExplicitModelRole(modelOverride ?? agent.model, subagentSettings),
|
|
3146
|
+
resolvedModel: progress.resolvedModel,
|
|
3147
|
+
readOnly: isReadOnlyAgent(agent),
|
|
3101
3148
|
spawns: spawnsEnv,
|
|
3102
3149
|
readSummarize: agent.readSummarize,
|
|
3103
3150
|
outputSchema,
|
|
@@ -3147,7 +3194,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3147
3194
|
session.sessionManager.appendLabelChange(targetId, label);
|
|
3148
3195
|
},
|
|
3149
3196
|
getActiveTools: () => session.getEnabledToolNames(),
|
|
3150
|
-
getAllTools: () => session.
|
|
3197
|
+
getAllTools: () => session.getAllToolInfos(),
|
|
3151
3198
|
setActiveTools: (toolNames: string[]) =>
|
|
3152
3199
|
session.setActiveToolsByName(toolNames.filter(name => !isParentOwnedTool(name))),
|
|
3153
3200
|
getCommands: () => getSessionSlashCommands(session),
|
|
@@ -3358,7 +3405,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3358
3405
|
const done = await runSubagent();
|
|
3359
3406
|
monitor.finish();
|
|
3360
3407
|
|
|
3361
|
-
|
|
3408
|
+
const result = await finalizeRunResult({
|
|
3362
3409
|
monitor,
|
|
3363
3410
|
done,
|
|
3364
3411
|
index,
|
|
@@ -3367,6 +3414,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3367
3414
|
task,
|
|
3368
3415
|
assignment,
|
|
3369
3416
|
modelOverride,
|
|
3417
|
+
modelRole,
|
|
3370
3418
|
outputSchema,
|
|
3371
3419
|
outputSchemaMode: options.outputSchemaMode,
|
|
3372
3420
|
outputSchemaSource: options.outputSchemaSource,
|
|
@@ -3378,4 +3426,6 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3378
3426
|
sessionFile: subtaskSessionFile,
|
|
3379
3427
|
startTime,
|
|
3380
3428
|
});
|
|
3429
|
+
AgentRegistry.global().setHistory(id, { outputPath: result.outputPath });
|
|
3430
|
+
return result;
|
|
3381
3431
|
}
|
package/src/task/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { TASK_EFFORTS, type TaskEffort } from "../thinking";
|
|
|
27
27
|
import { truncateForPrompt } from "../tools/approval";
|
|
28
28
|
import { isIrcEnabled } from "../tools/hub";
|
|
29
29
|
import { formatBytes, formatDuration } from "../tools/render-utils";
|
|
30
|
+
import { isReadOnlyAgent } from "./read-only-policy";
|
|
30
31
|
import { isScoutSpawnable, resolveSpawnPolicy } from "./spawn-policy";
|
|
31
32
|
import {
|
|
32
33
|
type AgentDefinition,
|
|
@@ -102,6 +103,7 @@ export { loadBundledAgents as BUNDLED_AGENTS } from "./agents";
|
|
|
102
103
|
export { discoverCommands, expandCommand, getCommand } from "./commands";
|
|
103
104
|
export { discoverAgents, getAgent } from "./discovery";
|
|
104
105
|
export { AgentOutputManager } from "./output-manager";
|
|
106
|
+
export * from "./read-only-policy";
|
|
105
107
|
export type {
|
|
106
108
|
AgentDefinition,
|
|
107
109
|
AgentProgress,
|
|
@@ -119,32 +121,6 @@ export {
|
|
|
119
121
|
taskSchema,
|
|
120
122
|
} from "./types";
|
|
121
123
|
|
|
122
|
-
// Built-in tools whose approval tier is "read" (see tool classes' `approval`).
|
|
123
|
-
// An agent is read-only iff its declared tools are a non-empty subset of this set.
|
|
124
|
-
// Fail-safe: any unknown tool makes the agent not read-only.
|
|
125
|
-
export const READ_ONLY_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
126
|
-
"read",
|
|
127
|
-
"grep",
|
|
128
|
-
"glob",
|
|
129
|
-
"web_search",
|
|
130
|
-
"ast_grep",
|
|
131
|
-
"yield",
|
|
132
|
-
"hub",
|
|
133
|
-
"ask",
|
|
134
|
-
"todo",
|
|
135
|
-
"recall",
|
|
136
|
-
"reflect",
|
|
137
|
-
"retain",
|
|
138
|
-
"memory_edit",
|
|
139
|
-
"inspect_image",
|
|
140
|
-
"checkpoint",
|
|
141
|
-
"rewind",
|
|
142
|
-
]);
|
|
143
|
-
|
|
144
|
-
export function isReadOnlyAgent(agent: AgentDefinition): boolean {
|
|
145
|
-
return !!agent.tools?.length && agent.tools.every(tool => READ_ONLY_TOOL_NAMES.has(tool));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
124
|
/**
|
|
149
125
|
* Preview text for a child result. Falls back to "(no output)" — annotated
|
|
150
126
|
* with the request count when the child actually did work, so the parent can
|
|
@@ -465,16 +441,19 @@ export function composeSpawnAdvisory(args: {
|
|
|
465
441
|
class TaskJobError extends Error {}
|
|
466
442
|
|
|
467
443
|
/**
|
|
468
|
-
* Process-level
|
|
444
|
+
* Process-level create-time discovery memo and published reload snapshots,
|
|
445
|
+
* keyed by resolved cwd.
|
|
469
446
|
*
|
|
470
447
|
* `TaskTool.create` runs for every (sub)agent session in this process and the
|
|
471
448
|
* walk-up + plugin-registry scan in `discoverAgents` is identical for a given
|
|
472
|
-
* cwd, so repeat creations reuse the first scan.
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
449
|
+
* cwd, so repeat creations reuse the first scan. Explicit plugin reloads
|
|
450
|
+
* replace the matching snapshot so already-created tools advertise the latest
|
|
451
|
+
* definitions. Execution-time discovery (`#runSpawn`) intentionally stays
|
|
452
|
+
* fresh. The memo also tracks the live `discoverAgents` binding: test spies
|
|
453
|
+
* swap that binding, which invalidates both caches automatically.
|
|
476
454
|
*/
|
|
477
455
|
const discoveryMemo = new Map<string, Promise<DiscoveryResult>>();
|
|
456
|
+
const discoverySnapshots = new Map<string, AgentDefinition[]>();
|
|
478
457
|
let discoveryMemoFn: typeof discoverAgents | undefined;
|
|
479
458
|
|
|
480
459
|
function discoverAgentsForCreate(cwd: string): Promise<DiscoveryResult> {
|
|
@@ -482,6 +461,7 @@ function discoverAgentsForCreate(cwd: string): Promise<DiscoveryResult> {
|
|
|
482
461
|
if (discoveryMemoFn !== fn) {
|
|
483
462
|
discoveryMemoFn = fn;
|
|
484
463
|
discoveryMemo.clear();
|
|
464
|
+
discoverySnapshots.clear();
|
|
485
465
|
}
|
|
486
466
|
const key = path.resolve(cwd);
|
|
487
467
|
let pending = discoveryMemo.get(key);
|
|
@@ -495,6 +475,17 @@ function discoverAgentsForCreate(cwd: string): Promise<DiscoveryResult> {
|
|
|
495
475
|
return pending;
|
|
496
476
|
}
|
|
497
477
|
|
|
478
|
+
/** Rescan one cwd and publish its definitions to existing and future task tools. */
|
|
479
|
+
export async function refreshAgentDiscovery(cwd: string): Promise<void> {
|
|
480
|
+
const key = path.resolve(cwd);
|
|
481
|
+
discoveryMemo.delete(key);
|
|
482
|
+
const pending = discoverAgentsForCreate(cwd);
|
|
483
|
+
const { agents } = await pending;
|
|
484
|
+
if (discoveryMemo.get(key) === pending) {
|
|
485
|
+
discoverySnapshots.set(key, agents);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
498
489
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
499
490
|
// Tool Class
|
|
500
491
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -611,7 +602,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
611
602
|
const planMode = this.session.getPlanModeState?.()?.enabled === true;
|
|
612
603
|
const isolationMode = this.session.settings.get("task.isolation.mode");
|
|
613
604
|
return renderDescription({
|
|
614
|
-
agents: this.#discoveredAgents,
|
|
605
|
+
agents: discoverySnapshots.get(path.resolve(this.session.cwd)) ?? this.#discoveredAgents,
|
|
615
606
|
isolationEnabled: !planMode && isolationMode !== "none",
|
|
616
607
|
applyIsolatedChanges: this.session.settings.get("task.isolation.apply"),
|
|
617
608
|
disabledAgents,
|
|
@@ -860,6 +851,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
860
851
|
id: agentId,
|
|
861
852
|
agent: agentType,
|
|
862
853
|
agentSource,
|
|
854
|
+
modelRole: policy.modelRole,
|
|
863
855
|
status: "pending",
|
|
864
856
|
task: renderSubagentUserPrompt(assignment),
|
|
865
857
|
assignment,
|
|
@@ -1143,8 +1135,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1143
1135
|
// polling row reflects the resolved model, reasoning level,
|
|
1144
1136
|
// and running counters without reverting the "running"
|
|
1145
1137
|
// status back to the subagent's initial "pending" snapshot.
|
|
1138
|
+
progress.modelRole = nextProgress.modelRole ?? progress.modelRole;
|
|
1146
1139
|
progress.resolvedModel = nextProgress.resolvedModel;
|
|
1147
|
-
progress.resolvedModelIsFallback =
|
|
1140
|
+
progress.resolvedModelIsFallback =
|
|
1141
|
+
nextProgress.resolvedModelIsFallback ?? progress.resolvedModelIsFallback;
|
|
1148
1142
|
progress.tokens = nextProgress.tokens;
|
|
1149
1143
|
progress.requests = nextProgress.requests;
|
|
1150
1144
|
progress.contextTokens = nextProgress.contextTokens;
|
|
@@ -1187,9 +1181,11 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1187
1181
|
progress.extractedToolData = singleResult?.extractedToolData;
|
|
1188
1182
|
progress.retryFailure = singleResult?.retryFailure;
|
|
1189
1183
|
progress.retryState = undefined;
|
|
1184
|
+
progress.modelRole = singleResult?.modelRole ?? progress.modelRole;
|
|
1190
1185
|
if (singleResult?.resolvedModel) {
|
|
1191
1186
|
progress.resolvedModel = singleResult.resolvedModel;
|
|
1192
|
-
progress.resolvedModelIsFallback =
|
|
1187
|
+
progress.resolvedModelIsFallback =
|
|
1188
|
+
singleResult.resolvedModelIsFallback ?? progress.resolvedModelIsFallback;
|
|
1193
1189
|
} else {
|
|
1194
1190
|
delete progress.resolvedModel;
|
|
1195
1191
|
delete progress.resolvedModelIsFallback;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import * as path from "node:path";
|
|
22
22
|
import type * as natives from "@oh-my-pi/pi-natives";
|
|
23
|
+
import { AgentRegistry } from "../registry/agent-registry";
|
|
23
24
|
import type { ToolSession } from "../tools";
|
|
24
25
|
import { generateCommitMessage } from "../utils/commit-message-generator";
|
|
25
26
|
import * as git from "../utils/git";
|
|
@@ -44,6 +45,15 @@ import {
|
|
|
44
45
|
|
|
45
46
|
type IsoBackendKind = natives.IsoBackendKind;
|
|
46
47
|
|
|
48
|
+
function rememberAgentArtifacts(result: SingleResult): SingleResult {
|
|
49
|
+
AgentRegistry.global().setHistory(result.id, {
|
|
50
|
+
outputPath: result.outputPath,
|
|
51
|
+
patchPath: result.patchPath,
|
|
52
|
+
branchName: result.branchName,
|
|
53
|
+
});
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
/** Resolved repo + baseline used by every isolated spawn in a single call. */
|
|
48
58
|
export interface IsolationContext {
|
|
49
59
|
repoRoot: string;
|
|
@@ -172,14 +182,14 @@ export async function runIsolatedSubprocess(opts: IsolatedRunOptions): Promise<S
|
|
|
172
182
|
opts.description,
|
|
173
183
|
opts.buildCommitMessage?.(),
|
|
174
184
|
);
|
|
175
|
-
return {
|
|
185
|
+
return rememberAgentArtifacts({
|
|
176
186
|
...result,
|
|
177
187
|
branchName: commitResult?.branchName,
|
|
178
188
|
branchBaseSha: commitResult?.baseSha,
|
|
179
189
|
nestedPatches: commitResult?.nestedPatches,
|
|
180
|
-
};
|
|
190
|
+
});
|
|
181
191
|
} catch (mergeErr) {
|
|
182
|
-
// Agent succeeded but branch commit failed — clean up stale branch
|
|
192
|
+
// Agent succeeded but branch commit failed — clean up stale branch.
|
|
183
193
|
const branchName = `omp/task/${opts.agentId}`;
|
|
184
194
|
await git.branch.tryDelete(opts.context.repoRoot, branchName);
|
|
185
195
|
const msg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
@@ -190,34 +200,37 @@ export async function runIsolatedSubprocess(opts: IsolatedRunOptions): Promise<S
|
|
|
190
200
|
opts.artifactsDir,
|
|
191
201
|
opts.agentId,
|
|
192
202
|
);
|
|
193
|
-
return {
|
|
203
|
+
return rememberAgentArtifacts({
|
|
194
204
|
...result,
|
|
195
205
|
patchPath: patchResult.patchPath,
|
|
196
206
|
nestedPatches: patchResult.nestedPatches,
|
|
197
207
|
error: `Merge failed: ${msg}`,
|
|
198
|
-
};
|
|
208
|
+
});
|
|
199
209
|
} catch (patchErr) {
|
|
200
210
|
const patchMsg = patchErr instanceof Error ? patchErr.message : String(patchErr);
|
|
201
|
-
return {
|
|
211
|
+
return rememberAgentArtifacts({
|
|
212
|
+
...result,
|
|
213
|
+
error: `Merge failed: ${msg}; patch capture failed: ${patchMsg}`,
|
|
214
|
+
});
|
|
202
215
|
}
|
|
203
216
|
}
|
|
204
217
|
}
|
|
205
218
|
if (result.exitCode === 0) {
|
|
206
219
|
try {
|
|
207
220
|
const patchResult = await writeIsolationPatch(isolationDir, taskBaseline, opts.artifactsDir, opts.agentId);
|
|
208
|
-
return {
|
|
221
|
+
return rememberAgentArtifacts({
|
|
209
222
|
...result,
|
|
210
223
|
patchPath: patchResult.patchPath,
|
|
211
224
|
nestedPatches: patchResult.nestedPatches,
|
|
212
|
-
};
|
|
225
|
+
});
|
|
213
226
|
} catch (patchErr) {
|
|
214
227
|
const msg = patchErr instanceof Error ? patchErr.message : String(patchErr);
|
|
215
|
-
return { ...result, error: `Patch capture failed: ${msg}` };
|
|
228
|
+
return rememberAgentArtifacts({ ...result, error: `Patch capture failed: ${msg}` });
|
|
216
229
|
}
|
|
217
230
|
}
|
|
218
|
-
return result;
|
|
231
|
+
return rememberAgentArtifacts(result);
|
|
219
232
|
} catch (err) {
|
|
220
|
-
return opts.buildFailureResult(err);
|
|
233
|
+
return rememberAgentArtifacts(opts.buildFailureResult(err));
|
|
221
234
|
} finally {
|
|
222
235
|
if (handle) {
|
|
223
236
|
const isolationHandle = handle;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
|
-
|
|
3
2
|
import type { ModelRegistry } from "../config/model-registry";
|
|
3
|
+
import { formatModelRoleAlias } from "../config/model-roles";
|
|
4
4
|
import type { Settings } from "../config/settings";
|
|
5
5
|
import { MCPManager } from "../mcp/manager";
|
|
6
6
|
import type { PersistedSubagentReviverFactory } from "../registry/agent-lifecycle";
|
|
@@ -79,6 +79,14 @@ export function createPersistedSubagentReviverFactory(
|
|
|
79
79
|
taskDepth++;
|
|
80
80
|
parentId = registry.get(parentId)?.parentId;
|
|
81
81
|
}
|
|
82
|
+
const subagentSettings = createSubagentSettings(
|
|
83
|
+
ctx.settings,
|
|
84
|
+
init.readSummarize === false ? { "read.summarize.enabled": false } : undefined,
|
|
85
|
+
);
|
|
86
|
+
const persistedModelPattern =
|
|
87
|
+
init.modelRole && init.modelRole !== "default"
|
|
88
|
+
? [formatModelRoleAlias(init.modelRole), ...(init.resolvedModel ? [init.resolvedModel] : [])]
|
|
89
|
+
: init.resolvedModel;
|
|
82
90
|
return async expectedRef => {
|
|
83
91
|
// Re-open fresh on every revive: park closes the writer, so this takes
|
|
84
92
|
// the single-writer lock cleanly and restores the full message history.
|
|
@@ -96,10 +104,9 @@ export function createPersistedSubagentReviverFactory(
|
|
|
96
104
|
cwd: ctx.session.sessionManager.getCwd(),
|
|
97
105
|
authStorage: ctx.authStorage,
|
|
98
106
|
modelRegistry: ctx.modelRegistry,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
),
|
|
107
|
+
...(persistedModelPattern ? { modelPattern: persistedModelPattern } : {}),
|
|
108
|
+
modelPatternAuthFallback: init.resolvedModel,
|
|
109
|
+
settings: subagentSettings,
|
|
103
110
|
sessionManager: reopened,
|
|
104
111
|
agentId: ref.id,
|
|
105
112
|
agentDisplayName: ref.displayName,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AgentDefinition } from "./types";
|
|
2
|
+
|
|
3
|
+
// Built-in tools whose approval tier is "read" (see tool classes' `approval`).
|
|
4
|
+
// An agent is read-only iff its declared tools are a non-empty subset of this set.
|
|
5
|
+
// Fail-safe: any unknown tool makes the agent not read-only.
|
|
6
|
+
export const READ_ONLY_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
7
|
+
"read",
|
|
8
|
+
"grep",
|
|
9
|
+
"glob",
|
|
10
|
+
"web_search",
|
|
11
|
+
"ast_grep",
|
|
12
|
+
"yield",
|
|
13
|
+
"hub",
|
|
14
|
+
"ask",
|
|
15
|
+
"todo",
|
|
16
|
+
"recall",
|
|
17
|
+
"reflect",
|
|
18
|
+
"retain",
|
|
19
|
+
"memory_edit",
|
|
20
|
+
"inspect_image",
|
|
21
|
+
"checkpoint",
|
|
22
|
+
"rewind",
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
export function isReadOnlyAgent(agent: AgentDefinition): boolean {
|
|
26
|
+
return !!agent.tools?.length && agent.tools.every(tool => READ_ONLY_TOOL_NAMES.has(tool));
|
|
27
|
+
}
|