pi-subagents 0.66.0 → 0.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +138 -0
- package/README.md +5 -4
- package/agents/evidence-auditor.md +34 -0
- package/agents/reviewer.md +3 -2
- package/docs/agents.md +43 -15
- package/docs/configuration.md +67 -23
- package/docs/extension-api.md +38 -19
- package/docs/missions.md +10 -2
- package/docs/models.md +11 -79
- package/docs/observability.md +22 -12
- package/docs/standalone-background.md +59 -0
- package/docs/tool-reference.md +33 -20
- package/docs/watchdog.md +39 -10
- package/docs/workflows.md +37 -13
- package/index.ts +5 -2
- package/inspector-runner.mjs +2 -2
- package/package.json +4 -2
- package/prompts/parallel-review.md +1 -1
- package/runner-peer-loader.mjs +24 -0
- package/runner-peer-preload.mjs +32 -0
- package/skills/pi-subagents/SKILL.md +32 -21
- package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
- package/skills/pi-subagents/references/execution-controls.md +11 -9
- package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +17 -13
- package/skills/pi-subagents/references/review-and-validation.md +3 -3
- package/src/agents/advertised-agent-prompt.ts +34 -3
- package/src/agents/agent-management.ts +57 -58
- package/src/agents/agent-serializer.ts +4 -3
- package/src/agents/agents.ts +190 -71
- package/src/agents/builtin-names.ts +1 -0
- package/src/agents/chain-serializer.ts +5 -0
- package/src/agents/runtime-agent-registry.ts +7 -6
- package/src/api/delegation.ts +4 -0
- package/src/api/preflight.ts +94 -59
- package/src/api/required-child-extensions.ts +6 -0
- package/src/api/shared-types.ts +2 -0
- package/src/extension/config.ts +10 -37
- package/src/extension/fanout-child.ts +66 -4
- package/src/extension/herdr-pi-bridge.ts +160 -0
- package/src/extension/index.ts +62 -39
- package/src/extension/public-execution.ts +7 -5
- package/src/extension/rpc.ts +4 -0
- package/src/extension/schemas.ts +81 -81
- package/src/extension/tool-description.ts +30 -82
- package/src/inspectors/actions.ts +148 -0
- package/src/inspectors/ghostty/actions.ts +74 -0
- package/src/inspectors/ghostty/plugin.ts +17 -0
- package/src/inspectors/herdr/actions.ts +99 -179
- package/src/inspectors/herdr/plugin.ts +20 -0
- package/src/inspectors/herdr/project-panes.ts +1 -1
- package/src/inspectors/{herdr/inspector-runner.ts → inspector-runner.ts} +12 -12
- package/src/inspectors/plugins.ts +8 -0
- package/src/inspectors/{herdr/session-roots-codec.ts → session-roots-codec.ts} +3 -14
- package/src/inspectors/types.ts +51 -0
- package/src/intercom/intercom-bridge.ts +50 -8
- package/src/intercom/native-supervisor-channel.ts +44 -31
- package/src/policy/authority.ts +4 -0
- package/src/profiles/profiles.ts +12 -6
- package/src/runs/background/active-async-capacity.ts +4 -0
- package/src/runs/background/active-run-index.ts +17 -1
- package/src/runs/background/async-execution.ts +348 -176
- package/src/runs/background/async-job-tracker.ts +8 -6
- package/src/runs/background/async-resume.ts +17 -12
- package/src/runs/background/async-status.ts +15 -4
- package/src/runs/background/auto-drain.ts +23 -10
- package/src/runs/background/binary-bootstrap.ts +38 -0
- package/src/runs/background/chain-append.ts +1 -1
- package/src/runs/background/chain-root-attachment.ts +14 -33
- package/src/runs/background/fleet-view.ts +30 -2
- package/src/runs/background/notify.ts +105 -7
- package/src/runs/background/owned-process-tree.ts +29 -2
- package/src/runs/background/result-files.ts +8 -4
- package/src/runs/background/result-watcher.ts +19 -2
- package/src/runs/background/run-child-session.ts +81 -33
- package/src/runs/background/run-status.ts +3 -0
- package/src/runs/background/runner-aliases.ts +12 -33
- package/src/runs/background/runner-child-launch.ts +6 -1
- package/src/runs/background/runner-child-sessions.ts +5 -4
- package/src/runs/background/runner-http-dispatcher.ts +119 -0
- package/src/runs/background/scheduled-runs.ts +51 -18
- package/src/runs/background/stale-run-reconciler.ts +35 -11
- package/src/runs/background/steering.ts +20 -2
- package/src/runs/background/subagent-runner.ts +441 -304
- package/src/runs/background/subagent-wait.ts +176 -28
- package/src/runs/background/wait-completions.ts +75 -27
- package/src/runs/background/wait-subscriptions.ts +9 -3
- package/src/runs/background/wait-tool.ts +5 -3
- package/src/runs/foreground/async-steering-action.ts +18 -7
- package/src/runs/foreground/async-stop-action.ts +93 -3
- package/src/runs/foreground/execution.ts +134 -248
- package/src/runs/foreground/foreground-history.ts +2 -1
- package/src/runs/foreground/prompt-audit.ts +3 -1
- package/src/runs/foreground/subagent-executor.ts +374 -178
- package/src/runs/foreground/workflow-detach-reconcile.ts +2 -0
- package/src/runs/foreground/workflow-foreground-steering.ts +2 -1
- package/src/runs/shared/acceptance.ts +38 -11
- package/src/runs/shared/async-status-projection.ts +127 -33
- package/src/runs/shared/capability-ceiling.ts +2 -0
- package/src/runs/shared/child-hooks.ts +25 -10
- package/src/runs/shared/child-launch-plan.ts +15 -3
- package/src/runs/shared/child-launch.ts +28 -5
- package/src/runs/shared/child-lifecycle.ts +6 -3
- package/src/runs/shared/child-runtime-config.ts +8 -1
- package/src/runs/shared/child-session.ts +127 -52
- package/src/runs/shared/child-tool-plan.ts +142 -11
- package/src/runs/shared/completion-guard.ts +5 -3
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/effective-system-prompt.ts +33 -0
- package/src/runs/shared/external-cli-contract.ts +11 -1
- package/src/runs/shared/external-cli-preflight.ts +6 -2
- package/src/runs/shared/external-cli-runner.ts +9 -7
- package/src/runs/shared/herdr-connection.ts +134 -0
- package/src/runs/shared/herdr-external-adapters.ts +169 -0
- package/src/runs/shared/herdr-machine.ts +279 -0
- package/src/runs/shared/herdr-pi-protocol.ts +59 -0
- package/src/runs/shared/herdr-placed-run.ts +263 -0
- package/src/runs/shared/llm-intent-arbiter.ts +12 -3
- package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
- package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -235
- package/src/runs/shared/model-scope.ts +1 -1
- package/src/runs/shared/nested-events.ts +11 -2
- package/src/runs/shared/orca-progress-tabs.ts +1 -1
- package/src/runs/shared/parallel-utils.ts +7 -2
- package/src/runs/shared/pi-spawn.ts +10 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +12 -4
- package/src/runs/shared/task-intent.ts +46 -13
- package/src/runs/shared/workflow-async-child-guidance.ts +18 -0
- package/src/runs/shared/worktree-setup-command.ts +27 -4
- package/src/runs/shared/worktree.ts +45 -15
- package/src/shared/child-cache-retention.ts +43 -0
- package/src/shared/fork-context.ts +15 -72
- package/src/shared/launch-contract.ts +68 -8
- package/src/shared/opencode-session-headers.ts +30 -0
- package/src/shared/pruned-fork.ts +1 -1
- package/src/shared/required-child-extensions.ts +81 -0
- package/src/shared/settings.ts +5 -2
- package/src/shared/shortcuts.ts +0 -4
- package/src/shared/types.ts +74 -30
- package/src/slash/delegation-adapters.ts +3 -1
- package/src/slash/delegation-request.ts +14 -0
- package/src/slash/slash-commands.ts +2 -7
- package/src/slash/subagents-admin.ts +24 -13
- package/src/tui/fleet-status.ts +164 -19
- package/src/tui/fleet.ts +16 -14
- package/src/tui/render.ts +168 -37
- package/src/watchdog/child-status.ts +28 -28
- package/src/watchdog/lsp-diagnostics.ts +1 -1
- package/src/watchdog/model-selection.ts +21 -1
- package/src/watchdog/permission-arbiter.ts +3 -1
- package/src/watchdog/register-child.ts +10 -2
- package/src/watchdog/register-main.ts +39 -35
- package/src/watchdog/render.ts +1 -1
- package/src/watchdog/review.ts +123 -74
- package/src/watchdog/rules.ts +1 -1
- package/src/watchdog/runtime.ts +100 -27
- package/src/watchdog/scope.ts +1 -1
- package/src/watchdog/settings.ts +3 -0
- package/src/watchdog/tool-actions.ts +13 -12
- package/src/watchdog/turn-delta.ts +23 -0
- package/src/watchdog/types.ts +5 -3
- package/src/watchdog/warning-format.ts +1 -1
- package/src/workflows/scripted-workflow.ts +279 -10
- package/src/workflows/workflow-checklist.ts +2 -2
- package/src/workflows/workflow-receipt.ts +21 -3
- package/src/workflows/workflow-resources.ts +13 -2
- package/runner-server-preload.mjs +0 -13
- package/src/runs/shared/model-exclusions.ts +0 -374
- package/src/runs/shared/readonly-model-continuation.ts +0 -69
- package/src/runs/shared/readonly-session-evidence.ts +0 -307
- /package/src/inspectors/{herdr/shell-command.ts → shell-command.ts} +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
5
|
+
const MAX_REQUIRED_EXTENSIONS = 32;
|
|
6
|
+
const MAX_PATH_BYTES = 4096;
|
|
7
|
+
const EMPTY_SNAPSHOT: RequiredChildExtensionSnapshot = Object.freeze([]);
|
|
8
|
+
|
|
9
|
+
export interface RequiredChildExtension {
|
|
10
|
+
/** Safe host-owned identity exposed in launch evidence. */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Existing importable module path. Snapshotted to its canonical absolute path. */
|
|
13
|
+
path: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface RegisterRequiredChildExtensionsInput {
|
|
17
|
+
sessionId: string;
|
|
18
|
+
extensions: readonly RequiredChildExtension[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface RequiredChildExtensionRegistration { dispose(): void }
|
|
22
|
+
export type RequiredChildExtensionSnapshot = ReadonlyArray<Readonly<RequiredChildExtension>>;
|
|
23
|
+
|
|
24
|
+
/** Validate and freeze a snapshot; registration canonicalizes once, while retained launches preserve that identity. */
|
|
25
|
+
export function snapshotRequiredChildExtensions(value: unknown, label = "Required child extensions", canonicalizeFiles = false): RequiredChildExtensionSnapshot {
|
|
26
|
+
if (!Array.isArray(value) || value.length > MAX_REQUIRED_EXTENSIONS) throw new Error(`${label} must be an array of at most ${MAX_REQUIRED_EXTENSIONS} entries.`);
|
|
27
|
+
const ids = new Set<string>();
|
|
28
|
+
const paths = new Set<string>();
|
|
29
|
+
return Object.freeze(value.map((entry, index) => {
|
|
30
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).some((key) => key !== "id" && key !== "path")) throw new Error(`${label} entry ${index} requires only id and path.`);
|
|
31
|
+
const id = "id" in entry ? entry.id : undefined;
|
|
32
|
+
const rawPath = "path" in entry ? entry.path : undefined;
|
|
33
|
+
if (typeof id !== "string" || !ID_PATTERN.test(id)) throw new Error(`${label} entry ${index} requires a safe id of at most 128 characters.`);
|
|
34
|
+
if (ids.has(id)) throw new Error(`${label} id '${id}' is duplicated.`);
|
|
35
|
+
if (typeof rawPath !== "string" || !rawPath.trim() || rawPath.includes("\0") || Buffer.byteLength(rawPath, "utf8") > MAX_PATH_BYTES || (!canonicalizeFiles && !path.isAbsolute(rawPath))) throw new Error(`${label} '${id}' requires ${canonicalizeFiles ? "a" : "an absolute"} non-empty path of at most ${MAX_PATH_BYTES} bytes without NUL.`);
|
|
36
|
+
let extensionPath = rawPath;
|
|
37
|
+
if (canonicalizeFiles) {
|
|
38
|
+
try {
|
|
39
|
+
extensionPath = fs.realpathSync(path.resolve(rawPath));
|
|
40
|
+
if (!fs.statSync(extensionPath).isFile()) throw new Error("not a file");
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw new Error(`${label} '${id}' is not an importable file: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (paths.has(extensionPath)) throw new Error(`${label} path '${extensionPath}' is duplicated.`);
|
|
46
|
+
ids.add(id);
|
|
47
|
+
paths.add(extensionPath);
|
|
48
|
+
return Object.freeze({ id, path: extensionPath });
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface Registry { version: 1; bySession: Map<string, RequiredChildExtensionSnapshot> }
|
|
53
|
+
|
|
54
|
+
function registry(): Registry {
|
|
55
|
+
const key = Symbol.for("pi-subagents.required-child-extensions.v1");
|
|
56
|
+
const root = globalThis as Record<PropertyKey, unknown>;
|
|
57
|
+
const existing = root[key];
|
|
58
|
+
if (existing === undefined) {
|
|
59
|
+
const created: Registry = { version: 1, bySession: new Map() };
|
|
60
|
+
root[key] = created;
|
|
61
|
+
return created;
|
|
62
|
+
}
|
|
63
|
+
if (!existing || typeof existing !== "object" || !("version" in existing) || existing.version !== 1 || !("bySession" in existing) || !(existing.bySession instanceof Map)) throw new Error("Malformed or unsupported required child extension registry.");
|
|
64
|
+
return { version: 1, bySession: existing.bySession };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Register one immutable host-required extension snapshot for a parent session. */
|
|
68
|
+
export function registerRequiredChildExtensions(input: RegisterRequiredChildExtensionsInput): RequiredChildExtensionRegistration {
|
|
69
|
+
if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).some((key) => key !== "sessionId" && key !== "extensions")) throw new Error("Required child extension registration requires only sessionId and extensions.");
|
|
70
|
+
if (typeof input.sessionId !== "string" || !input.sessionId || input.sessionId.trim() !== input.sessionId || input.sessionId.length > 256 || input.sessionId.includes("\0")) throw new Error("Required child extension registration requires a non-empty trimmed sessionId of at most 256 characters without NUL.");
|
|
71
|
+
const frozen = snapshotRequiredChildExtensions(input.extensions, "Required child extensions", true);
|
|
72
|
+
const store = registry();
|
|
73
|
+
if (store.bySession.has(input.sessionId)) throw new Error(`Required child extensions are already registered for session '${input.sessionId}'; dispose them first.`);
|
|
74
|
+
store.bySession.set(input.sessionId, frozen);
|
|
75
|
+
return { dispose() { if (store.bySession.get(input.sessionId) === frozen) store.bySession.delete(input.sessionId); } };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function resolveRequiredChildExtensions(sessionId: string | undefined): RequiredChildExtensionSnapshot {
|
|
79
|
+
if (!sessionId) return EMPTY_SNAPSHOT;
|
|
80
|
+
return registry().bySession.get(sessionId) ?? EMPTY_SNAPSHOT;
|
|
81
|
+
}
|
package/src/shared/settings.ts
CHANGED
|
@@ -32,8 +32,9 @@ export interface SequentialStep {
|
|
|
32
32
|
phase?: string;
|
|
33
33
|
label?: string;
|
|
34
34
|
as?: string;
|
|
35
|
-
outputSchema?: JsonSchemaObject;
|
|
35
|
+
outputSchema?: JsonSchemaObject | false;
|
|
36
36
|
cwd?: string;
|
|
37
|
+
machine?: string;
|
|
37
38
|
output?: OutputOverrideInput;
|
|
38
39
|
outputMode?: OutputMode;
|
|
39
40
|
reads?: string[] | false;
|
|
@@ -56,8 +57,9 @@ export interface ParallelTaskItem {
|
|
|
56
57
|
phase?: string;
|
|
57
58
|
label?: string;
|
|
58
59
|
as?: string;
|
|
59
|
-
outputSchema?: JsonSchemaObject;
|
|
60
|
+
outputSchema?: JsonSchemaObject | false;
|
|
60
61
|
cwd?: string;
|
|
62
|
+
machine?: string;
|
|
61
63
|
count?: number;
|
|
62
64
|
output?: OutputOverrideInput;
|
|
63
65
|
outputMode?: OutputMode;
|
|
@@ -110,6 +112,7 @@ export interface ParallelStep {
|
|
|
110
112
|
failFast?: boolean;
|
|
111
113
|
worktree?: boolean;
|
|
112
114
|
cwd?: string;
|
|
115
|
+
machine?: string;
|
|
113
116
|
agentContract?: AgentContract;
|
|
114
117
|
gateOn?: ChainGateLayer;
|
|
115
118
|
}
|
package/src/shared/shortcuts.ts
CHANGED
package/src/shared/types.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type { GlobalMissionIndexRecord, MissionRecord, MissionStoreConfig } from
|
|
|
16
16
|
import type { ExtensionBindings } from "../runs/shared/extension-bindings.ts";
|
|
17
17
|
import type { WorkflowChildPermitContext } from "./workflow-child-permit.ts";
|
|
18
18
|
import type { WatchdogWarningDetails } from "../watchdog/types.ts";
|
|
19
|
+
import type { RequiredChildExtensionSnapshot } from "./required-child-extensions.ts";
|
|
19
20
|
|
|
20
21
|
// ============================================================================
|
|
21
22
|
// Basic Types
|
|
@@ -230,6 +231,7 @@ export interface WorkflowReceipt {
|
|
|
230
231
|
state: WorkflowReceiptState;
|
|
231
232
|
createdAt: number;
|
|
232
233
|
entries: Record<string, WorkflowReceiptEntry>;
|
|
234
|
+
argsDigest?: string;
|
|
233
235
|
resource?: WorkflowResourceProvenance;
|
|
234
236
|
hostSteps?: HostStepNode[];
|
|
235
237
|
workflowChildren?: WorkflowChildSummary;
|
|
@@ -655,6 +657,12 @@ export type ProcessTreeTerminal =
|
|
|
655
657
|
processGroupId: number;
|
|
656
658
|
verifiedAt: number;
|
|
657
659
|
}
|
|
660
|
+
| {
|
|
661
|
+
state: "observed";
|
|
662
|
+
mechanism: "windows-taskkill";
|
|
663
|
+
pid: number;
|
|
664
|
+
verifiedAt: number;
|
|
665
|
+
}
|
|
658
666
|
| {
|
|
659
667
|
state: "unknown";
|
|
660
668
|
reason: "unsupported-platform" | "signal-failed" | "verification-failed";
|
|
@@ -708,6 +716,7 @@ export type ProcessTerminal =
|
|
|
708
716
|
export interface ScheduleOrigin {
|
|
709
717
|
id: string;
|
|
710
718
|
name?: string;
|
|
719
|
+
quiet?: boolean;
|
|
711
720
|
}
|
|
712
721
|
|
|
713
722
|
export type SteeringActionState = "delivered" | "scheduled" | "pending" | "partial" | "recovered" | "failed";
|
|
@@ -799,6 +808,7 @@ export interface SteeringRecoveryDescriptor {
|
|
|
799
808
|
version: 1;
|
|
800
809
|
launchContractDigest?: string;
|
|
801
810
|
extensionBindings?: ExtensionBindings;
|
|
811
|
+
requiredExtensions?: RequiredChildExtensionSnapshot;
|
|
802
812
|
runFanoutBudget: RunFanoutBudgetDescriptor;
|
|
803
813
|
sourceRunId: string;
|
|
804
814
|
agentContract?: AgentContract;
|
|
@@ -811,7 +821,6 @@ export interface SteeringRecoveryDescriptor {
|
|
|
811
821
|
modelProvider?: string;
|
|
812
822
|
modelOverrideFromParent?: boolean;
|
|
813
823
|
modelOrigin?: "explicit" | "inherited" | "configured";
|
|
814
|
-
fallbackModels?: string[];
|
|
815
824
|
fast?: boolean;
|
|
816
825
|
thinking?: string;
|
|
817
826
|
thinkingCeiling?: ThinkingLevel;
|
|
@@ -915,7 +924,7 @@ export interface SubagentResultIntercomPayload {
|
|
|
915
924
|
// Progress Tracking
|
|
916
925
|
// ============================================================================
|
|
917
926
|
|
|
918
|
-
export interface ChildWatchdogWarningSummary extends Pick<WatchdogWarningDetails, "severity" | "category" | "summary" | "evidence" | "recommendedAction" | "displayedAt"> {
|
|
927
|
+
export interface ChildWatchdogWarningSummary extends Pick<WatchdogWarningDetails, "severity" | "importance" | "category" | "summary" | "evidence" | "recommendedAction" | "displayedAt"> {
|
|
919
928
|
/** True when a later assistant turn in the child followed the warning. */
|
|
920
929
|
addressed: boolean;
|
|
921
930
|
stalemate: boolean;
|
|
@@ -992,14 +1001,6 @@ interface ProgressSummary {
|
|
|
992
1001
|
// Results
|
|
993
1002
|
// ============================================================================
|
|
994
1003
|
|
|
995
|
-
export interface ModelAttempt {
|
|
996
|
-
model: string;
|
|
997
|
-
success: boolean;
|
|
998
|
-
exitCode?: number | null;
|
|
999
|
-
error?: string;
|
|
1000
|
-
usage?: Usage;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
1004
|
export type AcceptanceLevel = "auto" | "none" | "attested" | "checked" | "verified";
|
|
1004
1005
|
|
|
1005
1006
|
export type AcceptanceEvidenceKind =
|
|
@@ -1186,10 +1187,13 @@ export interface LaunchResolvedChildExtensions {
|
|
|
1186
1187
|
disableAmbientExtensions: boolean;
|
|
1187
1188
|
runtime: string[];
|
|
1188
1189
|
configured: string[];
|
|
1190
|
+
/** Bounded host-supplied identities; paths are intentionally not exposed. */
|
|
1191
|
+
required: string[];
|
|
1189
1192
|
effective: string[];
|
|
1190
1193
|
omitted: {
|
|
1191
1194
|
runtime: number;
|
|
1192
1195
|
configured: number;
|
|
1196
|
+
required: number;
|
|
1193
1197
|
effective: number;
|
|
1194
1198
|
};
|
|
1195
1199
|
}
|
|
@@ -1260,16 +1264,16 @@ export interface SingleResult {
|
|
|
1260
1264
|
messages?: Message[];
|
|
1261
1265
|
usage: Usage;
|
|
1262
1266
|
model?: string;
|
|
1267
|
+
/** Authoritative before/after Git evidence captured by a pane-native remote machine. */
|
|
1268
|
+
nativeMachine?: { provider: "herdr"; machineId: string; initialGit?: HerdrRemoteGitStatus; finalGit?: HerdrRemoteGitStatus };
|
|
1263
1269
|
/** Effective thinking level used by this foreground child, when known. */
|
|
1264
1270
|
thinking?: string;
|
|
1265
|
-
|
|
1266
|
-
modelAttempts?: ModelAttempt[];
|
|
1271
|
+
requestedModel?: string;
|
|
1267
1272
|
controlEvents?: ControlEvent[];
|
|
1268
1273
|
error?: string;
|
|
1269
1274
|
/**
|
|
1270
1275
|
* True when the dispatch failed because the input exceeded the model's
|
|
1271
|
-
* context window.
|
|
1272
|
-
* same input on another model cannot succeed). Callers should treat this as
|
|
1276
|
+
* context window. Callers should treat this as
|
|
1273
1277
|
* a signal to reduce input size or re-decompose the task.
|
|
1274
1278
|
*/
|
|
1275
1279
|
contextOverflow?: boolean;
|
|
@@ -1380,10 +1384,11 @@ export interface AgentCapabilityRow {
|
|
|
1380
1384
|
executable: boolean;
|
|
1381
1385
|
restrictionSources?: string[];
|
|
1382
1386
|
aliases?: string[];
|
|
1383
|
-
runner: { type: "pi" } | { type: "external-cli"; adapter?: string; command: string; available: boolean; unavailableReason?: string; capabilities: ExternalCliCapabilities } | { type: "external-job"; provider: string; available?: boolean; capabilities: ExternalJobRunnerStatus["capabilities"] };
|
|
1387
|
+
runner: { type: "pi" } | { type: "external-cli"; adapter?: string; command: string; machine?: string; available: boolean; unavailableReason?: string; capabilities: ExternalCliCapabilities } | { type: "external-job"; provider: string; available?: boolean; capabilities: ExternalJobRunnerStatus["capabilities"] };
|
|
1384
1388
|
tools: { ambient: boolean; names: string[]; excludeTools?: string[]; mcpDirectTools: string[]; mutationTools?: string[] };
|
|
1385
|
-
model?: { value?: string;
|
|
1389
|
+
model?: { value?: string; thinking?: string | false };
|
|
1386
1390
|
execution?: { defaultAsync?: boolean; timeoutMs?: number };
|
|
1391
|
+
acceptance?: { policy?: AcceptanceInput; role?: AcceptanceRole };
|
|
1387
1392
|
output?: { path?: string; mode?: OutputMode };
|
|
1388
1393
|
extensions?: { names?: string[]; subagentOnly?: string[]; skills?: string[] };
|
|
1389
1394
|
}
|
|
@@ -1410,6 +1415,12 @@ export interface Details {
|
|
|
1410
1415
|
timedOut: true;
|
|
1411
1416
|
activeRunIds: string[];
|
|
1412
1417
|
activeProviderItems: Array<{ provider: string; id: string }>;
|
|
1418
|
+
} | {
|
|
1419
|
+
/** Non-terminal internal auto-drain yield; tracked work remains active. */
|
|
1420
|
+
reason: "supervisor_request";
|
|
1421
|
+
timedOut: false;
|
|
1422
|
+
activeRunIds: string[];
|
|
1423
|
+
activeProviderItems: Array<{ provider: string; id: string }>;
|
|
1413
1424
|
};
|
|
1414
1425
|
controlEvents?: ControlEvent[];
|
|
1415
1426
|
steering?: SteerActionResult;
|
|
@@ -1471,6 +1482,8 @@ export interface Details {
|
|
|
1471
1482
|
mission?: MissionRecord;
|
|
1472
1483
|
workflow?: {
|
|
1473
1484
|
value?: unknown;
|
|
1485
|
+
args?: Record<string, unknown>;
|
|
1486
|
+
argsDigest?: string;
|
|
1474
1487
|
resource?: WorkflowResourceProvenance;
|
|
1475
1488
|
preflightWarnings?: string[];
|
|
1476
1489
|
trace: Array<{
|
|
@@ -1706,6 +1719,26 @@ export type AgentRunnerConfig =
|
|
|
1706
1719
|
|
|
1707
1720
|
export type ExternalCliCapabilityNarrowing = Partial<Record<"steer" | "resume" | "structuredOutput" | "toolEvents" | "supervisor" | "forkContext" | "extensionBindings", false>>;
|
|
1708
1721
|
|
|
1722
|
+
export interface HerdrRemoteGitStatus {
|
|
1723
|
+
head?: string;
|
|
1724
|
+
branch?: string;
|
|
1725
|
+
dirty?: boolean;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
/** A Herdr saved SSH machine resolved for one launch. `cwd` is the directory on that machine. */
|
|
1729
|
+
export interface HerdrMachineReference {
|
|
1730
|
+
provider: "herdr";
|
|
1731
|
+
id: string;
|
|
1732
|
+
label?: string;
|
|
1733
|
+
target: string;
|
|
1734
|
+
session?: string;
|
|
1735
|
+
cwd: string;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
export interface ExternalCliMachineStatus extends HerdrMachineReference {
|
|
1739
|
+
remoteGit?: HerdrRemoteGitStatus;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1709
1742
|
export interface ExternalCliCapabilities {
|
|
1710
1743
|
stop: true;
|
|
1711
1744
|
steer: false;
|
|
@@ -1720,6 +1753,7 @@ export interface ExternalCliCapabilities {
|
|
|
1720
1753
|
export interface ExternalCliReceiptMetadata {
|
|
1721
1754
|
adapter: { id: "external-cli" | "codex-exec" | "codex-exec-writer" | "claude-code" | "claude-code-writer" | "cursor-agent" | "cursor-agent-writer" | "grok-build"; version: 1; executionMode: "one-shot-stdin" | "one-shot-prompt-file" };
|
|
1722
1755
|
capabilities: ExternalCliCapabilities;
|
|
1756
|
+
machine?: ExternalCliMachineStatus;
|
|
1723
1757
|
safety?:
|
|
1724
1758
|
| { sandbox: "read-only"; approvalPolicy: "never"; ephemeral: true }
|
|
1725
1759
|
| { access: "workspace-write"; sandbox: "workspace-write"; approvalPolicy: "never"; ephemeral: true }
|
|
@@ -1744,6 +1778,7 @@ export interface ExternalCliRunnerStatus {
|
|
|
1744
1778
|
capabilities: ExternalCliCapabilities;
|
|
1745
1779
|
unsupportedReasons: Record<Exclude<keyof ExternalCliCapabilities, "stop">, string>;
|
|
1746
1780
|
nonResumableReason: string;
|
|
1781
|
+
machine?: HerdrMachineReference;
|
|
1747
1782
|
}
|
|
1748
1783
|
|
|
1749
1784
|
export interface ExternalJobRunnerStatus {
|
|
@@ -1795,6 +1830,7 @@ export interface ExternalProcessStatus {
|
|
|
1795
1830
|
stderrBytes?: number;
|
|
1796
1831
|
stdoutTruncated?: boolean;
|
|
1797
1832
|
stderrTruncated?: boolean;
|
|
1833
|
+
machine?: ExternalCliMachineStatus;
|
|
1798
1834
|
}
|
|
1799
1835
|
|
|
1800
1836
|
export interface AsyncStatus {
|
|
@@ -1927,8 +1963,7 @@ export interface AsyncStatus {
|
|
|
1927
1963
|
thinking?: string;
|
|
1928
1964
|
contextLimit?: number;
|
|
1929
1965
|
thinkingCeiling?: ThinkingLevel;
|
|
1930
|
-
|
|
1931
|
-
modelAttempts?: ModelAttempt[];
|
|
1966
|
+
requestedModel?: string;
|
|
1932
1967
|
/** True when the child input exceeded the model context window. */
|
|
1933
1968
|
contextOverflow?: boolean;
|
|
1934
1969
|
totalCost?: CostSummary;
|
|
@@ -2069,7 +2104,7 @@ export interface ForegroundResumeChild {
|
|
|
2069
2104
|
/** Private bounded launch fields needed to preserve the child contract on resume. */
|
|
2070
2105
|
resumeContract?: {
|
|
2071
2106
|
modelResponseAliases?: Record<string, string[]>;
|
|
2072
|
-
outputSchema?: JsonSchemaObject;
|
|
2107
|
+
outputSchema?: JsonSchemaObject | false;
|
|
2073
2108
|
agentContract?: AgentContract;
|
|
2074
2109
|
acceptance?: AcceptanceInput;
|
|
2075
2110
|
output?: string | boolean;
|
|
@@ -2078,6 +2113,7 @@ export interface ForegroundResumeChild {
|
|
|
2078
2113
|
launchContractDigest?: string;
|
|
2079
2114
|
/** Private retained launch authority. Never project into status or result output. */
|
|
2080
2115
|
extensionBindings?: ExtensionBindings;
|
|
2116
|
+
requiredExtensions?: RequiredChildExtensionSnapshot;
|
|
2081
2117
|
launchResolvedExtensions?: LaunchResolvedChildExtensions;
|
|
2082
2118
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
|
|
2083
2119
|
execution?: ExecutionProjection;
|
|
@@ -2255,8 +2291,8 @@ export interface SubagentState {
|
|
|
2255
2291
|
lastUiContext: ExtensionContext | null;
|
|
2256
2292
|
poller: NodeJS.Timeout | null;
|
|
2257
2293
|
completionSeen: Map<string, number>;
|
|
2258
|
-
/**
|
|
2259
|
-
completedResults?: Map<string, { seenAt: number; completion: WaitCompletion }>;
|
|
2294
|
+
/** Session-owned terminal result payloads observed by the result watcher, keyed by run id and pruned by the completion TTL. */
|
|
2295
|
+
completedResults?: Map<string, { sessionId: string; seenAt: number; completion: WaitCompletion }>;
|
|
2260
2296
|
watcher: FSWatcher | null;
|
|
2261
2297
|
watcherRestartTimer: ReturnType<typeof setTimeout> | null;
|
|
2262
2298
|
resultFileCoalescer: {
|
|
@@ -2359,6 +2395,8 @@ export interface RunSyncOptions {
|
|
|
2359
2395
|
unknownAgentDiagnosticContext?: import("../agents/agents.ts").UnknownAgentDiagnosticContext;
|
|
2360
2396
|
/** Session factory for the in-process child; defaults to the process-wide factory. */
|
|
2361
2397
|
childSessionFactory?: import("../runs/shared/child-session.ts").ChildSessionFactory;
|
|
2398
|
+
/** Invoking parent registry inherited only by its local foreground launch. */
|
|
2399
|
+
parentProviderRegistry?: import("../runs/shared/child-session.ts").ParentProviderRegistry;
|
|
2362
2400
|
/** The launching executor's own child runtime when it is itself an in-process child. */
|
|
2363
2401
|
childRuntime?: import("../runs/shared/child-runtime-config.ts").ChildRuntimeConfig;
|
|
2364
2402
|
/** Fires once the child session exists and can be steered. */
|
|
@@ -2370,6 +2408,10 @@ export interface RunSyncOptions {
|
|
|
2370
2408
|
/** Resolved launch context for this child. */
|
|
2371
2409
|
context?: "fresh" | "fork";
|
|
2372
2410
|
cwd?: string;
|
|
2411
|
+
/** Resolved pane-native saved-machine placement. */
|
|
2412
|
+
machine?: HerdrMachineReference;
|
|
2413
|
+
/** Explicit read override resolved by the remote ambient agent profile. */
|
|
2414
|
+
remoteReads?: string[] | false;
|
|
2373
2415
|
/** Original cwd input retained for launch diagnostics. */
|
|
2374
2416
|
requestedCwd?: string;
|
|
2375
2417
|
signal?: AbortSignal;
|
|
@@ -2430,6 +2472,7 @@ export interface RunSyncOptions {
|
|
|
2430
2472
|
/** Override the agent's default thinking level for this run */
|
|
2431
2473
|
thinkingOverride?: AgentConfig["thinking"];
|
|
2432
2474
|
thinkingCeiling?: ThinkingLevel;
|
|
2475
|
+
requiredExtensions?: RequiredChildExtensionSnapshot;
|
|
2433
2476
|
extensionBindings?: ExtensionBindings;
|
|
2434
2477
|
/** Package-internal one-use authorization for one foreground workflow child. */
|
|
2435
2478
|
workflowChildPermitLaunch?: WorkflowChildPermitContext;
|
|
@@ -2440,7 +2483,9 @@ export interface RunSyncOptions {
|
|
|
2440
2483
|
preferredModelProvider?: string;
|
|
2441
2484
|
/** Parent Pi event host used to snapshot runtime-registered MCP servers before child launch. */
|
|
2442
2485
|
runtimeSnapshotHost?: import("../runs/shared/mcp-direct-tool-allowlist.ts").McpRuntimeSnapshotHost;
|
|
2443
|
-
/**
|
|
2486
|
+
/** Builtin tool names the host runtime provides; used to intersect agent-declared tools. */
|
|
2487
|
+
hostAvailableBuiltins?: readonly string[];
|
|
2488
|
+
/** Optional subagent model-scope enforcement. */
|
|
2444
2489
|
modelScope?: ModelScopeRule | ModelScopeRule[];
|
|
2445
2490
|
/** Skills to make available (overrides agent default if provided) */
|
|
2446
2491
|
skills?: string[];
|
|
@@ -2502,11 +2547,6 @@ export interface ScheduledRunsConfig {
|
|
|
2502
2547
|
storeRoot?: string;
|
|
2503
2548
|
}
|
|
2504
2549
|
|
|
2505
|
-
export interface ModelExclusionsConfig {
|
|
2506
|
-
/** Default duration in milliseconds. A lower configured value also shortens active cached exclusions. */
|
|
2507
|
-
defaultTtlMs?: number;
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
2550
|
export type FleetViewPlacement = "aboveEditor" | "belowEditor";
|
|
2511
2551
|
|
|
2512
2552
|
export const FLEET_KEYBINDING_ACTIONS = [
|
|
@@ -2569,8 +2609,6 @@ export interface ExtensionConfig {
|
|
|
2569
2609
|
fleetKeybindings?: FleetKeybindingsConfig;
|
|
2570
2610
|
/** Show the under-editor async runs widget. Defaults to true, including when FleetView is enabled. */
|
|
2571
2611
|
asyncWidget?: boolean;
|
|
2572
|
-
/** Configure the process-wide TTL policy for persisted model exclusions. */
|
|
2573
|
-
modelExclusions?: ModelExclusionsConfig;
|
|
2574
2612
|
/** Exact provider/model candidates mapped to operator-declared equivalent response IDs. Empty arrays add no accepted IDs. */
|
|
2575
2613
|
modelResponseAliases?: Record<string, string[]>;
|
|
2576
2614
|
/** Tool description variant registered for the parent-facing subagent tool. Defaults to split metadata. */
|
|
@@ -2615,6 +2653,12 @@ export interface ExtensionConfig {
|
|
|
2615
2653
|
* are rejected with an error.
|
|
2616
2654
|
*/
|
|
2617
2655
|
toolTimeoutMs?: number;
|
|
2656
|
+
/**
|
|
2657
|
+
* Global default for the async single-agent `checkpointBeforeDeadlineMs` launch option: the runner requests that
|
|
2658
|
+
* the child checkpoint and stop this many milliseconds before its run deadline (best-effort). The call param wins; values that
|
|
2659
|
+
* leave no run time before the checkpoint disarm it.
|
|
2660
|
+
*/
|
|
2661
|
+
checkpointBeforeDeadlineMs?: number;
|
|
2618
2662
|
control?: ControlConfig;
|
|
2619
2663
|
completionBatch?: CompletionBatchConfig;
|
|
2620
2664
|
toolBudget?: ToolBudgetConfig;
|
|
@@ -2754,7 +2798,7 @@ export const POLL_INTERVAL_MS = 250;
|
|
|
2754
2798
|
export const WIDGET_ANIMATION_INTERVAL_MS = 1000;
|
|
2755
2799
|
export const MAX_WIDGET_JOBS = 4;
|
|
2756
2800
|
export const DEFAULT_SUBAGENT_MAX_DEPTH = 2;
|
|
2757
|
-
export const SUBAGENT_ACTIONS = ["list", "get", "models", "children.list", "guide", "validate", "create", "update", "delete", "eject", "disable", "enable", "reset", "mission.create", "mission.list", "mission.show", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "worktree.discard", "worktree.cleanup", "lane.status", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.show", "refine.rollback", "inspector.open", "inspector.status", "inspector.close", "project.open", "project.status", "project.close", "status", "debug.run", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "doctor", "watchdog.status", "watchdog.check", "watchdog.configure", "watchdog.recommend-model", "schedule.create", "schedule.list", "schedule.show", "schedule.history", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"] as const;
|
|
2801
|
+
export const SUBAGENT_ACTIONS = ["list", "get", "models", "children.list", "guide", "validate", "create", "update", "delete", "eject", "disable", "enable", "reset", "mission.create", "mission.list", "mission.show", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "worktree.discard", "worktree.cleanup", "lane.status", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.show", "refine.rollback", "inspector.open", "inspector.command", "inspector.status", "inspector.close", "project.open", "project.status", "project.close", "status", "debug.run", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "doctor", "watchdog.status", "watchdog.check", "watchdog.configure", "watchdog.recommend-model", "schedule.create", "schedule.list", "schedule.show", "schedule.history", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"] as const;
|
|
2758
2802
|
|
|
2759
2803
|
export const DEFAULT_FORK_PREAMBLE =
|
|
2760
2804
|
"You are a delegated subagent running from a fork of the parent session. " +
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type SubagentDelegationUpdate,
|
|
7
7
|
type SubagentDelegationValue,
|
|
8
8
|
} from "../api/delegation.ts";
|
|
9
|
-
import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, JsonSchemaObject, ReviewProjection, ToolBudgetConfig, Usage } from "../shared/types.ts";
|
|
9
|
+
import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, IntercomBridgeConfig, JsonSchemaObject, ReviewProjection, ToolBudgetConfig, Usage } from "../shared/types.ts";
|
|
10
10
|
import { cloneJsonWithinByteLimit } from "./delegation-json.ts";
|
|
11
11
|
|
|
12
12
|
export interface PromptTemplateDelegationRequest {
|
|
@@ -127,6 +127,7 @@ export interface DelegatedSubagentExecutionParams {
|
|
|
127
127
|
agentContract?: AgentContract;
|
|
128
128
|
acceptance?: AcceptanceInput;
|
|
129
129
|
artifacts?: boolean;
|
|
130
|
+
intercomBridge?: IntercomBridgeConfig;
|
|
130
131
|
/** Internal-only thinking override accepted by executeDelegated. */
|
|
131
132
|
delegatedThinkingOverride?: SubagentDelegationThinking;
|
|
132
133
|
/** Internal-only capability accepted and stripped by executeDelegated. */
|
|
@@ -295,6 +296,7 @@ export function toSubagentDelegationExecutionParams(request: SubagentDelegationR
|
|
|
295
296
|
...(request.result.kind === "structured" ? { outputSchema: request.result.schema } : {}),
|
|
296
297
|
acceptance: false,
|
|
297
298
|
artifacts: request.artifacts,
|
|
299
|
+
...(request.intercomBridge !== undefined ? { intercomBridge: request.intercomBridge } : {}),
|
|
298
300
|
delegatedThinkingOverride: request.thinking,
|
|
299
301
|
delegatedAllowZeroToolBudget: true,
|
|
300
302
|
async: false,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type SubagentDelegationRequest,
|
|
3
3
|
} from "../api/delegation.ts";
|
|
4
|
+
import { validateIntercomBridgeConfig } from "../intercom/intercom-bridge.ts";
|
|
4
5
|
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
|
|
6
|
+
import type { IntercomBridgeConfig } from "../shared/types.ts";
|
|
5
7
|
import { cloneJsonWithinByteLimit } from "./delegation-json.ts";
|
|
6
8
|
|
|
7
9
|
export type SubagentDelegationParseResult =
|
|
@@ -22,6 +24,7 @@ const supportedFields = new Set([
|
|
|
22
24
|
"toolBudget",
|
|
23
25
|
"skill",
|
|
24
26
|
"artifacts",
|
|
27
|
+
"intercomBridge",
|
|
25
28
|
"result",
|
|
26
29
|
]);
|
|
27
30
|
|
|
@@ -97,6 +100,15 @@ export function parseSubagentDelegationRequest(data: unknown): SubagentDelegatio
|
|
|
97
100
|
if (value.artifacts !== undefined && typeof value.artifacts !== "boolean") {
|
|
98
101
|
return { ok: false, ...identity, error: "artifacts must be a boolean." };
|
|
99
102
|
}
|
|
103
|
+
let intercomBridge: IntercomBridgeConfig | undefined;
|
|
104
|
+
if (value.intercomBridge !== undefined) {
|
|
105
|
+
const bridge = validateIntercomBridgeConfig({ value: value.intercomBridge, label: "intercomBridge" });
|
|
106
|
+
if (!bridge.ok) return { ok: false, ...identity, error: bridge.error };
|
|
107
|
+
if (typeof bridge.value.instructionFile === "string" && Buffer.byteLength(bridge.value.instructionFile, "utf8") > MAX_SHORT_TEXT_BYTES) {
|
|
108
|
+
return { ok: false, ...identity, error: "intercomBridge.instructionFile exceeds 1 KiB when UTF-8 encoded." };
|
|
109
|
+
}
|
|
110
|
+
intercomBridge = bridge.value;
|
|
111
|
+
}
|
|
100
112
|
if (Buffer.byteLength(value.task as string, "utf8") > MAX_TASK_BYTES) {
|
|
101
113
|
return { ok: false, ...identity, error: "Delegation task exceeds 1 MiB when UTF-8 encoded." };
|
|
102
114
|
}
|
|
@@ -154,6 +166,8 @@ export function parseSubagentDelegationRequest(data: unknown): SubagentDelegatio
|
|
|
154
166
|
ok: true,
|
|
155
167
|
request: {
|
|
156
168
|
...value,
|
|
169
|
+
// The validated copy replaces the caller's object so the request never aliases untrusted input.
|
|
170
|
+
...(intercomBridge ? { intercomBridge } : {}),
|
|
157
171
|
result: structuredSchema
|
|
158
172
|
? { kind: "structured", schema: structuredSchema }
|
|
159
173
|
: { kind: "text" },
|
|
@@ -25,12 +25,12 @@ import { resolveAsyncStatusChild } from "../runs/shared/child-identity.ts";
|
|
|
25
25
|
import { readStatus } from "../shared/utils.ts";
|
|
26
26
|
import { getArtifactPaths, getArtifactsDir } from "../shared/artifacts.ts";
|
|
27
27
|
import { readWorkflowReceipt } from "../workflows/workflow-receipt.ts";
|
|
28
|
-
import { FLEET_OPEN_SHORTCUT } from "../shared/shortcuts.ts";
|
|
29
28
|
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
|
|
30
29
|
import { registerPromptWorkflowCommands } from "./prompt-workflows.ts";
|
|
31
30
|
import { openSubagentsAdmin } from "./subagents-admin.ts";
|
|
32
31
|
import { SUBAGENT_GUIDE_TOPICS } from "../extension/subagent-guide.ts";
|
|
33
32
|
import { openSubagentFleet } from "../tui/fleet.ts";
|
|
33
|
+
import { createBuiltinInspectorPlugins } from "../inspectors/plugins.ts";
|
|
34
34
|
import {
|
|
35
35
|
applySlashUpdate,
|
|
36
36
|
buildSlashInitialResult,
|
|
@@ -860,7 +860,7 @@ export function registerSlashCommands(
|
|
|
860
860
|
}
|
|
861
861
|
fleetOpen = true;
|
|
862
862
|
try {
|
|
863
|
-
await openSubagentFleet(ctx, state, { asyncDirRoot: DIRS.async, resultsDir: DIRS.results, fleetKeybindings: options.fleetKeybindings });
|
|
863
|
+
await openSubagentFleet(ctx, state, { asyncDirRoot: DIRS.async, inspectorPlugins: createBuiltinInspectorPlugins(), resultsDir: DIRS.results, fleetKeybindings: options.fleetKeybindings });
|
|
864
864
|
} finally {
|
|
865
865
|
fleetOpen = false;
|
|
866
866
|
}
|
|
@@ -975,11 +975,6 @@ export function registerSlashCommands(
|
|
|
975
975
|
handler: async (_args, ctx) => showFleet(ctx),
|
|
976
976
|
});
|
|
977
977
|
|
|
978
|
-
pi.registerShortcut(FLEET_OPEN_SHORTCUT, {
|
|
979
|
-
description: "Open subagent fleet inspector",
|
|
980
|
-
handler: async (ctx) => showFleet(ctx),
|
|
981
|
-
});
|
|
982
|
-
|
|
983
978
|
const detachForegroundRun = (args: string, ctx: ExtensionContext): void => {
|
|
984
979
|
const id = args.trim();
|
|
985
980
|
let control: ReturnType<typeof selectForegroundDetachControl>;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type BuiltinAgentOverrideBase,
|
|
12
12
|
} from "../agents/agents.ts";
|
|
13
13
|
import { serializeAgent } from "../agents/agent-serializer.ts";
|
|
14
|
+
import { mergeRuntimeAgents, type RuntimeAgentOwner } from "../agents/runtime-agent-registry.ts";
|
|
14
15
|
import { editableAgentConfig, preservedAgentFrontmatterFields } from "../agents/agent-management.ts";
|
|
15
16
|
import { findModelInfo, getSupportedThinkingLevels, toModelInfo } from "../shared/model-info.ts";
|
|
16
17
|
import { SelectorComponent, type SelectorItem, type SelectorResult } from "./selector.ts";
|
|
@@ -28,11 +29,13 @@ function sourceRank(source: AgentConfig["source"]): number {
|
|
|
28
29
|
return 3;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
function allVisibleAgents(cwd: string): AgentConfig[] {
|
|
32
|
+
function allVisibleAgents(pi: RuntimeAgentOwner, cwd: string): AgentConfig[] {
|
|
32
33
|
const d = discoverAgentsAll(cwd);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const allConfigured = [...d.project, ...d.user, ...d.package, ...d.builtin];
|
|
35
|
+
const visibleConfigured = allConfigured.filter((agent) => !agent.disabled);
|
|
36
|
+
// Disabled definitions remain in collision checks even though the panel hides them.
|
|
37
|
+
const agents = mergeRuntimeAgents(pi, { agents: visibleConfigured }, allConfigured).agents;
|
|
38
|
+
return agents.sort((a, b) => a.name.localeCompare(b.name) || sourceRank(a.source) - sourceRank(b.source));
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
function agentLabel(agent: AgentConfig): string {
|
|
@@ -71,9 +74,16 @@ function modelFullId(model: ModelInfo): string {
|
|
|
71
74
|
return `${model.provider}/${model.id}`;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
function liveAvailableModels(ctx: ExtensionContext) {
|
|
77
|
+
async function liveAvailableModels(ctx: ExtensionContext) {
|
|
75
78
|
try {
|
|
76
|
-
|
|
79
|
+
// Reload local configuration and cached catalogs without network discovery on picker open.
|
|
80
|
+
const result = await ctx.modelRegistry.refresh?.({ allowNetwork: false, signal: AbortSignal.timeout(5_000) });
|
|
81
|
+
const firstError = result?.errors.entries().next().value;
|
|
82
|
+
if (firstError) {
|
|
83
|
+
ctx.ui.notify(`Could not refresh ${firstError[0]}; using the currently loaded choices. ${firstError[1].message}`, "warning");
|
|
84
|
+
} else if (result?.aborted) {
|
|
85
|
+
ctx.ui.notify("Model registry refresh timed out; using the currently loaded choices.", "warning");
|
|
86
|
+
}
|
|
77
87
|
} catch (error) {
|
|
78
88
|
const message = error instanceof Error ? error.message : String(error);
|
|
79
89
|
ctx.ui.notify(`Could not refresh the model registry; using the last loaded choices. ${message}`, "warning");
|
|
@@ -84,7 +94,6 @@ function liveAvailableModels(ctx: ExtensionContext) {
|
|
|
84
94
|
function buildBuiltinBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
85
95
|
return {
|
|
86
96
|
...(agent.model !== undefined ? { model: agent.model } : {}),
|
|
87
|
-
...(agent.fallbackModels !== undefined ? { fallbackModels: [...agent.fallbackModels] } : {}),
|
|
88
97
|
...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
|
|
89
98
|
systemPromptMode: agent.systemPromptMode,
|
|
90
99
|
inheritProjectContext: agent.inheritProjectContext,
|
|
@@ -139,6 +148,9 @@ function isReadOnlyExtraAgent(agent: AgentConfig): boolean {
|
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
function readOnlyAgentMessage(agent: AgentConfig, field: EditableOverrideField): string | undefined {
|
|
151
|
+
if (agent.source === "runtime") {
|
|
152
|
+
return `Cannot update '${agent.name}' ${field} because that agent is runtime-registered by an extension; edit its source definition instead.`;
|
|
153
|
+
}
|
|
142
154
|
if (agent.source === "package") {
|
|
143
155
|
return `Cannot update '${agent.name}' ${field} because that field is owned by its read-only package definition.`;
|
|
144
156
|
}
|
|
@@ -147,8 +159,8 @@ function readOnlyAgentMessage(agent: AgentConfig, field: EditableOverrideField):
|
|
|
147
159
|
: undefined;
|
|
148
160
|
}
|
|
149
161
|
|
|
150
|
-
async function selectAgent(ctx: ExtensionContext, args: string): Promise<AgentSelection> {
|
|
151
|
-
const agents = allVisibleAgents(ctx.cwd);
|
|
162
|
+
async function selectAgent(pi: RuntimeAgentOwner, ctx: ExtensionContext, args: string): Promise<AgentSelection> {
|
|
163
|
+
const agents = allVisibleAgents(pi, ctx.cwd);
|
|
152
164
|
const requestedName = args.trim().split(/\s+/)[0] ?? "";
|
|
153
165
|
if (agents.length === 0) return { kind: "not-found", agents, requestedName: requestedName || undefined };
|
|
154
166
|
|
|
@@ -182,7 +194,6 @@ function metadataFor(agent: AgentConfig): string {
|
|
|
182
194
|
lines.push(`Package: ${agent.packageName}`);
|
|
183
195
|
}
|
|
184
196
|
lines.push(`Model: ${agent.model ?? "default / inherit"}`);
|
|
185
|
-
if (agent.fallbackModels?.length) lines.push(`Fallback models: ${agent.fallbackModels.join(", ")}`);
|
|
186
197
|
if (agent.thinking !== undefined) lines.push(`Thinking: ${agent.thinking === false ? "off" : agent.thinking}`);
|
|
187
198
|
if (tools.length) lines.push(`Tools: ${tools.join(", ")}`);
|
|
188
199
|
if (agent.excludeTools?.length) lines.push(`Excluded tools: ${agent.excludeTools.join(", ")}`);
|
|
@@ -217,7 +228,7 @@ async function selectFromList(ctx: ExtensionContext, title: string, subtitle: st
|
|
|
217
228
|
}
|
|
218
229
|
|
|
219
230
|
async function chooseModel(ctx: ExtensionContext, agent: AgentConfig): Promise<string | undefined | null> {
|
|
220
|
-
const models = liveAvailableModels(ctx);
|
|
231
|
+
const models = await liveAvailableModels(ctx);
|
|
221
232
|
const current = agent.model ?? INHERIT_MODEL_CHOICE;
|
|
222
233
|
const items: SelectorItem[] = [{ value: INHERIT_MODEL_CHOICE, label: INHERIT_MODEL_CHOICE, current: !agent.model }];
|
|
223
234
|
if (agent.model && !models.some((model) => modelFullId(model) === agent.model)) {
|
|
@@ -233,7 +244,7 @@ async function chooseModel(ctx: ExtensionContext, agent: AgentConfig): Promise<s
|
|
|
233
244
|
}
|
|
234
245
|
|
|
235
246
|
async function chooseThinking(ctx: ExtensionContext, agent: AgentConfig): Promise<string | undefined | null> {
|
|
236
|
-
const availableModels = liveAvailableModels(ctx).map(toModelInfo);
|
|
247
|
+
const availableModels = (await liveAvailableModels(ctx)).map(toModelInfo);
|
|
237
248
|
const effectiveModel = agent.model ?? (ctx.model ? modelFullId(ctx.model) : undefined);
|
|
238
249
|
const modelInfo = findModelInfo(effectiveModel, availableModels, ctx.model?.provider);
|
|
239
250
|
const levels = getSupportedThinkingLevels(modelInfo);
|
|
@@ -383,7 +394,7 @@ async function editSystemPrompt(ctx: ExtensionContext, agent: AgentConfig): Prom
|
|
|
383
394
|
}
|
|
384
395
|
|
|
385
396
|
export async function openSubagentsAdmin(pi: ExtensionAPI, ctx: ExtensionContext, args = ""): Promise<void> {
|
|
386
|
-
const selection = await selectAgent(ctx, args);
|
|
397
|
+
const selection = await selectAgent(pi, ctx, args);
|
|
387
398
|
if (selection.kind === "cancelled") return;
|
|
388
399
|
if (selection.kind === "ambiguous") {
|
|
389
400
|
sendAdminMessage(pi, `Subagent '${selection.requestedName}' is ambiguous. Choose a scope in interactive mode:\n${selection.matches.map((agent) => `- ${agent.source}: ${agent.filePath}`).join("\n")}`);
|