pi-subagents 0.40.0 → 0.42.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 +97 -0
- package/README.md +54 -1879
- package/agents/oracle.md +1 -0
- package/inspector-runner.mjs +11 -0
- package/package.json +13 -5
- package/prompts/parallel-context-build.md +1 -1
- package/prompts/parallel-handoff-plan.md +1 -1
- package/prompts/review-loop.md +1 -1
- package/skills/pi-subagents/SKILL.md +9 -7
- package/skills/pi-subagents/references/constraints-and-recipes.md +24 -32
- package/skills/pi-subagents/references/execution-controls.md +99 -97
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +23 -30
- package/src/agents/agent-management.ts +155 -65
- package/src/agents/agent-serializer.ts +19 -0
- package/src/agents/agents.ts +154 -71
- package/src/agents/chain-serializer.ts +10 -7
- package/src/agents/frontmatter.ts +5 -3
- package/src/agents/identity.ts +1 -1
- package/src/agents/proactive-skills.ts +13 -10
- package/src/agents/skills.ts +23 -6
- package/src/api/control-channel.ts +4 -0
- package/src/api/delegation.ts +26 -194
- package/src/api/external-runs.ts +129 -0
- package/src/api/intercom-bridge.ts +3 -0
- package/src/api/pi-args.ts +5 -0
- package/src/api/preflight.ts +3 -3
- package/src/api/shared-types.ts +19 -0
- package/src/extension/config.ts +10 -0
- package/src/extension/control-notices.ts +5 -39
- package/src/extension/doctor.ts +10 -9
- package/src/extension/fanout-child.ts +7 -4
- package/src/extension/index.ts +232 -68
- package/src/extension/rpc.ts +18 -12
- package/src/extension/schemas.ts +48 -37
- package/src/extension/tool-description.ts +36 -86
- package/src/inspectors/herdr/actions.ts +229 -0
- package/src/inspectors/herdr/client.ts +130 -0
- package/src/inspectors/herdr/inspector-runner.ts +141 -0
- package/src/inspectors/herdr/project-panes.ts +154 -0
- package/src/integrations/herdr-status.ts +330 -0
- package/src/intercom/intercom-bridge.ts +3 -2
- package/src/intercom/result-intercom.ts +5 -1
- package/src/missions/actions.ts +374 -0
- package/src/missions/lifecycle.ts +314 -0
- package/src/missions/store.ts +442 -0
- package/src/missions/types.ts +135 -0
- package/src/policy/authority.ts +46 -0
- package/src/profiles/profiles.ts +29 -3
- package/src/runs/background/async-execution.ts +110 -50
- package/src/runs/background/async-job-tracker.ts +27 -4
- package/src/runs/background/async-resume.ts +6 -6
- package/src/runs/background/async-status.ts +29 -1
- package/src/runs/background/auto-drain.ts +3 -3
- package/src/runs/background/chain-append.ts +3 -2
- package/src/runs/background/control-channel.ts +9 -7
- package/src/runs/background/fleet-view.ts +3 -4
- package/src/runs/background/notify.ts +2 -1
- package/src/runs/background/process-terminal.ts +5 -5
- package/src/runs/background/result-watcher.ts +13 -5
- package/src/runs/background/run-id-resolver.ts +3 -3
- package/src/runs/background/run-status.ts +35 -8
- package/src/runs/background/scheduled-runs.ts +602 -375
- package/src/runs/background/stale-run-reconciler.ts +3 -3
- package/src/runs/background/subagent-runner.ts +608 -445
- package/src/runs/background/subagent-wait.ts +50 -9
- package/src/runs/background/wait-subscriptions.ts +253 -0
- package/src/runs/background/wait-tool.ts +12 -4
- package/src/runs/foreground/async-steering-action.ts +3 -3
- package/src/runs/foreground/chain-clarify.ts +8 -4
- package/src/runs/foreground/chain-execution.ts +56 -30
- package/src/runs/foreground/execution.ts +34 -9
- package/src/runs/foreground/subagent-executor.ts +1036 -274
- package/src/runs/shared/acceptance.ts +28 -6
- package/src/runs/shared/child-protocol.ts +302 -22
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/external-cli-runner.ts +130 -0
- package/src/runs/shared/long-running-guard.ts +42 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +2 -0
- package/src/runs/shared/nested-events.ts +59 -5
- package/src/runs/shared/nested-render.ts +9 -4
- package/src/runs/shared/parallel-handoff.ts +86 -2
- package/src/runs/shared/parallel-utils.ts +11 -2
- package/src/runs/shared/permissions.ts +95 -0
- package/src/runs/shared/pi-args.ts +468 -109
- package/src/runs/shared/pi-spawn.ts +11 -1
- package/src/runs/shared/run-history.ts +1 -1
- package/src/runs/shared/subagent-prompt-runtime.ts +36 -5
- package/src/runs/shared/subagent-startup-retry.ts +5 -2
- package/src/runs/shared/turn-budget.ts +6 -6
- package/src/runs/shared/worktree.ts +122 -12
- package/src/shared/accessible-dir.ts +29 -7
- package/src/shared/artifacts.ts +143 -1
- package/src/shared/fork-context.ts +3 -2
- package/src/shared/launch-contract.ts +1 -0
- package/src/shared/settings.ts +10 -0
- package/src/shared/types.ts +156 -14
- package/src/shared/utils.ts +8 -6
- package/src/slash/delegation-adapters.ts +32 -194
- package/src/slash/delegation-request.ts +43 -126
- package/src/slash/prompt-template-bridge.ts +158 -205
- package/src/slash/prompt-workflows.ts +21 -57
- package/src/slash/slash-bridge.ts +14 -0
- package/src/slash/slash-commands.ts +31 -632
- package/src/slash/subagents-admin.ts +18 -14
- package/src/tui/fleet-status.ts +156 -21
- package/src/tui/fleet-transcript.ts +110 -5
- package/src/tui/fleet.ts +57 -25
- package/src/tui/render.ts +368 -152
- package/src/types/pi-runtime-compat.d.ts +8 -0
- package/src/watchdog/lsp-diagnostics.ts +12 -7
- package/src/watchdog/model-selection.ts +2 -2
- package/src/watchdog/permission-arbiter.ts +145 -0
- package/src/watchdog/register-child.ts +1 -1
- package/src/watchdog/register-main.ts +1 -1
- package/src/watchdog/review.ts +4 -1
- package/src/watchdog/runtime.ts +3 -2
- package/src/workflows/chat-progress.ts +140 -0
- package/src/workflows/scripted-workflow.ts +415 -0
- package/agents/advisor.md +0 -73
- package/src/extension/chain-validation.ts +0 -181
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SUBAGENT_DELEGATION_CANCEL_EVENT,
|
|
3
|
-
SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
4
|
-
SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
5
3
|
SUBAGENT_DELEGATION_REQUEST_EVENT,
|
|
6
4
|
SUBAGENT_DELEGATION_RESPONSE_EVENT,
|
|
7
5
|
SUBAGENT_DELEGATION_STARTED_EVENT,
|
|
8
6
|
SUBAGENT_DELEGATION_UPDATE_EVENT,
|
|
7
|
+
type SubagentDelegationInvalidResponse,
|
|
9
8
|
type SubagentDelegationRequest,
|
|
10
9
|
type SubagentDelegationResponse,
|
|
11
|
-
type SubagentDelegationV2InvalidResponse,
|
|
12
|
-
type SubagentDelegationV2Request,
|
|
13
|
-
type SubagentDelegationV2Response,
|
|
14
10
|
} from "../api/delegation.ts";
|
|
15
11
|
import { parseSubagentDelegationRequest } from "./delegation-request.ts";
|
|
16
12
|
import {
|
|
@@ -21,9 +17,6 @@ import {
|
|
|
21
17
|
toSubagentDelegationExecutionParams,
|
|
22
18
|
toSubagentDelegationResponse,
|
|
23
19
|
toSubagentDelegationUpdate,
|
|
24
|
-
toSubagentDelegationV2ExecutionParams,
|
|
25
|
-
toSubagentDelegationV2Response,
|
|
26
|
-
toSubagentDelegationV2Update,
|
|
27
20
|
type DelegatedSubagentExecutionParams,
|
|
28
21
|
type PromptTemplateBridgeResult,
|
|
29
22
|
type PromptTemplateDelegationRequest,
|
|
@@ -51,11 +44,8 @@ interface PromptTemplateBridgeOptions<Ctx extends { cwd?: string }> {
|
|
|
51
44
|
ctx: Ctx,
|
|
52
45
|
onUpdate: (result: PromptTemplateBridgeResult) => void,
|
|
53
46
|
) => Promise<PromptTemplateBridgeResult>;
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
* Non-versioned prompt-template requests retain the ordinary single-dispatch guard.
|
|
57
|
-
*/
|
|
58
|
-
executeVersioned?: (
|
|
47
|
+
/** Concurrent-safe executor for structured delegation requests. */
|
|
48
|
+
executeStructured?: (
|
|
59
49
|
requestId: string,
|
|
60
50
|
params: DelegatedSubagentExecutionParams,
|
|
61
51
|
signal: AbortSignal,
|
|
@@ -64,32 +54,43 @@ interface PromptTemplateBridgeOptions<Ctx extends { cwd?: string }> {
|
|
|
64
54
|
) => Promise<PromptTemplateBridgeResult>;
|
|
65
55
|
}
|
|
66
56
|
|
|
57
|
+
function hasStructuredDelegationMarker(data: unknown): boolean {
|
|
58
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return false;
|
|
59
|
+
const value = data as Record<string, unknown>;
|
|
60
|
+
return Object.hasOwn(value, "ownerRunId")
|
|
61
|
+
|| Object.hasOwn(value, "nodeId")
|
|
62
|
+
|| Object.hasOwn(value, "result")
|
|
63
|
+
|| Object.hasOwn(value, "version");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validId(value: unknown): value is string {
|
|
67
|
+
return typeof value === "string" && value.trim().length > 0 && value.length <= 256 && !/[\r\n]/.test(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
67
70
|
export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: string }>(
|
|
68
71
|
options: PromptTemplateBridgeOptions<Ctx>,
|
|
69
72
|
): {
|
|
70
73
|
cancelAll: () => void;
|
|
71
74
|
dispose: () => void;
|
|
72
75
|
} {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const activeV2Nodes = new Map<string, { attemptKey: string; controller: AbortController }>();
|
|
80
|
-
const settledV2Attempts = new Map<string, true>();
|
|
76
|
+
const legacyControllers = new Map<string, AbortController>();
|
|
77
|
+
const pendingLegacyCancels = new Map<string, true>();
|
|
78
|
+
const attemptControllers = new Map<string, AbortController>();
|
|
79
|
+
const pendingAttemptCancels = new Map<string, true>();
|
|
80
|
+
const activeOwnedNodes = new Map<string, { attemptKey: string; controller: AbortController }>();
|
|
81
|
+
const settledAttempts = new Map<string, true>();
|
|
81
82
|
const subscriptions: Array<() => void> = [];
|
|
82
83
|
let disposed = false;
|
|
83
|
-
let
|
|
84
|
+
let identitySaturated = false;
|
|
84
85
|
|
|
85
86
|
const subscribe = (event: string, handler: (data: unknown) => void): void => {
|
|
86
87
|
const unsubscribe = options.events.on(event, handler);
|
|
87
88
|
if (typeof unsubscribe === "function") subscriptions.push(unsubscribe);
|
|
88
89
|
};
|
|
89
|
-
const
|
|
90
|
-
!disposed &&
|
|
91
|
-
const
|
|
92
|
-
!disposed &&
|
|
90
|
+
const ownsLegacyRequest = (requestId: string, controller: AbortController): boolean =>
|
|
91
|
+
!disposed && legacyControllers.get(requestId) === controller;
|
|
92
|
+
const ownsAttempt = (attemptKey: string, controller: AbortController): boolean =>
|
|
93
|
+
!disposed && attemptControllers.get(attemptKey) === controller;
|
|
93
94
|
const boundedRemember = (map: Map<string, true>, key: string): void => {
|
|
94
95
|
map.delete(key);
|
|
95
96
|
map.set(key, true);
|
|
@@ -99,28 +100,27 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
99
100
|
map.delete(oldest);
|
|
100
101
|
}
|
|
101
102
|
};
|
|
102
|
-
const
|
|
103
|
-
if (map.has(key) ||
|
|
103
|
+
const rememberIdentity = (map: Map<string, true>, key: string): void => {
|
|
104
|
+
if (map.has(key) || identitySaturated) return;
|
|
104
105
|
if (map.size >= 8_192) {
|
|
105
|
-
|
|
106
|
+
identitySaturated = true;
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
108
109
|
map.set(key, true);
|
|
109
110
|
if (map.size === 8_192) {
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
v2IdentitySaturated = true;
|
|
111
|
+
// Exact cancellation and terminal-attempt facts are security state, not an
|
|
112
|
+
// LRU cache. Once full, fail closed rather than evicting identity facts.
|
|
113
|
+
identitySaturated = true;
|
|
114
114
|
}
|
|
115
115
|
};
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
boundedRemember(
|
|
116
|
+
const nodeKey = (ownerRunId: string, nodeId: string): string => JSON.stringify([ownerRunId, nodeId]);
|
|
117
|
+
const attemptKey = (requestId: string, ownerRunId: string, nodeId: string): string => JSON.stringify([requestId, ownerRunId, nodeId]);
|
|
118
|
+
const rememberPendingLegacyCancel = (requestId: string): void => {
|
|
119
|
+
boundedRemember(pendingLegacyCancels, requestId);
|
|
120
120
|
};
|
|
121
|
-
const
|
|
122
|
-
if (disposed ||
|
|
123
|
-
|
|
121
|
+
const emitTerminal = (key: string, payload: SubagentDelegationResponse): void => {
|
|
122
|
+
if (disposed || settledAttempts.has(key)) return;
|
|
123
|
+
rememberIdentity(settledAttempts, key);
|
|
124
124
|
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);
|
|
125
125
|
};
|
|
126
126
|
|
|
@@ -128,119 +128,107 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
128
128
|
if (!data || typeof data !== "object" || Array.isArray(data)) return;
|
|
129
129
|
const value = data as Record<string, unknown>;
|
|
130
130
|
const requestId = value.requestId;
|
|
131
|
-
if (
|
|
132
|
-
if (
|
|
133
|
-
if (value.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
else rememberV2Identity(pendingV2Cancels, attemptKey);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (value.version !== SUBAGENT_DELEGATION_PROTOCOL_VERSION) return;
|
|
146
|
-
if (Object.keys(value).some((key) => key !== "version" && key !== "requestId")) return;
|
|
131
|
+
if (!validId(requestId)) return;
|
|
132
|
+
if (hasStructuredDelegationMarker(data)) {
|
|
133
|
+
if (Object.keys(value).some((key) => key !== "requestId" && key !== "ownerRunId" && key !== "nodeId")) return;
|
|
134
|
+
const ownerRunId = value.ownerRunId;
|
|
135
|
+
const nodeId = value.nodeId;
|
|
136
|
+
if (!validId(ownerRunId) || !validId(nodeId)) return;
|
|
137
|
+
const key = attemptKey(requestId, ownerRunId, nodeId);
|
|
138
|
+
const controller = attemptControllers.get(key);
|
|
139
|
+
if (controller) controller.abort();
|
|
140
|
+
else rememberIdentity(pendingAttemptCancels, key);
|
|
141
|
+
return;
|
|
147
142
|
}
|
|
148
|
-
const controller =
|
|
143
|
+
const controller = legacyControllers.get(requestId);
|
|
149
144
|
if (controller) {
|
|
150
145
|
controller.abort();
|
|
151
146
|
return;
|
|
152
147
|
}
|
|
153
|
-
|
|
148
|
+
rememberPendingLegacyCancel(requestId);
|
|
154
149
|
});
|
|
155
150
|
|
|
156
151
|
subscribe(PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT, async (data) => {
|
|
157
|
-
const
|
|
152
|
+
const structuredPayload = hasStructuredDelegationMarker(data);
|
|
158
153
|
let requestId: string;
|
|
159
154
|
let params: DelegatedSubagentExecutionParams;
|
|
160
|
-
let
|
|
161
|
-
let
|
|
162
|
-
let v2Key: string | undefined;
|
|
155
|
+
let structuredRequest: SubagentDelegationRequest | undefined;
|
|
156
|
+
let key: string | undefined;
|
|
163
157
|
let legacyRequest: PromptTemplateDelegationRequest | undefined;
|
|
164
158
|
|
|
165
|
-
if (
|
|
159
|
+
if (structuredPayload) {
|
|
166
160
|
const parsed = parseSubagentDelegationRequest(data);
|
|
167
161
|
if (parsed.ok === false) {
|
|
168
162
|
if (!disposed && parsed.requestId) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
} else {
|
|
182
|
-
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);
|
|
183
|
-
}
|
|
184
|
-
} else if (!controllers.has(parsed.requestId)) {
|
|
185
|
-
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
186
|
-
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
187
|
-
requestId: parsed.requestId,
|
|
188
|
-
status: "invalid_request",
|
|
189
|
-
error: parsed.error,
|
|
190
|
-
} satisfies SubagentDelegationResponse);
|
|
163
|
+
const payload = {
|
|
164
|
+
requestId: parsed.requestId,
|
|
165
|
+
...(parsed.ownerRunId ? { ownerRunId: parsed.ownerRunId } : {}),
|
|
166
|
+
...(parsed.nodeId ? { nodeId: parsed.nodeId } : {}),
|
|
167
|
+
status: "invalid_request",
|
|
168
|
+
error: parsed.error,
|
|
169
|
+
} satisfies SubagentDelegationInvalidResponse;
|
|
170
|
+
if (parsed.ownerRunId && parsed.nodeId) {
|
|
171
|
+
const attemptedKey = attemptKey(parsed.requestId, parsed.ownerRunId, parsed.nodeId);
|
|
172
|
+
if (!attemptControllers.has(attemptedKey)) emitTerminal(attemptedKey, payload);
|
|
173
|
+
} else {
|
|
174
|
+
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);
|
|
191
175
|
}
|
|
192
176
|
}
|
|
193
177
|
return;
|
|
194
178
|
}
|
|
195
|
-
|
|
179
|
+
structuredRequest = parsed.request;
|
|
196
180
|
requestId = parsed.request.requestId;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
v2Key = v2AttemptKey(requestId, parsed.request.ownerRunId, parsed.request.nodeId);
|
|
200
|
-
params = toSubagentDelegationV2ExecutionParams(parsed.request);
|
|
201
|
-
} else {
|
|
202
|
-
params = toSubagentDelegationExecutionParams(parsed.request);
|
|
203
|
-
}
|
|
181
|
+
key = attemptKey(requestId, parsed.request.ownerRunId, parsed.request.nodeId);
|
|
182
|
+
params = toSubagentDelegationExecutionParams(parsed.request);
|
|
204
183
|
} else {
|
|
184
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
185
|
+
const legacy = data as Record<string, unknown>;
|
|
186
|
+
if (legacy.tasks !== undefined || legacy.worktree !== undefined) {
|
|
187
|
+
if (typeof legacy.requestId === "string" && legacy.requestId) {
|
|
188
|
+
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
189
|
+
requestId: legacy.requestId,
|
|
190
|
+
messages: [],
|
|
191
|
+
isError: true,
|
|
192
|
+
errorText: "Legacy prompt-template tasks/worktree orchestration was removed; use workflowScript.",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
205
198
|
legacyRequest = parsePromptTemplateRequest(data);
|
|
206
199
|
if (!legacyRequest) return;
|
|
207
200
|
requestId = legacyRequest.requestId;
|
|
208
201
|
params = toLegacyExecutionParams(legacyRequest);
|
|
209
202
|
}
|
|
210
203
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (pendingV2Cancels.delete(v2Key)) {
|
|
217
|
-
emitV2Terminal(v2Key, {
|
|
218
|
-
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
204
|
+
if (!structuredRequest && legacyControllers.has(requestId)) return;
|
|
205
|
+
if (structuredRequest && key) {
|
|
206
|
+
if (attemptControllers.has(key) || settledAttempts.has(key)) return;
|
|
207
|
+
if (pendingAttemptCancels.delete(key)) {
|
|
208
|
+
emitTerminal(key, {
|
|
219
209
|
requestId,
|
|
220
|
-
ownerRunId:
|
|
221
|
-
nodeId:
|
|
210
|
+
ownerRunId: structuredRequest.ownerRunId,
|
|
211
|
+
nodeId: structuredRequest.nodeId,
|
|
222
212
|
status: "cancelled",
|
|
223
213
|
});
|
|
224
214
|
return;
|
|
225
215
|
}
|
|
226
|
-
if (
|
|
216
|
+
if (identitySaturated) {
|
|
227
217
|
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
228
|
-
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
229
218
|
requestId,
|
|
230
|
-
ownerRunId:
|
|
231
|
-
nodeId:
|
|
219
|
+
ownerRunId: structuredRequest.ownerRunId,
|
|
220
|
+
nodeId: structuredRequest.nodeId,
|
|
232
221
|
status: "unavailable_context",
|
|
233
|
-
error: "Delegation
|
|
234
|
-
} satisfies
|
|
222
|
+
error: "Delegation identity capacity is exhausted for this extension context.",
|
|
223
|
+
} satisfies SubagentDelegationResponse);
|
|
235
224
|
return;
|
|
236
225
|
}
|
|
237
|
-
const active =
|
|
226
|
+
const active = activeOwnedNodes.get(nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId));
|
|
238
227
|
if (active) {
|
|
239
|
-
|
|
240
|
-
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
228
|
+
emitTerminal(key, {
|
|
241
229
|
requestId,
|
|
242
|
-
ownerRunId:
|
|
243
|
-
nodeId:
|
|
230
|
+
ownerRunId: structuredRequest.ownerRunId,
|
|
231
|
+
nodeId: structuredRequest.nodeId,
|
|
244
232
|
status: "duplicate_node",
|
|
245
233
|
});
|
|
246
234
|
return;
|
|
@@ -248,22 +236,14 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
248
236
|
}
|
|
249
237
|
const ctx = options.getContext();
|
|
250
238
|
if (!ctx) {
|
|
251
|
-
if (
|
|
252
|
-
|
|
253
|
-
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
239
|
+
if (structuredRequest && key) {
|
|
240
|
+
emitTerminal(key, {
|
|
254
241
|
requestId,
|
|
255
|
-
ownerRunId:
|
|
256
|
-
nodeId:
|
|
242
|
+
ownerRunId: structuredRequest.ownerRunId,
|
|
243
|
+
nodeId: structuredRequest.nodeId,
|
|
257
244
|
status: "unavailable_context",
|
|
258
245
|
error: "No active extension context for delegated subagent execution.",
|
|
259
246
|
});
|
|
260
|
-
} else if (versionedRequest) {
|
|
261
|
-
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
262
|
-
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
263
|
-
requestId,
|
|
264
|
-
status: "unavailable_context",
|
|
265
|
-
error: "No active extension context for delegated subagent execution.",
|
|
266
|
-
} satisfies SubagentDelegationResponse);
|
|
267
247
|
} else if (legacyRequest) {
|
|
268
248
|
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
269
249
|
...legacyRequest,
|
|
@@ -276,29 +256,22 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
276
256
|
}
|
|
277
257
|
|
|
278
258
|
const controller = new AbortController();
|
|
279
|
-
if (
|
|
280
|
-
|
|
281
|
-
|
|
259
|
+
if (structuredRequest && key) {
|
|
260
|
+
attemptControllers.set(key, controller);
|
|
261
|
+
activeOwnedNodes.set(nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId), { attemptKey: key, controller });
|
|
282
262
|
} else {
|
|
283
|
-
|
|
284
|
-
if (
|
|
263
|
+
legacyControllers.set(requestId, controller);
|
|
264
|
+
if (pendingLegacyCancels.delete(requestId)) controller.abort();
|
|
285
265
|
}
|
|
286
266
|
if (controller.signal.aborted) {
|
|
287
|
-
if (
|
|
288
|
-
|
|
289
|
-
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
267
|
+
if (structuredRequest && key) {
|
|
268
|
+
emitTerminal(key, {
|
|
290
269
|
requestId,
|
|
291
|
-
ownerRunId:
|
|
292
|
-
nodeId:
|
|
270
|
+
ownerRunId: structuredRequest.ownerRunId,
|
|
271
|
+
nodeId: structuredRequest.nodeId,
|
|
293
272
|
status: "cancelled",
|
|
294
273
|
});
|
|
295
|
-
|
|
296
|
-
} else if (versionedRequest) {
|
|
297
|
-
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
298
|
-
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
299
|
-
requestId,
|
|
300
|
-
status: "cancelled",
|
|
301
|
-
} satisfies SubagentDelegationResponse);
|
|
274
|
+
activeOwnedNodes.delete(nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId));
|
|
302
275
|
} else if (legacyRequest) {
|
|
303
276
|
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
304
277
|
...legacyRequest,
|
|
@@ -307,23 +280,21 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
307
280
|
errorText: "Delegated prompt cancelled.",
|
|
308
281
|
} satisfies PromptTemplateDelegationResponse);
|
|
309
282
|
}
|
|
310
|
-
if (
|
|
311
|
-
else
|
|
283
|
+
if (key) attemptControllers.delete(key);
|
|
284
|
+
else legacyControllers.delete(requestId);
|
|
312
285
|
return;
|
|
313
286
|
}
|
|
314
287
|
|
|
315
288
|
options.events.emit(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
? {
|
|
319
|
-
:
|
|
320
|
-
? { version: SUBAGENT_DELEGATION_PROTOCOL_VERSION, requestId }
|
|
321
|
-
: { requestId },
|
|
289
|
+
structuredRequest ? SUBAGENT_DELEGATION_STARTED_EVENT : PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT,
|
|
290
|
+
structuredRequest
|
|
291
|
+
? { requestId, ownerRunId: structuredRequest.ownerRunId, nodeId: structuredRequest.nodeId }
|
|
292
|
+
: { requestId },
|
|
322
293
|
);
|
|
323
294
|
|
|
324
295
|
try {
|
|
325
|
-
const executeRequest =
|
|
326
|
-
? options.
|
|
296
|
+
const executeRequest = structuredRequest && options.executeStructured
|
|
297
|
+
? options.executeStructured
|
|
327
298
|
: options.execute;
|
|
328
299
|
const result = await executeRequest(
|
|
329
300
|
requestId,
|
|
@@ -331,14 +302,9 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
331
302
|
controller.signal,
|
|
332
303
|
ctx,
|
|
333
304
|
(update) => {
|
|
334
|
-
if (
|
|
335
|
-
if (
|
|
336
|
-
const payload =
|
|
337
|
-
if (payload) options.events.emit(SUBAGENT_DELEGATION_UPDATE_EVENT, payload);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
if (versionedRequest) {
|
|
341
|
-
const payload = toSubagentDelegationUpdate(requestId, update);
|
|
305
|
+
if (key ? !ownsAttempt(key, controller) : !ownsLegacyRequest(requestId, controller)) return;
|
|
306
|
+
if (structuredRequest) {
|
|
307
|
+
const payload = toSubagentDelegationUpdate(structuredRequest, update);
|
|
342
308
|
if (payload) options.events.emit(SUBAGENT_DELEGATION_UPDATE_EVENT, payload);
|
|
343
309
|
return;
|
|
344
310
|
}
|
|
@@ -346,14 +312,9 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
346
312
|
if (payload) options.events.emit(PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT, payload);
|
|
347
313
|
},
|
|
348
314
|
);
|
|
349
|
-
if (
|
|
350
|
-
if (
|
|
351
|
-
|
|
352
|
-
} else if (versionedRequest) {
|
|
353
|
-
options.events.emit(
|
|
354
|
-
SUBAGENT_DELEGATION_RESPONSE_EVENT,
|
|
355
|
-
toSubagentDelegationResponse(requestId, result, controller.signal.aborted),
|
|
356
|
-
);
|
|
315
|
+
if (key ? !ownsAttempt(key, controller) : !ownsLegacyRequest(requestId, controller)) return;
|
|
316
|
+
if (structuredRequest && key) {
|
|
317
|
+
emitTerminal(key, toSubagentDelegationResponse(structuredRequest, result, controller.signal.aborted));
|
|
357
318
|
} else if (legacyRequest) {
|
|
358
319
|
options.events.emit(
|
|
359
320
|
PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT,
|
|
@@ -363,23 +324,15 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
363
324
|
);
|
|
364
325
|
}
|
|
365
326
|
} catch (error) {
|
|
366
|
-
if (
|
|
367
|
-
if (
|
|
368
|
-
|
|
369
|
-
version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
|
|
327
|
+
if (key ? !ownsAttempt(key, controller) : !ownsLegacyRequest(requestId, controller)) return;
|
|
328
|
+
if (structuredRequest && key) {
|
|
329
|
+
emitTerminal(key, {
|
|
370
330
|
requestId,
|
|
371
|
-
ownerRunId:
|
|
372
|
-
nodeId:
|
|
331
|
+
ownerRunId: structuredRequest.ownerRunId,
|
|
332
|
+
nodeId: structuredRequest.nodeId,
|
|
373
333
|
status: controller.signal.aborted ? "cancelled" : "failed",
|
|
374
334
|
...(controller.signal.aborted ? {} : { error: error instanceof Error ? error.message : String(error) }),
|
|
375
335
|
});
|
|
376
|
-
} else if (versionedRequest) {
|
|
377
|
-
options.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {
|
|
378
|
-
version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
|
|
379
|
-
requestId,
|
|
380
|
-
status: controller.signal.aborted ? "cancelled" : "failed",
|
|
381
|
-
...(controller.signal.aborted ? {} : { error: error instanceof Error ? error.message : String(error) }),
|
|
382
|
-
} satisfies SubagentDelegationResponse);
|
|
383
336
|
} else if (legacyRequest) {
|
|
384
337
|
options.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {
|
|
385
338
|
...legacyRequest,
|
|
@@ -389,40 +342,40 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
|
|
|
389
342
|
} satisfies PromptTemplateDelegationResponse);
|
|
390
343
|
}
|
|
391
344
|
} finally {
|
|
392
|
-
if (
|
|
393
|
-
if (
|
|
394
|
-
} else if (
|
|
395
|
-
if (
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
345
|
+
if (key) {
|
|
346
|
+
if (attemptControllers.get(key) === controller) attemptControllers.delete(key);
|
|
347
|
+
} else if (legacyControllers.get(requestId) === controller) legacyControllers.delete(requestId);
|
|
348
|
+
if (structuredRequest) {
|
|
349
|
+
const ownedNodeKey = nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId);
|
|
350
|
+
if (activeOwnedNodes.get(ownedNodeKey)?.controller === controller) activeOwnedNodes.delete(ownedNodeKey);
|
|
398
351
|
}
|
|
399
352
|
}
|
|
400
353
|
});
|
|
401
354
|
|
|
402
355
|
return {
|
|
403
356
|
cancelAll: () => {
|
|
404
|
-
for (const controller of
|
|
405
|
-
for (const controller of
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
357
|
+
for (const controller of legacyControllers.values()) controller.abort();
|
|
358
|
+
for (const controller of attemptControllers.values()) controller.abort();
|
|
359
|
+
legacyControllers.clear();
|
|
360
|
+
attemptControllers.clear();
|
|
361
|
+
pendingLegacyCancels.clear();
|
|
362
|
+
pendingAttemptCancels.clear();
|
|
363
|
+
activeOwnedNodes.clear();
|
|
364
|
+
settledAttempts.clear();
|
|
365
|
+
identitySaturated = false;
|
|
413
366
|
},
|
|
414
367
|
dispose: () => {
|
|
415
368
|
disposed = true;
|
|
416
|
-
for (const controller of
|
|
417
|
-
for (const controller of
|
|
418
|
-
|
|
419
|
-
|
|
369
|
+
for (const controller of legacyControllers.values()) controller.abort();
|
|
370
|
+
for (const controller of attemptControllers.values()) controller.abort();
|
|
371
|
+
legacyControllers.clear();
|
|
372
|
+
attemptControllers.clear();
|
|
420
373
|
for (const unsubscribe of subscriptions) unsubscribe();
|
|
421
374
|
subscriptions.length = 0;
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
375
|
+
pendingLegacyCancels.clear();
|
|
376
|
+
pendingAttemptCancels.clear();
|
|
377
|
+
activeOwnedNodes.clear();
|
|
378
|
+
settledAttempts.clear();
|
|
426
379
|
},
|
|
427
380
|
};
|
|
428
381
|
}
|