@oh-my-pi/pi-coding-agent 17.2.8 → 17.2.10
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 +94 -1
- package/dist/{CHANGELOG-0b0w17se.md → CHANGELOG-rhwzpexa.md} +94 -1
- package/dist/cli.js +13216 -15614
- package/dist/types/async/job-manager.d.ts +12 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +13 -0
- package/dist/types/discovery/agents.d.ts +11 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +5 -5
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/loader.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -8
- package/dist/types/extensibility/hooks/types.d.ts +5 -5
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +10 -0
- package/dist/types/hindsight/state.d.ts +0 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/lsp/utils.d.ts +8 -0
- package/dist/types/main.d.ts +1 -1
- 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 +12 -5
- package/dist/types/modes/components/model-browser.d.ts +9 -1
- package/dist/types/modes/interactive-mode.d.ts +8 -1
- package/dist/types/modes/session-observer-registry.d.ts +2 -0
- package/dist/types/registry/agent-lifecycle.d.ts +1 -1
- package/dist/types/registry/agent-registry.d.ts +47 -0
- package/dist/types/registry/persisted-agents.d.ts +3 -1
- package/dist/types/session/agent-session-types.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +8 -4
- 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 +10 -1
- package/dist/types/session/turn-recovery.d.ts +6 -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 +10 -0
- package/dist/types/task/index.d.ts +2 -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 +3 -0
- package/dist/types/tools/browser/tab-worker.d.ts +2 -2
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/read.d.ts +3 -5
- package/dist/types/tools/run-scope.d.ts +27 -1
- package/dist/types/tools/shell-tokenize.d.ts +21 -3
- package/dist/types/tools/terminal-output.d.ts +1 -1
- package/dist/types/utils/changelog.d.ts +3 -2
- package/dist/types/utils/late-cleanup.d.ts +2 -0
- package/dist/types/utils/turndown.d.ts +1 -1
- package/dist/types/vibe/runtime.d.ts +4 -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/omp +11 -2
- package/src/advisor/runtime.ts +54 -0
- package/src/async/job-manager.ts +26 -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/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/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 +4 -4
- package/src/cli/tiny-models-cli.ts +1 -1
- package/src/cli/ttsr-cli.ts +1 -1
- package/src/cli/update-cli.ts +3 -57
- 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/commands/say.ts +1 -1
- package/src/commands/token.ts +1 -1
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/cli.ts +1 -1
- package/src/config/config-file.ts +2 -2
- package/src/config/keybindings.ts +3 -3
- package/src/config/model-discovery.ts +36 -2
- package/src/config/model-registry.ts +4 -1
- package/src/config/model-resolver.ts +54 -7
- package/src/discovery/agents.ts +73 -3
- 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.ts +8 -5
- package/src/discovery/cursor.ts +8 -5
- package/src/discovery/gemini.ts +11 -8
- package/src/discovery/vscode.ts +1 -0
- package/src/discovery/windsurf.ts +4 -2
- package/src/edit/hashline/filesystem.ts +7 -7
- package/src/eval/agent-bridge.ts +1 -3
- package/src/eval/jl/prelude.jl +4 -4
- package/src/eval/js/shared/prelude.txt +2 -2
- package/src/eval/py/prelude.py +0 -3
- package/src/eval/py/runner.py +38 -1
- package/src/eval/rb/prelude.rb +1 -2
- 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 +1 -1
- package/src/extensibility/extensions/loader.ts +7 -6
- package/src/extensibility/extensions/types.ts +39 -8
- package/src/extensibility/hooks/loader.ts +4 -5
- package/src/extensibility/hooks/types.ts +5 -5
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +23 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +53 -0
- package/src/hindsight/state.ts +2 -22
- package/src/index.ts +2 -2
- package/src/internal-urls/memory-protocol.ts +33 -0
- package/src/launch/terminal-output.ts +1 -1
- package/src/lsp/client.ts +2 -2
- package/src/lsp/utils.ts +29 -0
- package/src/main.ts +85 -21
- 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/modes/acp/acp-agent.ts +7 -6
- 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-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +670 -192
- package/src/modes/components/agent-transcript-viewer.ts +1 -3
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/bordered-loader.ts +1 -1
- package/src/modes/components/custom-editor.ts +2 -2
- package/src/modes/components/extensions/inspector-panel.ts +11 -6
- package/src/modes/components/footer.ts +1 -3
- package/src/modes/components/hook-input.ts +1 -1
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/model-browser.ts +11 -3
- package/src/modes/components/model-hub.ts +4 -1
- package/src/modes/components/session-selector.ts +2 -2
- package/src/modes/components/status-line/segments.ts +4 -3
- package/src/modes/controllers/event-controller.ts +188 -7
- package/src/modes/controllers/extension-ui-controller.ts +4 -3
- package/src/modes/controllers/mcp-command-controller.ts +81 -20
- package/src/modes/controllers/selector-controller.ts +40 -49
- package/src/modes/controllers/streaming-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/print-mode.ts +29 -12
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/session-observer-registry.ts +5 -0
- package/src/modes/theme/theme.ts +2 -2
- package/src/prompts/tools/computer.md +1 -1
- package/src/registry/agent-lifecycle.ts +35 -10
- package/src/registry/agent-registry.ts +65 -2
- package/src/registry/persisted-agents.ts +341 -16
- package/src/sdk.ts +11 -5
- package/src/session/agent-session-types.ts +8 -0
- package/src/session/agent-session.ts +177 -188
- package/src/session/session-entries.ts +10 -0
- 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 +105 -110
- package/src/session/session-tools.ts +28 -1
- package/src/session/settings-stream-fn.ts +7 -3
- package/src/session/turn-recovery.ts +236 -18
- package/src/session/unexpected-stop-classifier.ts +12 -3
- package/src/slash-commands/acp-builtins.ts +1 -1
- package/src/slash-commands/available-commands.ts +1 -1
- package/src/slash-commands/helpers/stats-dashboard.ts +2 -1
- package/src/task/agents.ts +1 -1
- package/src/task/executor.ts +173 -47
- package/src/task/index.ts +9 -28
- package/src/task/isolation-runner.ts +43 -12
- package/src/task/persisted-revive.ts +12 -5
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/structured-subagent.ts +31 -6
- package/src/task/types.ts +4 -0
- package/src/tiny/worker.ts +1 -1
- package/src/tools/auto-generated-guard.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash-interceptor.ts +8 -4
- package/src/tools/bash.ts +6 -6
- package/src/tools/browser/cmux/cmux-tab.ts +66 -18
- package/src/tools/browser/launch.ts +76 -19
- 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/fetch.ts +1 -1
- package/src/tools/glob.ts +4 -2
- package/src/tools/path-utils.ts +22 -5
- package/src/tools/read.ts +22 -5
- package/src/tools/run-scope.ts +290 -4
- package/src/tools/shell-tokenize.ts +38 -9
- package/src/tools/terminal-output.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/utils/changelog.ts +5 -4
- 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/late-cleanup.ts +17 -0
- package/src/utils/turndown.ts +1 -2
- package/src/vibe/runtime.ts +202 -58
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/hackage.ts +1 -12
- 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/duckduckgo.ts +1 -1
- package/src/web/search/providers/ecosia.ts +2 -2
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/firecrawl.ts +1 -1
- package/src/web/search/providers/google.ts +1 -1
- package/src/web/search/providers/mojeek.ts +2 -2
- package/src/web/search/providers/perplexity.ts +1 -1
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/startpage.ts +2 -2
- package/src/markit/converters/mammoth.d.ts +0 -24
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";
|
|
@@ -54,10 +55,12 @@ import { normalizeSchema } from "../tools/jtd-to-json-schema";
|
|
|
54
55
|
import { buildOutputValidator, summarizeValidationFailure } from "../tools/output-schema-validator";
|
|
55
56
|
import { ToolAbortError } from "../tools/tool-errors";
|
|
56
57
|
import type { EventBus } from "../utils/event-bus";
|
|
58
|
+
import { trackLateCleanup } from "../utils/late-cleanup";
|
|
57
59
|
import { buildNamedToolChoice } from "../utils/tool-choice";
|
|
58
60
|
import type { WorkspaceTree } from "../workspace-tree";
|
|
59
61
|
import { generateTaskLabel } from "./label";
|
|
60
62
|
import { resolveAgentPrewalkDefault } from "./prewalk";
|
|
63
|
+
import { isReadOnlyAgent } from "./read-only-policy";
|
|
61
64
|
import { subprocessToolRegistry } from "./subprocess-tool-registry";
|
|
62
65
|
import {
|
|
63
66
|
type AgentDefinition,
|
|
@@ -79,6 +82,7 @@ import { arrayValuedLabels, assembleYieldResult } from "./yield-assembly";
|
|
|
79
82
|
export type { YieldItem } from "./types";
|
|
80
83
|
|
|
81
84
|
const MCP_CALL_TIMEOUT_MS = 60_000;
|
|
85
|
+
const TASK_ABORT_CLEANUP_GRACE_MS = 10_000;
|
|
82
86
|
|
|
83
87
|
/**
|
|
84
88
|
* Soft per-agent request budgets (assistant requests per run). Crossing the
|
|
@@ -166,9 +170,11 @@ function resolveSubagentRetryFallbackCandidates(
|
|
|
166
170
|
): SubagentRetryFallbackCandidate[] {
|
|
167
171
|
const candidates: SubagentRetryFallbackCandidate[] = [];
|
|
168
172
|
const seen = new Set<string>();
|
|
173
|
+
const disabledProviders = new Set(settings.get("disabledProviders"));
|
|
169
174
|
for (const pattern of modelPatterns) {
|
|
170
175
|
const resolved = resolveModelOverride([pattern], modelRegistry, settings);
|
|
171
176
|
if (!resolved.model) continue;
|
|
177
|
+
if (disabledProviders.has(resolved.model.provider)) continue;
|
|
172
178
|
const selector = resolved.explicitThinkingLevel
|
|
173
179
|
? formatModelSelectorValue(formatModelStringWithRouting(resolved.model), resolved.thinkingLevel)
|
|
174
180
|
: formatModelStringWithRouting(resolved.model);
|
|
@@ -179,8 +185,26 @@ function resolveSubagentRetryFallbackCandidates(
|
|
|
179
185
|
return candidates;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
|
|
183
|
-
|
|
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(
|
|
199
|
+
settings: Settings,
|
|
200
|
+
modelRegistry: ModelRegistry,
|
|
201
|
+
modelPatterns: string[],
|
|
202
|
+
): string[] | undefined {
|
|
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;
|
|
184
208
|
if (
|
|
185
209
|
!Array.isArray(fallbackChain) ||
|
|
186
210
|
fallbackChain.length === 0 ||
|
|
@@ -188,18 +212,22 @@ function resolveSubagentDefaultRetryFallbackChain(settings: Settings): string[]
|
|
|
188
212
|
) {
|
|
189
213
|
return undefined;
|
|
190
214
|
}
|
|
191
|
-
|
|
215
|
+
const disabledProviders = new Set(settings.get("disabledProviders"));
|
|
216
|
+
return fallbackChain.filter(entry => {
|
|
217
|
+
const resolved = resolveModelOverride([entry], modelRegistry, settings);
|
|
218
|
+
return !resolved.model || !disabledProviders.has(resolved.model.provider);
|
|
219
|
+
});
|
|
192
220
|
}
|
|
193
221
|
|
|
194
222
|
function installSubagentRetryFallbackChain(args: {
|
|
195
223
|
settings: Settings;
|
|
196
224
|
id: string;
|
|
197
225
|
candidates: SubagentRetryFallbackCandidate[];
|
|
198
|
-
|
|
226
|
+
inheritedFallbackChain: string[] | undefined;
|
|
199
227
|
model: Model<Api> | undefined;
|
|
200
228
|
authFallbackUsed: boolean;
|
|
201
229
|
}): string | undefined {
|
|
202
|
-
const { settings, id, candidates,
|
|
230
|
+
const { settings, id, candidates, inheritedFallbackChain, model, authFallbackUsed } = args;
|
|
203
231
|
if (!model || authFallbackUsed || candidates.length === 0) return undefined;
|
|
204
232
|
|
|
205
233
|
const selectedIndex = candidates.findIndex(
|
|
@@ -208,8 +236,8 @@ function installSubagentRetryFallbackChain(args: {
|
|
|
208
236
|
if (selectedIndex < 0) return undefined;
|
|
209
237
|
const fallbackSelectors = candidates.slice(selectedIndex + 1).map(candidate => candidate.selector);
|
|
210
238
|
const existingFallbackChains = settings.get("retry.fallbackChains");
|
|
211
|
-
// A single
|
|
212
|
-
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;
|
|
213
241
|
if (
|
|
214
242
|
!Array.isArray(fallbackChain) ||
|
|
215
243
|
fallbackChain.length === 0 ||
|
|
@@ -333,6 +361,8 @@ export interface ExecutorOptions {
|
|
|
333
361
|
*/
|
|
334
362
|
detached?: boolean;
|
|
335
363
|
modelOverride?: string | string[];
|
|
364
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
365
|
+
modelRole?: string;
|
|
336
366
|
/**
|
|
337
367
|
* Active model selector of the parent session, used as an auth-aware fallback
|
|
338
368
|
* if the resolved subagent model has no working credentials. See #985.
|
|
@@ -455,6 +485,8 @@ export interface ExecutorOptions {
|
|
|
455
485
|
* set this false so disposal unregisters them instead of leaving idle peers.
|
|
456
486
|
*/
|
|
457
487
|
keepAlive?: boolean;
|
|
488
|
+
/** Internal ownership handoff for cleanup that outlives the visible Task result. */
|
|
489
|
+
onCleanupDeferred?: (completion: Promise<void>) => void;
|
|
458
490
|
}
|
|
459
491
|
|
|
460
492
|
function parseStringifiedJson(value: unknown): unknown {
|
|
@@ -877,6 +909,8 @@ interface RunMonitorArgs {
|
|
|
877
909
|
/** Parent settings for tiny-model label generation. */
|
|
878
910
|
settings?: Settings;
|
|
879
911
|
modelOverride?: string | string[];
|
|
912
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
913
|
+
modelRole?: string;
|
|
880
914
|
signal?: AbortSignal;
|
|
881
915
|
onProgress?: (progress: AgentProgress) => void;
|
|
882
916
|
eventBus?: EventBus;
|
|
@@ -992,6 +1026,7 @@ function createSubagentRunMonitor(args: RunMonitorArgs): SubagentRunMonitor {
|
|
|
992
1026
|
cost: 0,
|
|
993
1027
|
durationMs: 0,
|
|
994
1028
|
modelOverride: args.modelOverride,
|
|
1029
|
+
modelRole: args.modelRole,
|
|
995
1030
|
};
|
|
996
1031
|
|
|
997
1032
|
const outputChunks: string[] = [];
|
|
@@ -1964,9 +1999,7 @@ async function driveSessionToYield(
|
|
|
1964
1999
|
// yield: the next iteration's ladder demands a fresh one.
|
|
1965
2000
|
}
|
|
1966
2001
|
|
|
1967
|
-
if (monitor.yieldCalled()) {
|
|
1968
|
-
await session.waitForIdle();
|
|
1969
|
-
} else {
|
|
2002
|
+
if (!monitor.yieldCalled()) {
|
|
1970
2003
|
await awaitAbortable(session.waitForIdle());
|
|
1971
2004
|
}
|
|
1972
2005
|
|
|
@@ -2044,6 +2077,8 @@ interface FinalizeRunArgs {
|
|
|
2044
2077
|
task: string;
|
|
2045
2078
|
assignment?: string;
|
|
2046
2079
|
modelOverride?: string | string[];
|
|
2080
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
2081
|
+
modelRole?: string;
|
|
2047
2082
|
outputSchema?: unknown;
|
|
2048
2083
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
2049
2084
|
outputSchemaSource?: StructuredSubagentSchemaSource;
|
|
@@ -2063,7 +2098,7 @@ interface FinalizeRunArgs {
|
|
|
2063
2098
|
* event.
|
|
2064
2099
|
*/
|
|
2065
2100
|
async function finalizeRunResult(args: FinalizeRunArgs): Promise<SingleResult> {
|
|
2066
|
-
const { monitor, done, index, id, agent, task, assignment, signal, modelOverride } = args;
|
|
2101
|
+
const { monitor, done, index, id, agent, task, assignment, signal, modelOverride, modelRole } = args;
|
|
2067
2102
|
const progress = monitor.progress;
|
|
2068
2103
|
let exitCode = done.exitCode;
|
|
2069
2104
|
let stderr = done.error ?? "";
|
|
@@ -2140,14 +2175,17 @@ async function finalizeRunResult(args: FinalizeRunArgs): Promise<SingleResult> {
|
|
|
2140
2175
|
exitCode = 1;
|
|
2141
2176
|
}
|
|
2142
2177
|
const wasAborted =
|
|
2143
|
-
runtimeLimitExceeded || abortedViaYield || (!hasYield && (
|
|
2178
|
+
runtimeLimitExceeded || Boolean(done.aborted) || abortedViaYield || (!hasYield && Boolean(signal?.aborted));
|
|
2144
2179
|
const finalAbortReason = wasAborted
|
|
2145
2180
|
? runtimeLimitExceeded
|
|
2146
2181
|
? monitor.resolveAbortReasonText()
|
|
2147
|
-
:
|
|
2148
|
-
?
|
|
2149
|
-
:
|
|
2150
|
-
|
|
2182
|
+
: done.aborted
|
|
2183
|
+
? (done.abortReason ?? monitor.resolveAbortReasonText())
|
|
2184
|
+
: abortedViaYield
|
|
2185
|
+
? yieldAbortReason
|
|
2186
|
+
: signal?.aborted
|
|
2187
|
+
? monitor.resolveSignalAbortReason()
|
|
2188
|
+
: monitor.resolveAbortReasonText()
|
|
2151
2189
|
: undefined;
|
|
2152
2190
|
progress.status = wasAborted ? "aborted" : exitCode === 0 ? "completed" : "failed";
|
|
2153
2191
|
monitor.scheduleProgress(true);
|
|
@@ -2187,6 +2225,7 @@ async function finalizeRunResult(args: FinalizeRunArgs): Promise<SingleResult> {
|
|
|
2187
2225
|
contextTokens: progress.contextTokens,
|
|
2188
2226
|
contextWindow: progress.contextWindow,
|
|
2189
2227
|
modelOverride,
|
|
2228
|
+
modelRole,
|
|
2190
2229
|
resolvedModel: progress.resolvedModel,
|
|
2191
2230
|
resolvedModelIsFallback: progress.resolvedModelIsFallback,
|
|
2192
2231
|
error: exitCode !== 0 && stderr ? stderr : undefined,
|
|
@@ -2208,6 +2247,8 @@ export interface IrcWakeTurnMonitorOptions {
|
|
|
2208
2247
|
agent: AgentDefinition;
|
|
2209
2248
|
description?: string;
|
|
2210
2249
|
modelOverride?: string | string[];
|
|
2250
|
+
/** Explicit pre-expansion model role alias selected for this run. */
|
|
2251
|
+
modelRole?: string;
|
|
2211
2252
|
eventBus?: EventBus;
|
|
2212
2253
|
parentToolCallId?: string;
|
|
2213
2254
|
/** Fallback session file when the registry ref carries none. */
|
|
@@ -2252,6 +2293,7 @@ export function attachIrcWakeTurnMonitor(session: AgentSession, options: IrcWake
|
|
|
2252
2293
|
task: ircTask,
|
|
2253
2294
|
description: options.description,
|
|
2254
2295
|
modelOverride: options.modelOverride,
|
|
2296
|
+
modelRole: options.modelRole,
|
|
2255
2297
|
eventBus: options.eventBus,
|
|
2256
2298
|
parentToolCallId: options.parentToolCallId,
|
|
2257
2299
|
detached: true,
|
|
@@ -2309,6 +2351,7 @@ export function attachIrcWakeTurnMonitor(session: AgentSession, options: IrcWake
|
|
|
2309
2351
|
agent,
|
|
2310
2352
|
task: ircTask,
|
|
2311
2353
|
modelOverride: options.modelOverride,
|
|
2354
|
+
modelRole: options.modelRole,
|
|
2312
2355
|
outputSchema: options.outputSchema,
|
|
2313
2356
|
outputSchemaMode: options.outputSchemaMode,
|
|
2314
2357
|
outputSchemaSource: options.outputSchemaSource,
|
|
@@ -2346,15 +2389,27 @@ export async function finalizeSubagentLifecycle(args: {
|
|
|
2346
2389
|
isolated: boolean;
|
|
2347
2390
|
agentIdleTtlMs: number;
|
|
2348
2391
|
reviveSession: AgentReviver | null;
|
|
2392
|
+
cleanupDeadlineAt?: number;
|
|
2393
|
+
onCleanupDeferred?: (completion: Promise<void>) => void;
|
|
2349
2394
|
}): Promise<void> {
|
|
2350
2395
|
const registry = AgentRegistry.global();
|
|
2351
2396
|
const ref = registry.get(args.id);
|
|
2352
2397
|
const ownsRef = Boolean(ref && ref.session === args.session);
|
|
2398
|
+
const cleanupDeadlineAt = args.cleanupDeadlineAt ?? Date.now() + 5000;
|
|
2353
2399
|
const disposeSession = async (): Promise<void> => {
|
|
2400
|
+
const disposal = args.session.dispose();
|
|
2401
|
+
const remainingMs = Math.max(0, cleanupDeadlineAt - Date.now());
|
|
2354
2402
|
try {
|
|
2355
|
-
await untilAborted(AbortSignal.timeout(
|
|
2356
|
-
} catch {
|
|
2357
|
-
|
|
2403
|
+
await untilAborted(AbortSignal.timeout(remainingMs), () => disposal);
|
|
2404
|
+
} catch (error) {
|
|
2405
|
+
if (Date.now() >= cleanupDeadlineAt) {
|
|
2406
|
+
args.onCleanupDeferred?.(disposal);
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2409
|
+
logger.warn("Subagent session cleanup failed", {
|
|
2410
|
+
id: args.id,
|
|
2411
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2412
|
+
});
|
|
2358
2413
|
}
|
|
2359
2414
|
};
|
|
2360
2415
|
|
|
@@ -2365,14 +2420,20 @@ export async function finalizeSubagentLifecycle(args: {
|
|
|
2365
2420
|
args.abortKind === "budget" && args.keepAlive && !args.isolated && args.reviveSession !== null;
|
|
2366
2421
|
if (args.aborted && !resumableAbort) {
|
|
2367
2422
|
if (ref && ownsRef) {
|
|
2368
|
-
//
|
|
2369
|
-
//
|
|
2370
|
-
//
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
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();
|
|
2374
2436
|
}
|
|
2375
|
-
await disposeSession();
|
|
2376
2437
|
return;
|
|
2377
2438
|
}
|
|
2378
2439
|
|
|
@@ -2421,6 +2482,8 @@ export interface FollowUpTurnOptions {
|
|
|
2421
2482
|
message: string;
|
|
2422
2483
|
index?: number;
|
|
2423
2484
|
description?: string;
|
|
2485
|
+
/** Explicit pre-expansion model role alias retained from the original run. */
|
|
2486
|
+
modelRole?: string;
|
|
2424
2487
|
/** Structured-output state retained from the original invocation. */
|
|
2425
2488
|
outputSchema?: unknown;
|
|
2426
2489
|
outputSchemaMode?: StructuredSubagentSchemaMode;
|
|
@@ -2460,6 +2523,7 @@ export async function runSubagentFollowUpTurn(options: FollowUpTurnOptions): Pro
|
|
|
2460
2523
|
agent,
|
|
2461
2524
|
task: message,
|
|
2462
2525
|
description: options.description,
|
|
2526
|
+
modelRole: options.modelRole,
|
|
2463
2527
|
signal,
|
|
2464
2528
|
onProgress: options.onProgress,
|
|
2465
2529
|
eventBus: options.eventBus,
|
|
@@ -2509,6 +2573,7 @@ export async function runSubagentFollowUpTurn(options: FollowUpTurnOptions): Pro
|
|
|
2509
2573
|
id,
|
|
2510
2574
|
agent,
|
|
2511
2575
|
task: message,
|
|
2576
|
+
modelRole: options.modelRole,
|
|
2512
2577
|
outputSchema: options.outputSchema,
|
|
2513
2578
|
outputSchemaMode: options.outputSchemaMode,
|
|
2514
2579
|
outputSchemaSource: options.outputSchemaSource,
|
|
@@ -2535,6 +2600,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2535
2600
|
id,
|
|
2536
2601
|
worktree,
|
|
2537
2602
|
modelOverride,
|
|
2603
|
+
modelRole,
|
|
2538
2604
|
thinkingLevel,
|
|
2539
2605
|
outputSchema,
|
|
2540
2606
|
enableLsp,
|
|
@@ -2564,6 +2630,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2564
2630
|
tokens: 0,
|
|
2565
2631
|
requests: 0,
|
|
2566
2632
|
modelOverride,
|
|
2633
|
+
modelRole,
|
|
2567
2634
|
error: "Cancelled before start",
|
|
2568
2635
|
aborted: true,
|
|
2569
2636
|
abortReason: "Cancelled before start",
|
|
@@ -2654,6 +2721,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2654
2721
|
modelRegistry: options.modelRegistry,
|
|
2655
2722
|
settings,
|
|
2656
2723
|
modelOverride,
|
|
2724
|
+
modelRole,
|
|
2657
2725
|
signal,
|
|
2658
2726
|
onProgress,
|
|
2659
2727
|
eventBus: options.eventBus,
|
|
@@ -2687,6 +2755,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2687
2755
|
agent,
|
|
2688
2756
|
description: options.description,
|
|
2689
2757
|
modelOverride,
|
|
2758
|
+
modelRole,
|
|
2690
2759
|
eventBus: options.eventBus,
|
|
2691
2760
|
parentToolCallId: options.parentToolCallId,
|
|
2692
2761
|
sessionFile: subtaskSessionFile,
|
|
@@ -2764,9 +2833,9 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2764
2833
|
checkAbort();
|
|
2765
2834
|
|
|
2766
2835
|
const configuredModelPatterns = resolveConfiguredModelPatterns(modelPatterns, settings);
|
|
2767
|
-
const
|
|
2836
|
+
const inheritedRetryFallbackChain =
|
|
2768
2837
|
configuredModelPatterns.length === 1
|
|
2769
|
-
?
|
|
2838
|
+
? resolveSubagentInheritedRetryFallbackChain(subagentSettings, modelRegistry, modelPatterns)
|
|
2770
2839
|
: undefined;
|
|
2771
2840
|
const {
|
|
2772
2841
|
model,
|
|
@@ -2800,8 +2869,8 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2800
2869
|
const retryFallbackRole = installSubagentRetryFallbackChain({
|
|
2801
2870
|
settings: subagentSettings,
|
|
2802
2871
|
id,
|
|
2803
|
-
candidates: resolveSubagentRetryFallbackCandidates(modelPatterns, modelRegistry,
|
|
2804
|
-
|
|
2872
|
+
candidates: resolveSubagentRetryFallbackCandidates(modelPatterns, modelRegistry, subagentSettings),
|
|
2873
|
+
inheritedFallbackChain: inheritedRetryFallbackChain,
|
|
2805
2874
|
model,
|
|
2806
2875
|
authFallbackUsed,
|
|
2807
2876
|
});
|
|
@@ -2944,7 +3013,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
2944
3013
|
modelPatternFallbackRole:
|
|
2945
3014
|
model || modelOverride === undefined ? undefined : `${SUBAGENT_RETRY_FALLBACK_ROLE_PREFIX}${id}`,
|
|
2946
3015
|
modelPatternDefaultFallbackChain:
|
|
2947
|
-
model || modelOverride === undefined ? undefined :
|
|
3016
|
+
model || modelOverride === undefined ? undefined : inheritedRetryFallbackChain,
|
|
2948
3017
|
thinkingLevel: effectiveThinkingLevel,
|
|
2949
3018
|
thinkingLevelCeiling: spawnEffortCeiling,
|
|
2950
3019
|
toolNames,
|
|
@@ -3072,6 +3141,10 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3072
3141
|
systemPrompt: session.agent.state.systemPrompt.join("\n\n"),
|
|
3073
3142
|
task,
|
|
3074
3143
|
tools: session.getActiveToolNames(),
|
|
3144
|
+
agent: agent.name,
|
|
3145
|
+
modelRole: modelRole ?? resolveExplicitModelRole(modelOverride ?? agent.model, subagentSettings),
|
|
3146
|
+
resolvedModel: progress.resolvedModel,
|
|
3147
|
+
readOnly: isReadOnlyAgent(agent),
|
|
3075
3148
|
spawns: spawnsEnv,
|
|
3076
3149
|
readSummarize: agent.readSummarize,
|
|
3077
3150
|
outputSchema,
|
|
@@ -3121,7 +3194,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3121
3194
|
session.sessionManager.appendLabelChange(targetId, label);
|
|
3122
3195
|
},
|
|
3123
3196
|
getActiveTools: () => session.getEnabledToolNames(),
|
|
3124
|
-
getAllTools: () => session.
|
|
3197
|
+
getAllTools: () => session.getAllToolInfos(),
|
|
3125
3198
|
setActiveTools: (toolNames: string[]) =>
|
|
3126
3199
|
session.setActiveToolsByName(toolNames.filter(name => !isParentOwnedTool(name))),
|
|
3127
3200
|
getCommands: () => getSessionSlashCommands(session),
|
|
@@ -3186,6 +3259,20 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3186
3259
|
error = err instanceof Error ? err.stack || err.message : String(err);
|
|
3187
3260
|
}
|
|
3188
3261
|
} finally {
|
|
3262
|
+
const cleanupDeadlineAt = Date.now() + TASK_ABORT_CLEANUP_GRACE_MS;
|
|
3263
|
+
const cleanupChangeStatus =
|
|
3264
|
+
worktree === undefined
|
|
3265
|
+
? "This task was not isolated, so its changes may remain in the working directory."
|
|
3266
|
+
: "No isolated changes were applied.";
|
|
3267
|
+
const lateCleanups: Promise<void>[] = [];
|
|
3268
|
+
let deferredSessionShutdown: Promise<void> | undefined;
|
|
3269
|
+
const deferCleanup = (completion: Promise<void>): void => {
|
|
3270
|
+
lateCleanups.push(completion);
|
|
3271
|
+
exitCode = 1;
|
|
3272
|
+
aborted = true;
|
|
3273
|
+
abortReasonText = `cleanup exceeded ${TASK_ABORT_CLEANUP_GRACE_MS} ms`;
|
|
3274
|
+
error ??= `Task aborted. Cleanup did not finish within ${TASK_ABORT_CLEANUP_GRACE_MS} ms. ${cleanupChangeStatus}`;
|
|
3275
|
+
};
|
|
3189
3276
|
if (abortSignal.aborted) {
|
|
3190
3277
|
aborted = monitor.isAbortedRun();
|
|
3191
3278
|
if (aborted) {
|
|
@@ -3194,10 +3281,21 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3194
3281
|
if (exitCode === 0) exitCode = 1;
|
|
3195
3282
|
}
|
|
3196
3283
|
sessionAbortController.abort();
|
|
3284
|
+
const activeSessionAbort = monitor.waitForActiveSessionAbort();
|
|
3197
3285
|
try {
|
|
3198
|
-
await untilAborted(
|
|
3199
|
-
|
|
3200
|
-
|
|
3286
|
+
await untilAborted(
|
|
3287
|
+
AbortSignal.timeout(Math.max(0, cleanupDeadlineAt - Date.now())),
|
|
3288
|
+
() => activeSessionAbort,
|
|
3289
|
+
);
|
|
3290
|
+
} catch (cleanupError) {
|
|
3291
|
+
if (Date.now() >= cleanupDeadlineAt) {
|
|
3292
|
+
deferCleanup(activeSessionAbort);
|
|
3293
|
+
} else {
|
|
3294
|
+
logger.warn("Subagent abort cleanup failed", {
|
|
3295
|
+
id,
|
|
3296
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError),
|
|
3297
|
+
});
|
|
3298
|
+
}
|
|
3201
3299
|
}
|
|
3202
3300
|
if (unsubscribe) {
|
|
3203
3301
|
try {
|
|
@@ -3207,6 +3305,17 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3207
3305
|
}
|
|
3208
3306
|
unsubscribe = null;
|
|
3209
3307
|
}
|
|
3308
|
+
const jobManager = AsyncJobManager.instance();
|
|
3309
|
+
if (jobManager) {
|
|
3310
|
+
const reap = await jobManager.cancelAndReapOwnerJobs(id, cleanupDeadlineAt);
|
|
3311
|
+
if (!reap.settled) {
|
|
3312
|
+
deferCleanup(reap.completion);
|
|
3313
|
+
logger.warn("Subagent async job cleanup exceeded its deadline", {
|
|
3314
|
+
id,
|
|
3315
|
+
pendingJobIds: reap.pendingJobIds,
|
|
3316
|
+
});
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3210
3319
|
const session = monitor.takeActiveSession();
|
|
3211
3320
|
if (session) {
|
|
3212
3321
|
monitor.captureSalvage(session);
|
|
@@ -3222,22 +3331,36 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3222
3331
|
isolated: worktree !== undefined,
|
|
3223
3332
|
agentIdleTtlMs,
|
|
3224
3333
|
reviveSession,
|
|
3334
|
+
cleanupDeadlineAt,
|
|
3335
|
+
onCleanupDeferred: completion => {
|
|
3336
|
+
deferredSessionShutdown = completion;
|
|
3337
|
+
deferCleanup(completion);
|
|
3338
|
+
},
|
|
3225
3339
|
});
|
|
3226
3340
|
}
|
|
3227
|
-
// Structured-concurrency reap: cancel and await ALL surviving owner
|
|
3228
|
-
// jobs (abort paths; suppressed/watched jobs the model left behind)
|
|
3229
|
-
// so isolation capture/cleanup never races a live process writing
|
|
3230
|
-
// into the worktree. This never proceeds while an owner process is
|
|
3231
|
-
// live: cancellation SIGKILL-escalates, so settlement is expected
|
|
3232
|
-
// within one interval — an unkillable process blocks here visibly
|
|
3233
|
-
// (with periodic warnings) instead of silently racing teardown.
|
|
3234
|
-
const jobManager = AsyncJobManager.instance();
|
|
3235
3341
|
if (jobManager) {
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3342
|
+
if (deferredSessionShutdown) {
|
|
3343
|
+
const finalReap = Promise.allSettled([deferredSessionShutdown]).then(async () => {
|
|
3344
|
+
const reap = await jobManager.cancelAndReapOwnerJobs(id, Date.now());
|
|
3345
|
+
await reap.completion;
|
|
3346
|
+
});
|
|
3347
|
+
lateCleanups.push(finalReap);
|
|
3348
|
+
} else {
|
|
3349
|
+
const reap = await jobManager.cancelAndReapOwnerJobs(id, cleanupDeadlineAt);
|
|
3350
|
+
if (!reap.settled) {
|
|
3351
|
+
deferCleanup(reap.completion);
|
|
3352
|
+
logger.warn("Subagent async job cleanup exceeded its deadline after session shutdown", {
|
|
3353
|
+
id,
|
|
3354
|
+
pendingJobIds: reap.pendingJobIds,
|
|
3355
|
+
});
|
|
3356
|
+
}
|
|
3239
3357
|
}
|
|
3240
3358
|
}
|
|
3359
|
+
if (lateCleanups.length > 0) {
|
|
3360
|
+
const completion = Promise.allSettled(lateCleanups).then(() => {});
|
|
3361
|
+
trackLateCleanup(completion, { id, resource: "subagent" });
|
|
3362
|
+
options.onCleanupDeferred?.(completion);
|
|
3363
|
+
}
|
|
3241
3364
|
}
|
|
3242
3365
|
|
|
3243
3366
|
// Launch-latency breakdown (subagent invocation → first chat dispatch).
|
|
@@ -3282,7 +3405,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3282
3405
|
const done = await runSubagent();
|
|
3283
3406
|
monitor.finish();
|
|
3284
3407
|
|
|
3285
|
-
|
|
3408
|
+
const result = await finalizeRunResult({
|
|
3286
3409
|
monitor,
|
|
3287
3410
|
done,
|
|
3288
3411
|
index,
|
|
@@ -3291,6 +3414,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3291
3414
|
task,
|
|
3292
3415
|
assignment,
|
|
3293
3416
|
modelOverride,
|
|
3417
|
+
modelRole,
|
|
3294
3418
|
outputSchema,
|
|
3295
3419
|
outputSchemaMode: options.outputSchemaMode,
|
|
3296
3420
|
outputSchemaSource: options.outputSchemaSource,
|
|
@@ -3302,4 +3426,6 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
3302
3426
|
sessionFile: subtaskSessionFile,
|
|
3303
3427
|
startTime,
|
|
3304
3428
|
});
|
|
3429
|
+
AgentRegistry.global().setHistory(id, { outputPath: result.outputPath });
|
|
3430
|
+
return result;
|
|
3305
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
|
|
@@ -860,6 +836,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
860
836
|
id: agentId,
|
|
861
837
|
agent: agentType,
|
|
862
838
|
agentSource,
|
|
839
|
+
modelRole: policy.modelRole,
|
|
863
840
|
status: "pending",
|
|
864
841
|
task: renderSubagentUserPrompt(assignment),
|
|
865
842
|
assignment,
|
|
@@ -1143,8 +1120,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1143
1120
|
// polling row reflects the resolved model, reasoning level,
|
|
1144
1121
|
// and running counters without reverting the "running"
|
|
1145
1122
|
// status back to the subagent's initial "pending" snapshot.
|
|
1123
|
+
progress.modelRole = nextProgress.modelRole ?? progress.modelRole;
|
|
1146
1124
|
progress.resolvedModel = nextProgress.resolvedModel;
|
|
1147
|
-
progress.resolvedModelIsFallback =
|
|
1125
|
+
progress.resolvedModelIsFallback =
|
|
1126
|
+
nextProgress.resolvedModelIsFallback ?? progress.resolvedModelIsFallback;
|
|
1148
1127
|
progress.tokens = nextProgress.tokens;
|
|
1149
1128
|
progress.requests = nextProgress.requests;
|
|
1150
1129
|
progress.contextTokens = nextProgress.contextTokens;
|
|
@@ -1187,9 +1166,11 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1187
1166
|
progress.extractedToolData = singleResult?.extractedToolData;
|
|
1188
1167
|
progress.retryFailure = singleResult?.retryFailure;
|
|
1189
1168
|
progress.retryState = undefined;
|
|
1169
|
+
progress.modelRole = singleResult?.modelRole ?? progress.modelRole;
|
|
1190
1170
|
if (singleResult?.resolvedModel) {
|
|
1191
1171
|
progress.resolvedModel = singleResult.resolvedModel;
|
|
1192
|
-
progress.resolvedModelIsFallback =
|
|
1172
|
+
progress.resolvedModelIsFallback =
|
|
1173
|
+
singleResult.resolvedModelIsFallback ?? progress.resolvedModelIsFallback;
|
|
1193
1174
|
} else {
|
|
1194
1175
|
delete progress.resolvedModel;
|
|
1195
1176
|
delete progress.resolvedModelIsFallback;
|