@marcoscale98/pi-extensible-workflows 5.17.0-fork.1 → 6.2.1-fork.1
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 +145 -0
- package/README.md +2 -2
- package/dist/src/agent-execution.d.ts +43 -10
- package/dist/src/agent-execution.js +442 -162
- package/dist/src/background-widget.d.ts +5 -1
- package/dist/src/background-widget.js +5 -10
- package/dist/src/decoders.d.ts +2 -3
- package/dist/src/decoders.js +59 -37
- package/dist/src/execution.d.ts +6 -2
- package/dist/src/execution.js +48 -7
- package/dist/src/host-delivery.js +5 -8
- package/dist/src/host-navigator.js +5 -2
- package/dist/src/host-phases.d.ts +1 -0
- package/dist/src/host-recovery.d.ts +11 -8
- package/dist/src/host-recovery.js +14 -22
- package/dist/src/host-runtime.js +56 -5
- package/dist/src/host-view.d.ts +6 -1
- package/dist/src/host-view.js +46 -20
- package/dist/src/host.d.ts +2 -2
- package/dist/src/host.js +246 -118
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +1985 -1690
- package/dist/src/index.js.map +3 -3
- package/dist/src/paths.d.ts +8 -5
- package/dist/src/paths.js +24 -13
- package/dist/src/persistence.d.ts +1 -0
- package/dist/src/persistence.js +1 -0
- package/dist/src/pi-runtime-runner.js +4 -1
- package/dist/src/registry.d.ts +9 -7
- package/dist/src/registry.js +29 -71
- package/dist/src/runtime/agent-runner.d.ts +2 -0
- package/dist/src/script-tools.d.ts +27 -0
- package/dist/src/script-tools.js +87 -0
- package/dist/src/session-lease.d.ts +1 -1
- package/dist/src/session-lease.js +45 -11
- package/dist/src/settings.d.ts +19 -3
- package/dist/src/settings.js +63 -50
- package/dist/src/store.d.ts +3 -1
- package/dist/src/store.js +17 -1
- package/dist/src/trajectory.d.ts +12 -3
- package/dist/src/trajectory.js +32 -11
- package/dist/src/types.d.ts +129 -45
- package/dist/src/types.js +5 -8
- package/dist/src/utils.d.ts +21 -1
- package/dist/src/utils.js +46 -6
- package/dist/src/validation.d.ts +14 -3
- package/dist/src/validation.js +143 -87
- package/dist/starter/index.js +8 -11
- package/dist/starter/index.js.map +1 -1
- package/dist/starter/review-loop.d.ts +0 -13
- package/dist/starter/review-loop.js +8 -9
- package/dist/subagents/index.js +904 -956
- package/dist/subagents/index.js.map +3 -3
- package/dist/subagents/src/contracts.d.ts +48 -31
- package/dist/subagents/src/contracts.js +20 -9
- package/dist/subagents/src/index.d.ts +1 -1
- package/dist/subagents/src/index.js +14 -8
- package/dist/subagents/src/manager.js +52 -73
- package/dist/subagents/src/navigator.js +3 -14
- package/dist/subagents/src/view.d.ts +1 -1
- package/dist/subagents/src/view.js +15 -68
- package/dist/subagents/src/worktree.js +1 -1
- package/dist/trajectory/assets/index.html +35 -13
- package/dist/trajectory/index.js +576 -932
- package/dist/trajectory/index.js.map +3 -3
- package/dist/trajectory/src/assets/index.html +35 -13
- package/dist/trajectory/src/index.js +134 -104
- package/dist/trajectory/src/server.js +268 -27
- package/dist/trajectory/src/server.js.map +3 -3
- package/dist/trajectory/src/startup-mutex.d.ts +17 -0
- package/dist/trajectory/src/startup-mutex.js +172 -0
- package/examples/workflow-extension-template/README.md +4 -7
- package/examples/workflow-extension-template/extension.test.mjs +4 -8
- package/examples/workflow-extension-template/index.js +0 -3
- package/package.json +10 -10
- package/skills/pi-extensible-workflows/SKILL.md +12 -8
- package/src/agent-execution.ts +412 -164
- package/src/background-widget.ts +5 -11
- package/src/decoders.ts +51 -37
- package/src/execution.ts +46 -9
- package/src/host-delivery.ts +5 -8
- package/src/host-navigator.ts +4 -2
- package/src/host-phases.ts +1 -1
- package/src/host-recovery.ts +23 -28
- package/src/host-runtime.ts +44 -6
- package/src/host-view.ts +41 -16
- package/src/host.ts +229 -142
- package/src/index.ts +1 -2
- package/src/paths.ts +18 -9
- package/src/persistence.ts +1 -0
- package/src/pi-runtime-runner.ts +3 -1
- package/src/registry.ts +28 -64
- package/src/runtime/agent-runner.ts +2 -0
- package/src/script-tools.ts +76 -0
- package/src/session-lease.ts +34 -6
- package/src/settings.ts +56 -50
- package/src/store.ts +18 -2
- package/src/trajectory.ts +32 -15
- package/src/types.ts +82 -34
- package/src/utils.ts +42 -5
- package/src/validation.ts +121 -80
- package/starter/index.ts +0 -1
- package/starter/review-loop.ts +8 -9
- package/starter/roles/developer.md +0 -1
- package/starter/roles/oracle.md +0 -1
- package/starter/roles/researcher.md +0 -1
- package/starter/roles/reviewer.md +0 -1
- package/starter/roles/scout.md +0 -1
- package/subagents/README.md +10 -16
- package/subagents/src/contracts.ts +21 -11
- package/subagents/src/index.ts +17 -8
- package/subagents/src/manager.ts +48 -128
- package/subagents/src/navigator.ts +4 -13
- package/subagents/src/view.ts +16 -63
- package/subagents/src/worktree.ts +1 -1
- package/trajectory/src/assets/index.html +35 -13
- package/trajectory/src/index.ts +112 -91
- package/trajectory/src/server.ts +46 -10
- package/trajectory/src/startup-mutex.ts +127 -0
- package/dist/src/roles.d.ts +0 -70
- package/dist/src/roles.js +0 -325
- package/dist/starter/roles/developer.md +0 -6
- package/dist/starter/roles/oracle.md +0 -18
- package/dist/starter/roles/researcher.md +0 -20
- package/dist/starter/roles/reviewer.md +0 -19
- package/dist/starter/roles/scout.md +0 -18
- package/examples/workflow-extension-template/roles/reviewer.md +0 -4
- package/src/roles.ts +0 -326
|
@@ -13,10 +13,10 @@ export declare const SUBAGENTS_RUN_PARAMETERS: Type.TObject<{
|
|
|
13
13
|
label: Type.TOptional<Type.TString>;
|
|
14
14
|
model: Type.TOptional<Type.TString>;
|
|
15
15
|
tools: Type.TOptional<Type.TArray<Type.TString>>;
|
|
16
|
+
excludeTools: Type.TOptional<Type.TArray<Type.TString>>;
|
|
16
17
|
skills: Type.TOptional<Type.TArray<Type.TString>>;
|
|
17
18
|
extensions: Type.TOptional<Type.TArray<Type.TString>>;
|
|
18
19
|
contextFiles: Type.TOptional<Type.TArray<Type.TString>>;
|
|
19
|
-
role: Type.TOptional<Type.TString>;
|
|
20
20
|
worktree: Type.TOptional<Type.TString>;
|
|
21
21
|
outputSchema: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
22
22
|
retries: Type.TOptional<Type.TInteger>;
|
|
@@ -24,6 +24,7 @@ export declare const SUBAGENTS_RUN_PARAMETERS: Type.TObject<{
|
|
|
24
24
|
}>;
|
|
25
25
|
export declare const SUBAGENTS_INSPECT_PARAMETERS: Type.TObject<{
|
|
26
26
|
id: Type.TOptional<Type.TString>;
|
|
27
|
+
scope: Type.TOptional<Type.TUnion<[Type.TLiteral<"session">, Type.TLiteral<"all">]>>;
|
|
27
28
|
}>;
|
|
28
29
|
export declare const SUBAGENTS_ID_PARAMETERS: Type.TObject<{
|
|
29
30
|
id: Type.TString;
|
|
@@ -38,37 +39,54 @@ export declare const SUBAGENTS_STOP_PARAMETERS: Type.TObject<{
|
|
|
38
39
|
export declare const SUBAGENTS_RETRY_PARAMETERS: Type.TObject<{
|
|
39
40
|
id: Type.TString;
|
|
40
41
|
}>;
|
|
41
|
-
export declare const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
42
|
+
export declare const SUBAGENT_STATUS_OUTPUT: Type.TObject<{
|
|
43
|
+
id: Type.TString;
|
|
44
|
+
state: Type.TString;
|
|
45
|
+
sessionId: Type.TOptional<Type.TString>;
|
|
46
|
+
startedAt: Type.TOptional<Type.TNumber>;
|
|
47
|
+
finishedAt: Type.TOptional<Type.TNumber>;
|
|
48
|
+
attempts: Type.TOptional<Type.TNumber>;
|
|
49
|
+
attemptDetails: Type.TOptional<Type.TArray<Type.TUnknown>>;
|
|
50
|
+
worktree: Type.TOptional<Type.TObject<{
|
|
51
|
+
path: Type.TString;
|
|
52
|
+
branch: Type.TString;
|
|
53
|
+
}>>;
|
|
54
|
+
error: Type.TOptional<Type.TObject<{
|
|
55
|
+
code: Type.TString;
|
|
56
|
+
message: Type.TString;
|
|
57
|
+
}>>;
|
|
58
|
+
progress: Type.TOptional<Type.TUnknown>;
|
|
59
|
+
value: Type.TOptional<Type.TUnknown>;
|
|
60
|
+
}>;
|
|
61
|
+
export declare const SUBAGENTS_INSPECT_OUTPUT: Type.TUnion<[Type.TObject<{
|
|
62
|
+
id: Type.TString;
|
|
63
|
+
state: Type.TString;
|
|
64
|
+
sessionId: Type.TOptional<Type.TString>;
|
|
65
|
+
startedAt: Type.TOptional<Type.TNumber>;
|
|
66
|
+
finishedAt: Type.TOptional<Type.TNumber>;
|
|
67
|
+
attempts: Type.TOptional<Type.TNumber>;
|
|
68
|
+
attemptDetails: Type.TOptional<Type.TArray<Type.TUnknown>>;
|
|
69
|
+
worktree: Type.TOptional<Type.TObject<{
|
|
70
|
+
path: Type.TString;
|
|
71
|
+
branch: Type.TString;
|
|
72
|
+
}>>;
|
|
73
|
+
error: Type.TOptional<Type.TObject<{
|
|
74
|
+
code: Type.TString;
|
|
62
75
|
message: Type.TString;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
}>>;
|
|
77
|
+
progress: Type.TOptional<Type.TUnknown>;
|
|
78
|
+
value: Type.TOptional<Type.TUnknown>;
|
|
79
|
+
}>, Type.TArray<Type.TObject<{
|
|
80
|
+
id: Type.TString;
|
|
81
|
+
state: Type.TString;
|
|
82
|
+
}>>]>;
|
|
83
|
+
export declare const SUBAGENTS_STEER_OUTPUT: Type.TObject<{
|
|
84
|
+
id: Type.TString;
|
|
85
|
+
accepted: Type.TBoolean;
|
|
86
|
+
}>;
|
|
87
|
+
export type SubagentRunRequest = Static<typeof SUBAGENTS_RUN_PARAMETERS> & {
|
|
88
|
+
readonly [key: string]: unknown;
|
|
70
89
|
};
|
|
71
|
-
export type SubagentRunRequest = Static<typeof SUBAGENTS_RUN_PARAMETERS>;
|
|
72
90
|
export declare function normalizeSubagentRunRequest(value: unknown): SubagentRunRequest;
|
|
73
91
|
export type SubagentInspectRequest = Static<typeof SUBAGENTS_INSPECT_PARAMETERS>;
|
|
74
92
|
export type SubagentIdRequest = Static<typeof SUBAGENTS_ID_PARAMETERS>;
|
|
@@ -101,7 +119,6 @@ export interface SubagentStatus {
|
|
|
101
119
|
export interface SubagentNotification {
|
|
102
120
|
readonly id: string;
|
|
103
121
|
readonly label?: string;
|
|
104
|
-
readonly role?: string;
|
|
105
122
|
readonly state: "completed" | "failed";
|
|
106
123
|
readonly error?: {
|
|
107
124
|
readonly code: string;
|
|
@@ -22,17 +22,18 @@ export const SUBAGENTS_RUN_PARAMETERS = Type.Object({
|
|
|
22
22
|
label: Type.Optional(Type.String({ description: "Optional display label for the subagent" })),
|
|
23
23
|
model: Type.Optional(Type.String({ description: "Optional model as provider/model:thinking or alias[:thinking]" })),
|
|
24
24
|
tools: Type.Optional(Type.Array(Type.String(), { description: "Optional ordered tool selectors; candidates start enabled and !* restricts the set" })),
|
|
25
|
+
excludeTools: Type.Optional(Type.Array(Type.String(), { description: "Optional exact tool names removed after preparation; no patterns, cannot remove workflow_result" })),
|
|
25
26
|
skills: Type.Optional(Type.Array(Type.String(), { description: "Optional ordered skill selectors; candidates start enabled and !* restricts the set" })),
|
|
26
27
|
extensions: Type.Optional(Type.Array(Type.String(), { description: "Optional ordered extension selectors; candidates start enabled and !* restricts the set" })),
|
|
27
28
|
contextFiles: Type.Optional(Type.Array(Type.String(), { description: "Optional context-file scopes: global, project, cwd" })),
|
|
28
|
-
role: Type.Optional(Type.String({ description: "Workflow role name" })),
|
|
29
29
|
worktree: Type.Optional(Type.String({ description: "Optional named worktree; requires a clean working tree" })),
|
|
30
30
|
outputSchema: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Optional JSON schema for the result" })),
|
|
31
31
|
retries: Type.Optional(Type.Integer({ minimum: 0, maximum: SUBAGENT_MAX_RETRIES, description: "Optional retry count; at most 255 retries" })),
|
|
32
32
|
timeoutMs: Type.Optional(Type.Union([Type.Integer({ minimum: 1, description: "Optional execution timeout in milliseconds" }), Type.Null()])),
|
|
33
|
-
}, { additionalProperties:
|
|
33
|
+
}, { additionalProperties: true });
|
|
34
34
|
export const SUBAGENTS_INSPECT_PARAMETERS = Type.Object({
|
|
35
35
|
id: Type.Optional(Type.String({ description: "Subagent ID; omit to list ordered run summaries" })),
|
|
36
|
+
scope: Type.Optional(Type.Union([Type.Literal("session"), Type.Literal("all")], { description: "List scope when id is omitted: session (default) lists runs from the current Pi session; all lists every stored run" })),
|
|
36
37
|
}, { additionalProperties: false });
|
|
37
38
|
export const SUBAGENTS_ID_PARAMETERS = Type.Object({
|
|
38
39
|
id: Type.String({ description: "Subagent ID" }),
|
|
@@ -47,13 +48,23 @@ export const SUBAGENTS_STOP_PARAMETERS = Type.Object({
|
|
|
47
48
|
export const SUBAGENTS_RETRY_PARAMETERS = Type.Object({
|
|
48
49
|
id: Type.String({ description: "Failed or stopped subagent ID to retry" }),
|
|
49
50
|
}, { additionalProperties: false });
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
// Structured results codemode scripts receive instead of the JSON text; nested records stay loose so they cannot drift from persistence.
|
|
52
|
+
export const SUBAGENT_STATUS_OUTPUT = Type.Object({
|
|
53
|
+
id: Type.String(),
|
|
54
|
+
state: Type.String(),
|
|
55
|
+
sessionId: Type.Optional(Type.String()),
|
|
56
|
+
startedAt: Type.Optional(Type.Number()),
|
|
57
|
+
finishedAt: Type.Optional(Type.Number()),
|
|
58
|
+
attempts: Type.Optional(Type.Number()),
|
|
59
|
+
attemptDetails: Type.Optional(Type.Array(Type.Unknown())),
|
|
60
|
+
worktree: Type.Optional(Type.Object({ path: Type.String(), branch: Type.String() })),
|
|
61
|
+
error: Type.Optional(Type.Object({ code: Type.String(), message: Type.String() })),
|
|
62
|
+
progress: Type.Optional(Type.Unknown()),
|
|
63
|
+
value: Type.Optional(Type.Unknown()),
|
|
64
|
+
});
|
|
65
|
+
// One run when id is given, otherwise the ordered run summaries; the summaries stay short in the codemode description.
|
|
66
|
+
export const SUBAGENTS_INSPECT_OUTPUT = Type.Union([SUBAGENT_STATUS_OUTPUT, Type.Array(Type.Object({ id: Type.String(), state: Type.String() }))]);
|
|
67
|
+
export const SUBAGENTS_STEER_OUTPUT = Type.Object({ id: Type.String(), accepted: Type.Boolean() });
|
|
57
68
|
export function normalizeSubagentRunRequest(value) {
|
|
58
69
|
if (!Value.Check(SUBAGENTS_RUN_PARAMETERS, value))
|
|
59
70
|
throw new WorkflowError("INVALID_METADATA", "Invalid subagents_run parameters");
|
|
@@ -5,7 +5,7 @@ export { attemptValue, statusValue, subagentErrorValue } from "./decode.js";
|
|
|
5
5
|
export { createSubagentManager, createUnavailableSubagentManager } from "./manager.js";
|
|
6
6
|
export { createRunStoreWorktreeAdapter, defaultWorktreeHome } from "./worktree.js";
|
|
7
7
|
export type { SubagentWorktreeAdapter, SubagentWorktreeContext, SubagentWorktreeHandle, SubagentWorktreeRunStore } from "./worktree.js";
|
|
8
|
-
type SubagentsExtensionAPI = Pick<ExtensionAPI, "registerTool"> & Partial<Pick<ExtensionAPI, "getActiveTools" | "on" | "sendMessage" | "registerCommand" | "appendEntry" | "registerEntryRenderer">>;
|
|
8
|
+
type SubagentsExtensionAPI = Pick<ExtensionAPI, "registerTool"> & Partial<Pick<ExtensionAPI, "events" | "getActiveTools" | "getAllTools" | "on" | "sendMessage" | "registerCommand" | "appendEntry" | "registerEntryRenderer">>;
|
|
9
9
|
export declare function createSubagentTools(manager: SubagentManager): readonly ToolDefinition[];
|
|
10
10
|
export declare function createSubagentsExtension(options?: SubagentsExtensionOptions, activeTools?: () => readonly string[], notify?: (notification: SubagentNotification) => void | Promise<void>, onStatus?: (status: Readonly<SubagentStatus>, request: Readonly<SubagentRunRequest>) => void, onResourceWarning?: (message: string) => void): SubagentsExtension;
|
|
11
11
|
export declare function registerSubagentsExtension(pi: SubagentsExtensionAPI, options?: SubagentsExtensionOptions): SubagentsExtension;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { defineTool, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
|
-
import { WorkflowError, loadingRegistry } from "../../src/index.js";
|
|
4
|
+
import { WorkflowError, loadCodemodeToolsSetting, loadingRegistry, reachableTools, workflowToolExposure } from "../../src/index.js";
|
|
5
5
|
import { clearSubagentManager, setSubagentManager } from "../../src/subagent-manager-handle.js";
|
|
6
6
|
import { createSubagentManager } from "./manager.js";
|
|
7
7
|
import { registerSubagentNavigator } from "./navigator.js";
|
|
8
8
|
import { createSubagentBackgroundWidget, renderSubagentCall, renderSubagentControlCall, renderSubagentControlResult, renderSubagentInspectCall, renderSubagentInspectResult, renderSubagentResult } from "./view.js";
|
|
9
|
-
import { normalizeSubagentRunRequest, SUBAGENTS_ID_PARAMETERS, SUBAGENTS_INSPECT_PARAMETERS, SUBAGENTS_RETRY_PARAMETERS, SUBAGENTS_RUN_PARAMETERS, SUBAGENTS_STEER_PARAMETERS, SUBAGENTS_STOP_PARAMETERS, } from "./contracts.js";
|
|
9
|
+
import { normalizeSubagentRunRequest, SUBAGENT_STATUS_OUTPUT, SUBAGENTS_ID_PARAMETERS, SUBAGENTS_INSPECT_OUTPUT, SUBAGENTS_INSPECT_PARAMETERS, SUBAGENTS_RETRY_PARAMETERS, SUBAGENTS_RUN_PARAMETERS, SUBAGENTS_STEER_OUTPUT, SUBAGENTS_STEER_PARAMETERS, SUBAGENTS_STOP_PARAMETERS, } from "./contracts.js";
|
|
10
10
|
export * from "./contracts.js";
|
|
11
11
|
export { attemptValue, statusValue, subagentErrorValue } from "./decode.js";
|
|
12
12
|
export { createSubagentManager, createUnavailableSubagentManager } from "./manager.js";
|
|
@@ -41,7 +41,7 @@ function serialize(value) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
function toolResult(value) {
|
|
44
|
-
return { content: [{ type: "text", text: serialize(value) }], details: value };
|
|
44
|
+
return { content: [{ type: "text", text: serialize(value) }], details: value, structuredContent: value };
|
|
45
45
|
}
|
|
46
46
|
function managerContext(toolCallId, signal, onUpdate, context) {
|
|
47
47
|
return {
|
|
@@ -63,6 +63,7 @@ export function createSubagentTools(manager) {
|
|
|
63
63
|
"Do not poll a running ID; use subagents_inspect({ id }) when you need its current status or terminal result.",
|
|
64
64
|
],
|
|
65
65
|
parameters: SUBAGENTS_RUN_PARAMETERS,
|
|
66
|
+
outputSchema: SUBAGENT_STATUS_OUTPUT,
|
|
66
67
|
async execute(toolCallId, params, signal, onUpdate, context) {
|
|
67
68
|
return toolResult(await manager.run(validateSubagentRunRequest(params), managerContext(toolCallId, signal, onUpdate, context)));
|
|
68
69
|
},
|
|
@@ -72,8 +73,9 @@ export function createSubagentTools(manager) {
|
|
|
72
73
|
defineTool({
|
|
73
74
|
name: "subagents_inspect",
|
|
74
75
|
label: "Subagents Inspect",
|
|
75
|
-
description: "Inspect durable subagent runs. Omit id for ordered run summaries, or provide id for detailed status, progress, activity, accounting, tool calls, timestamps, worktree metadata, and a terminal value or error when available.",
|
|
76
|
+
description: "Inspect durable subagent runs. Omit id for ordered run summaries of the current session (scope all for every session), or provide id for detailed status, progress, activity, accounting, tool calls, timestamps, worktree metadata, and a terminal value or error when available.",
|
|
76
77
|
parameters: SUBAGENTS_INSPECT_PARAMETERS,
|
|
78
|
+
outputSchema: SUBAGENTS_INSPECT_OUTPUT,
|
|
77
79
|
async execute(toolCallId, params, signal, onUpdate, context) {
|
|
78
80
|
return toolResult(await manager.inspect(validateSubagentInspectRequest(params), managerContext(toolCallId, signal, onUpdate, context)));
|
|
79
81
|
},
|
|
@@ -85,6 +87,7 @@ export function createSubagentTools(manager) {
|
|
|
85
87
|
label: "Subagents Steer",
|
|
86
88
|
description: "Send a message to a running subagent. The message is queued safely if its steering handler is not ready; settled runs cannot be steered.",
|
|
87
89
|
parameters: SUBAGENTS_STEER_PARAMETERS,
|
|
90
|
+
outputSchema: SUBAGENTS_STEER_OUTPUT,
|
|
88
91
|
async execute(toolCallId, params, signal, onUpdate, context) {
|
|
89
92
|
return toolResult(await manager.steer(validateSubagentSteerRequest(params), managerContext(toolCallId, signal, onUpdate, context)));
|
|
90
93
|
},
|
|
@@ -96,6 +99,7 @@ export function createSubagentTools(manager) {
|
|
|
96
99
|
label: "Subagents Stop",
|
|
97
100
|
description: "Stop one running subagent, abort its active session, persist state \"stopped\", and clean its worktree without affecting sibling runs.",
|
|
98
101
|
parameters: SUBAGENTS_STOP_PARAMETERS,
|
|
102
|
+
outputSchema: SUBAGENT_STATUS_OUTPUT,
|
|
99
103
|
async execute(toolCallId, params, signal, onUpdate, context) {
|
|
100
104
|
return toolResult(await manager.stop(validateSubagentIdRequest(params, "subagents_stop"), managerContext(toolCallId, signal, onUpdate, context)));
|
|
101
105
|
},
|
|
@@ -107,6 +111,7 @@ export function createSubagentTools(manager) {
|
|
|
107
111
|
label: "Subagents Retry",
|
|
108
112
|
description: "Start a fresh run from a failed or stopped subagent's persisted request. The new run gets a new ID and preserves its original background or foreground mode.",
|
|
109
113
|
parameters: SUBAGENTS_RETRY_PARAMETERS,
|
|
114
|
+
outputSchema: SUBAGENT_STATUS_OUTPUT,
|
|
110
115
|
async execute(toolCallId, params, signal, onUpdate, context) {
|
|
111
116
|
return toolResult(await manager.retry(validateSubagentIdRequest(params, "subagents_retry"), managerContext(toolCallId, signal, onUpdate, context)));
|
|
112
117
|
},
|
|
@@ -117,8 +122,7 @@ export function createSubagentTools(manager) {
|
|
|
117
122
|
}
|
|
118
123
|
function notificationContent(notification) {
|
|
119
124
|
const label = notification.label?.trim();
|
|
120
|
-
const
|
|
121
|
-
const identity = label ? `${label} role=${role} (${notification.id})` : `${notification.id} role=${role}`;
|
|
125
|
+
const identity = label ? `${label} (${notification.id})` : notification.id;
|
|
122
126
|
if (notification.state === "completed")
|
|
123
127
|
return `Subagent ${identity} completed. Inspect it with subagents_inspect({ id: "${notification.id}" }).`;
|
|
124
128
|
return `Subagent ${identity} failed: ${notification.error?.message ?? "unknown error"}. Inspect it with subagents_inspect({ id: "${notification.id}" }).`;
|
|
@@ -145,7 +149,8 @@ export function createSubagentsExtension(options = {}, activeTools, notify, onSt
|
|
|
145
149
|
}
|
|
146
150
|
export function registerSubagentsExtension(pi, options = {}) {
|
|
147
151
|
const getActiveTools = pi.getActiveTools;
|
|
148
|
-
const
|
|
152
|
+
const getAllTools = pi.getAllTools;
|
|
153
|
+
const activeTools = getActiveTools === undefined ? undefined : () => reachableTools({ getActiveTools: () => getActiveTools.call(pi), ...(getAllTools === undefined ? {} : { getAllTools: () => getAllTools.call(pi) }) });
|
|
149
154
|
const sendMessage = pi.sendMessage;
|
|
150
155
|
const notify = sendMessage === undefined ? undefined : (notification) => {
|
|
151
156
|
sendMessage.call(pi, { customType: "subagents", content: notificationContent(notification), display: true, details: notification }, { deliverAs: "steer", triggerTurn: true });
|
|
@@ -157,8 +162,9 @@ export function registerSubagentsExtension(pi, options = {}) {
|
|
|
157
162
|
const widget = createSubagentBackgroundWidget({ ...(appendEntry === undefined ? {} : { appendEntry: (customType, data) => { appendEntry.call(pi, customType, data); } }), ...(pi.registerEntryRenderer === undefined ? {} : { registerEntryRenderer: pi.registerEntryRenderer.bind(pi) }) });
|
|
158
163
|
const extension = createSubagentsExtension(options, activeTools, notify, (status, request) => { widget.update(status, request); const registry = loadingRegistry(); if (typeof registry.observeSubagentStatus === "function")
|
|
159
164
|
registry.observeSubagentStatus(status, request); }, onResourceWarning);
|
|
165
|
+
const codemodeTools = loadCodemodeToolsSetting(options.managerDependencies?.agentDir);
|
|
160
166
|
for (const tool of extension.tools)
|
|
161
|
-
pi.registerTool(tool);
|
|
167
|
+
pi.registerTool({ ...tool, ...workflowToolExposure(tool.name, codemodeTools) });
|
|
162
168
|
if (pi.registerCommand !== undefined)
|
|
163
169
|
registerSubagentNavigator(pi.registerCommand.bind(pi), extension.manager, storageDirectory(options), options.clipboard);
|
|
164
170
|
if (pi.on !== undefined) {
|
|
@@ -2,12 +2,11 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { chmod, link, mkdir, open, readFile, readdir, rename, rm, stat } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { addAccounting,
|
|
6
|
-
import {
|
|
7
|
-
import { loadAgentDefinitions } from "../../src/roles.js";
|
|
5
|
+
import { addAccounting, errorCode, errorText, finiteNumber, isNodeError, isThinkingLevel, jsonValue, object, loadingRegistry, localAgentTransport, resolveAgentResourcePolicy, resolveWorkflowSettings, sanitizeDisplayText, sumAccounting, structuralPath, validateModelAliasAvailability, WorkflowAgentExecutor, WorkflowError, workflowSettingsPath, SerialLane } from "../../src/index.js";
|
|
6
|
+
import { decodePreparedAgentConfiguration } from "../../src/decoders.js";
|
|
8
7
|
import { atomicJson, json as readJson, processAlive } from "../../src/persistence.js";
|
|
9
8
|
import { accountingValue, activityValue, legacyAccountingValue, worktreeValue } from "./decode.js";
|
|
10
|
-
import { SUBAGENT_ATTEMPT_DETAILS_LIMIT, SUBAGENT_MAX_RETRIES, SUBAGENT_SYSTEM_PROMPT_LIMIT, SUBAGENTS_TOOL_NAMES, normalizeSubagentRunRequest
|
|
9
|
+
import { SUBAGENT_ATTEMPT_DETAILS_LIMIT, SUBAGENT_MAX_RETRIES, SUBAGENT_SYSTEM_PROMPT_LIMIT, SUBAGENTS_TOOL_NAMES, normalizeSubagentRunRequest } from "./contracts.js";
|
|
11
10
|
import { createRunStoreWorktreeAdapter, defaultWorktreeHome } from "./worktree.js";
|
|
12
11
|
const WORKFLOW_NAME = "subagents";
|
|
13
12
|
const STORAGE_DIRECTORY = "subagents";
|
|
@@ -44,25 +43,11 @@ function rootModel(context) {
|
|
|
44
43
|
const thinking = context.extensionContext.thinkingLevel;
|
|
45
44
|
return { provider: model.provider, model: model.id, ...(thinking === undefined ? {} : { thinking }) };
|
|
46
45
|
}
|
|
47
|
-
function
|
|
48
|
-
return trustedProject && external.projectExtensionSettings !== undefined ? workflowProjectSettingsPath(cwd) : workflowSettingsPath(agentDir);
|
|
49
|
-
}
|
|
50
|
-
function validateStandaloneExtensionSources(context, external, registry, agentDir) {
|
|
51
|
-
const cwd = context.extensionContext.cwd;
|
|
52
|
-
const globalSettingsPath = workflowSettingsPath(agentDir);
|
|
53
|
-
const trustedProject = context.extensionContext.isProjectTrusted();
|
|
54
|
-
if (external.globalExtensionSettings !== undefined)
|
|
55
|
-
registry.validateExtensionSettings(external.globalExtensionSettings, { source: "global", cwd, projectTrusted: trustedProject, settingsPath: globalSettingsPath });
|
|
56
|
-
if (trustedProject && external.projectExtensionSettings !== undefined)
|
|
57
|
-
registry.validateExtensionSettings(external.projectExtensionSettings, { source: "project", cwd, projectTrusted: true, settingsPath: workflowProjectSettingsPath(cwd) });
|
|
58
|
-
}
|
|
59
|
-
function executionRoot(context, dependencies, signal, runId, worktree, external) {
|
|
46
|
+
function executionRoot(context, dependencies, signal, runId, worktree) {
|
|
60
47
|
const extensionContext = context.extensionContext;
|
|
61
48
|
const model = rootModel(context);
|
|
62
49
|
const agentDir = dependencies.agentDir ?? getAgentDir();
|
|
63
50
|
const currentTrustedProject = extensionContext.isProjectTrusted();
|
|
64
|
-
if (external.projectTrusted && !currentTrustedProject)
|
|
65
|
-
throw new WorkflowError("RESUME_INCOMPATIBLE", "Cannot retry standalone configuration from an untrusted project");
|
|
66
51
|
const trustedProject = currentTrustedProject;
|
|
67
52
|
const settingsPath = workflowSettingsPath(agentDir);
|
|
68
53
|
const settings = resolveWorkflowSettings(extensionContext.cwd, trustedProject, settingsPath);
|
|
@@ -85,11 +70,15 @@ function executionRoot(context, dependencies, signal, runId, worktree, external)
|
|
|
85
70
|
signal,
|
|
86
71
|
};
|
|
87
72
|
const registry = loadingRegistry();
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
if (settings.global.extensionSettings !== undefined)
|
|
74
|
+
registry.validateExtensionSettings(settings.global.extensionSettings, { source: "global", cwd: extensionContext.cwd, projectTrusted: trustedProject, settingsPath: settings.globalSettingsPath });
|
|
75
|
+
if (trustedProject && settings.project.extensionSettings !== undefined)
|
|
76
|
+
registry.validateExtensionSettings(settings.project.extensionSettings, { source: "project", cwd: extensionContext.cwd, projectTrusted: true, settingsPath: settings.projectSettingsPath });
|
|
77
|
+
const extensionSettings = settings.effective.extensionSettings;
|
|
78
|
+
const extensionSettingsPath = settings.sources.extensionSettings ?? settingsPath;
|
|
91
79
|
return {
|
|
92
80
|
cwd: extensionContext.cwd,
|
|
81
|
+
projectTrusted: trustedProject,
|
|
93
82
|
model,
|
|
94
83
|
tools,
|
|
95
84
|
resourceSelectors: resourcePolicy.effective,
|
|
@@ -99,9 +88,10 @@ function executionRoot(context, dependencies, signal, runId, worktree, external)
|
|
|
99
88
|
availableModels,
|
|
100
89
|
knownModels,
|
|
101
90
|
...(Object.keys(staticAliases).length ? { modelAliases: staticAliases } : {}),
|
|
91
|
+
dynamicModelAliasNames: [],
|
|
102
92
|
settingsPath: settings.sources.modelAliases,
|
|
103
93
|
extensionSettingsPath,
|
|
104
|
-
|
|
94
|
+
agentPreparationHooks: registry.agentPreparationHooks(),
|
|
105
95
|
agentSetupHooks: registry.agentSetupHooks(),
|
|
106
96
|
validateExtensionSettings: registry.validateExtensionSettings,
|
|
107
97
|
agentResourcePolicy: () => structuredClone(resourcePolicy),
|
|
@@ -118,11 +108,10 @@ async function addDynamicAliases(context, signal, root) {
|
|
|
118
108
|
const trustedProject = resourcePolicy?.projectTrusted ?? context.extensionContext.isProjectTrusted();
|
|
119
109
|
const dynamicAliases = await registry.resolveModelAliases({ cwd: context.extensionContext.cwd, projectTrusted: trustedProject, rootModel: root.model, knownModels: root.knownModels ?? new Set(), availableModels: root.availableModels ?? new Set(), signal }, new Set(Object.keys(staticAliases)));
|
|
120
110
|
validateModelAliasAvailability(dynamicAliases, Object.keys(dynamicAliases), root.availableModels ?? new Set(), root.knownModels ?? new Set(), root.settingsPath);
|
|
121
|
-
return { ...root, modelAliases: { ...dynamicAliases, ...staticAliases } };
|
|
111
|
+
return { ...root, modelAliases: { ...dynamicAliases, ...staticAliases }, dynamicModelAliasNames: Object.keys(dynamicAliases) };
|
|
122
112
|
}
|
|
123
113
|
function executionOptions(request, onAttempt, onProgress) {
|
|
124
|
-
const
|
|
125
|
-
const label = request.label ?? roleNameOf(role) ?? "subagent";
|
|
114
|
+
const label = request.label ?? "subagent";
|
|
126
115
|
return {
|
|
127
116
|
label,
|
|
128
117
|
workflowName: WORKFLOW_NAME,
|
|
@@ -131,11 +120,11 @@ function executionOptions(request, onAttempt, onProgress) {
|
|
|
131
120
|
...(request.skills === undefined ? {} : { skills: request.skills }),
|
|
132
121
|
...(request.extensions === undefined ? {} : { extensions: request.extensions }),
|
|
133
122
|
...(request.contextFiles === undefined ? {} : { contextFiles: request.contextFiles }),
|
|
134
|
-
...(role === undefined ? {} : { role }),
|
|
135
123
|
...(request.worktree === undefined ? {} : { worktreeOwner: structuralPath("worktree", "named", request.worktree) }),
|
|
136
124
|
...(request.outputSchema === undefined ? {} : { schema: request.outputSchema }),
|
|
137
125
|
...(request.retries === undefined ? {} : { retries: request.retries }),
|
|
138
126
|
...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
|
|
127
|
+
agentOptions: Object.fromEntries(Object.entries(request).filter(([key]) => !["prompt", "mode", "worktree"].includes(key))),
|
|
139
128
|
onAttempt,
|
|
140
129
|
onProgress,
|
|
141
130
|
};
|
|
@@ -326,36 +315,9 @@ function checkedRequest(request) {
|
|
|
326
315
|
return normalizeSubagentRunRequest(request);
|
|
327
316
|
}
|
|
328
317
|
function decodePersistedStandaloneExternalConfiguration(value) {
|
|
329
|
-
if (!object(value) ||
|
|
330
|
-
return undefined;
|
|
331
|
-
const globalExtensionSettings = value.globalExtensionSettings === undefined ? undefined : decodeWorkflowExtensions(value.globalExtensionSettings);
|
|
332
|
-
const projectExtensionSettings = value.projectExtensionSettings === undefined ? undefined : decodeWorkflowExtensions(value.projectExtensionSettings);
|
|
333
|
-
if (value.globalExtensionSettings !== undefined && globalExtensionSettings === undefined || value.projectExtensionSettings !== undefined && projectExtensionSettings === undefined)
|
|
334
|
-
return undefined;
|
|
335
|
-
if (!object(value.agentDefinitions))
|
|
318
|
+
if (!object(value) || value.version !== 1)
|
|
336
319
|
return undefined;
|
|
337
|
-
|
|
338
|
-
for (const [name, definition] of Object.entries(value.agentDefinitions)) {
|
|
339
|
-
const decoded = decodeAgentDefinition(definition);
|
|
340
|
-
if (decoded === undefined)
|
|
341
|
-
return undefined;
|
|
342
|
-
agentDefinitions[name] = decoded;
|
|
343
|
-
}
|
|
344
|
-
return deepFreeze({ projectTrusted: value.projectTrusted, ...(globalExtensionSettings === undefined ? {} : { globalExtensionSettings }), ...(projectExtensionSettings === undefined ? {} : { projectExtensionSettings }), agentDefinitions });
|
|
345
|
-
}
|
|
346
|
-
function standaloneExternalConfiguration(context, dependencies) {
|
|
347
|
-
const cwd = context.extensionContext.cwd;
|
|
348
|
-
const trustedProject = context.extensionContext.isProjectTrusted();
|
|
349
|
-
const agentDir = dependencies.agentDir ?? getAgentDir();
|
|
350
|
-
const resolution = resolveWorkflowSettings(cwd, trustedProject, workflowSettingsPath(agentDir));
|
|
351
|
-
const globalExtensionSettings = resolution.global.extensionSettings;
|
|
352
|
-
const projectExtensionSettings = resolution.project.extensionSettings;
|
|
353
|
-
return deepFreeze({
|
|
354
|
-
projectTrusted: trustedProject,
|
|
355
|
-
...(globalExtensionSettings === undefined ? {} : { globalExtensionSettings: structuredClone(globalExtensionSettings) }),
|
|
356
|
-
...(projectExtensionSettings === undefined ? {} : { projectExtensionSettings: structuredClone(projectExtensionSettings) }),
|
|
357
|
-
agentDefinitions: structuredClone(loadAgentDefinitions(cwd, agentDir, trustedProject)),
|
|
358
|
-
});
|
|
320
|
+
return decodePreparedAgentConfiguration(value.configuration);
|
|
359
321
|
}
|
|
360
322
|
function checkedId(request) {
|
|
361
323
|
if (typeof request.id !== "string" || !validSubagentId(request.id))
|
|
@@ -715,7 +677,8 @@ async function createRunStorage(root, id, request, status, external) {
|
|
|
715
677
|
created = true;
|
|
716
678
|
await chmod(directory, 0o700);
|
|
717
679
|
await atomicJson(requestPath(directory), request);
|
|
718
|
-
|
|
680
|
+
if (external !== undefined)
|
|
681
|
+
await atomicJson(configurationPath(directory), { version: 1, configuration: external });
|
|
719
682
|
await atomicJson(statusPath(directory), status);
|
|
720
683
|
return directory;
|
|
721
684
|
}
|
|
@@ -935,6 +898,7 @@ function unavailable(operation) {
|
|
|
935
898
|
class PersistentSubagentManager {
|
|
936
899
|
dependencies;
|
|
937
900
|
activeRuns = new Map();
|
|
901
|
+
pendingStarts = new Set();
|
|
938
902
|
activeRunCount = 0;
|
|
939
903
|
terminalSummaries = new Map();
|
|
940
904
|
reconciliationErrors = new Map();
|
|
@@ -991,8 +955,8 @@ class PersistentSubagentManager {
|
|
|
991
955
|
throw new WorkflowError("CANCELLED", "Subagent manager is disposed");
|
|
992
956
|
if (context.signal?.aborted)
|
|
993
957
|
throw new WorkflowError("CANCELLED", "Subagent cancelled");
|
|
994
|
-
const external = frozenExternal
|
|
995
|
-
if (external
|
|
958
|
+
const external = frozenExternal;
|
|
959
|
+
if (external?.projectTrusted && !context.extensionContext.isProjectTrusted())
|
|
996
960
|
throw new WorkflowError("RESUME_INCOMPATIBLE", "Cannot retry standalone configuration from an untrusted project");
|
|
997
961
|
const id = randomUUID();
|
|
998
962
|
const startedAt = Date.now();
|
|
@@ -1009,9 +973,16 @@ class PersistentSubagentManager {
|
|
|
1009
973
|
this.activeRunCount += 1;
|
|
1010
974
|
const controller = new AbortController();
|
|
1011
975
|
const initialStatus = { id, sessionId, state: "running", startedAt, owner: { ...owner } };
|
|
976
|
+
let finishStart;
|
|
977
|
+
const pendingStart = new Promise((resolve) => { finishStart = resolve; });
|
|
978
|
+
this.pendingStarts.add(pendingStart);
|
|
1012
979
|
let directory;
|
|
1013
980
|
try {
|
|
1014
981
|
directory = await createRunStorage(storageDirectory(this.dependencies), id, snapshot, initialStatus, external);
|
|
982
|
+
if (this.disposePromise !== undefined || context.signal?.aborted) {
|
|
983
|
+
await atomicJson(statusPath(directory), reconciledStatus(initialStatus, "stopped", Date.now()));
|
|
984
|
+
throw new WorkflowError("CANCELLED", "Subagent cancelled");
|
|
985
|
+
}
|
|
1015
986
|
}
|
|
1016
987
|
catch (error) {
|
|
1017
988
|
this.activeRunCount -= 1;
|
|
@@ -1019,6 +990,10 @@ class PersistentSubagentManager {
|
|
|
1019
990
|
throw error;
|
|
1020
991
|
throw internalStorageError(error, `Unable to start subagent ${id}`);
|
|
1021
992
|
}
|
|
993
|
+
finally {
|
|
994
|
+
this.pendingStarts.delete(pendingStart);
|
|
995
|
+
finishStart();
|
|
996
|
+
}
|
|
1022
997
|
const current = {};
|
|
1023
998
|
let resolveTerminal;
|
|
1024
999
|
const terminal = new Promise((resolve) => { resolveTerminal = resolve; });
|
|
@@ -1049,13 +1024,9 @@ class PersistentSubagentManager {
|
|
|
1049
1024
|
throw new WorkflowError("CANCELLED", "Subagent cancelled");
|
|
1050
1025
|
}
|
|
1051
1026
|
}
|
|
1052
|
-
const baseRoot = executionRoot(context, this.dependencies, controller.signal, id, worktree
|
|
1053
|
-
const root = loadingRegistry().modelAliases().length === 0 ? baseRoot : await addDynamicAliases(context, controller.signal, baseRoot);
|
|
1027
|
+
const baseRoot = executionRoot(context, this.dependencies, controller.signal, id, worktree);
|
|
1028
|
+
const root = external !== undefined || loadingRegistry().modelAliases().length === 0 ? baseRoot : await addDynamicAliases(context, controller.signal, baseRoot);
|
|
1054
1029
|
const transport = this.dependencies.transport ?? localAgentTransport;
|
|
1055
|
-
const injectedExecutor = this.dependencies.createExecutor?.(root, transport);
|
|
1056
|
-
executorOwnership.default = injectedExecutor === undefined;
|
|
1057
|
-
if (current.run)
|
|
1058
|
-
current.run.executorOwnsSession = executorOwnership.default;
|
|
1059
1030
|
const setSteer = (handler) => {
|
|
1060
1031
|
const run = current.run;
|
|
1061
1032
|
if (run)
|
|
@@ -1106,6 +1077,15 @@ class PersistentSubagentManager {
|
|
|
1106
1077
|
return;
|
|
1107
1078
|
emitUpdate(run);
|
|
1108
1079
|
}, (progress) => this.recordProgress(current.run, progress));
|
|
1080
|
+
if (external !== undefined)
|
|
1081
|
+
options.configuration = structuredClone(external);
|
|
1082
|
+
options.onConfiguration = (configuration) => atomicJson(configurationPath(directory), { version: 1, configuration });
|
|
1083
|
+
const cwd = worktree?.cwd ?? root.cwd;
|
|
1084
|
+
options.configuration = await new WorkflowAgentExecutor(root, transport).prepare(options, cwd, controller.signal);
|
|
1085
|
+
const injectedExecutor = this.dependencies.createExecutor?.({ ...root, extensionSettings: options.configuration.settings }, transport);
|
|
1086
|
+
executorOwnership.default = injectedExecutor === undefined;
|
|
1087
|
+
if (current.run)
|
|
1088
|
+
current.run.executorOwnsSession = executorOwnership.default;
|
|
1109
1089
|
if (injectedExecutor)
|
|
1110
1090
|
return injectedExecutor.execute(snapshot.prompt, options, controller.signal, setSteer);
|
|
1111
1091
|
return new WorkflowAgentExecutor(root, transport).execute(snapshot.prompt, options, controller.signal, [], setSteer);
|
|
@@ -1156,9 +1136,9 @@ class PersistentSubagentManager {
|
|
|
1156
1136
|
}
|
|
1157
1137
|
return inspection;
|
|
1158
1138
|
}
|
|
1159
|
-
return this.inspectList();
|
|
1139
|
+
return this.inspectList(request.scope === "all" ? undefined : context.extensionContext.sessionManager.getSessionId());
|
|
1160
1140
|
}
|
|
1161
|
-
async inspectList() {
|
|
1141
|
+
async inspectList(sessionId) {
|
|
1162
1142
|
const root = storageDirectory(this.dependencies);
|
|
1163
1143
|
await secureDirectory(root);
|
|
1164
1144
|
const entries = await readdir(root, { withFileTypes: true });
|
|
@@ -1172,7 +1152,7 @@ class PersistentSubagentManager {
|
|
|
1172
1152
|
try {
|
|
1173
1153
|
const active = this.activeRuns.get(entry.name);
|
|
1174
1154
|
const status = publicStatus(active ? persistedStatus(active) : this.terminalSummaries.get(entry.name) ?? await loadPersistedStatus(root, entry.name, false));
|
|
1175
|
-
if (status.startedAt === undefined)
|
|
1155
|
+
if (status.startedAt === undefined || (sessionId !== undefined && status.sessionId !== sessionId))
|
|
1176
1156
|
continue;
|
|
1177
1157
|
statuses.push({ status, startedAt: status.startedAt });
|
|
1178
1158
|
}
|
|
@@ -1228,11 +1208,11 @@ class PersistentSubagentManager {
|
|
|
1228
1208
|
async dispose() {
|
|
1229
1209
|
if (this.disposePromise)
|
|
1230
1210
|
return this.disposePromise;
|
|
1211
|
+
this.disposed = true;
|
|
1231
1212
|
this.disposePromise = (async () => {
|
|
1232
1213
|
await this.initialization;
|
|
1233
|
-
this.disposed = true;
|
|
1234
1214
|
const runs = [...this.activeRuns.values()];
|
|
1235
|
-
await Promise.allSettled(runs.map((run) => this.stopRun(run, true)));
|
|
1215
|
+
await Promise.allSettled([...this.pendingStarts, ...runs.map((run) => this.stopRun(run, true))]);
|
|
1236
1216
|
await Promise.allSettled([...this.notificationPromises]);
|
|
1237
1217
|
const owner = this.storageOwner;
|
|
1238
1218
|
this.storageOwner = undefined;
|
|
@@ -1610,9 +1590,8 @@ class PersistentSubagentManager {
|
|
|
1610
1590
|
if (!notify || run.notificationSent || run.disposed)
|
|
1611
1591
|
return;
|
|
1612
1592
|
run.notificationSent = true;
|
|
1613
|
-
const
|
|
1614
|
-
const
|
|
1615
|
-
const notification = { id: run.id, label, role, state: run.state, ...(run.error === undefined ? {} : { error: run.error }) };
|
|
1593
|
+
const label = run.request.label?.trim() || "subagent";
|
|
1594
|
+
const notification = { id: run.id, label, state: run.state, ...(run.error === undefined ? {} : { error: run.error }) };
|
|
1616
1595
|
const pending = Promise.resolve().then(() => notify(notification));
|
|
1617
1596
|
this.notificationPromises.add(pending);
|
|
1618
1597
|
void pending.then(() => { this.notificationPromises.delete(pending); }, () => { this.notificationPromises.delete(pending); });
|
|
@@ -60,17 +60,9 @@ async function inspectEntry(manager, storageDirectory, entry, context) {
|
|
|
60
60
|
entry: { status: inspected.status, ...(request.request === undefined ? {} : { request: request.request }), ...(request.error === undefined ? {} : { requestError: request.error }) },
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
function requestRole(request) {
|
|
64
|
-
const role = request?.role;
|
|
65
|
-
if (typeof role === "string" && role.trim())
|
|
66
|
-
return role.trim();
|
|
67
|
-
const override = objectValue(role);
|
|
68
|
-
return typeof override?.name === "string" && override.name.trim() ? override.name.trim() : "none";
|
|
69
|
-
}
|
|
70
63
|
function shortId(id) { return id.length > 12 ? id.slice(0, 8) : id; }
|
|
71
64
|
function entryName(entry) {
|
|
72
|
-
|
|
73
|
-
return boundedText(entry.request?.label?.trim() || (role === "none" ? shortId(entry.status.id) : role), 256);
|
|
65
|
+
return boundedText(entry.request?.label?.trim() || shortId(entry.status.id), 256);
|
|
74
66
|
}
|
|
75
67
|
/** Names for a list of runs; a repeated name carries its short ID, as in the `/workflow` picker, so every row stays unique. */
|
|
76
68
|
function listNames(entries) {
|
|
@@ -108,7 +100,7 @@ function usageAccounting(status) {
|
|
|
108
100
|
return status.progress?.accounting;
|
|
109
101
|
}
|
|
110
102
|
function detailPresentation(inspection) {
|
|
111
|
-
const { status
|
|
103
|
+
const { status } = inspection.entry;
|
|
112
104
|
const attempt = latestAttempt(status);
|
|
113
105
|
const state = status.progress?.state;
|
|
114
106
|
const activity = status.progress?.activity;
|
|
@@ -117,14 +109,12 @@ function detailPresentation(inspection) {
|
|
|
117
109
|
const lastEventAt = status.progress?.lastEventAt;
|
|
118
110
|
const attempts = status.attempts ?? attempt?.attempt;
|
|
119
111
|
const accounting = usageAccounting(status);
|
|
120
|
-
const role = requestRole(request);
|
|
121
112
|
const error = status.error ?? attempt?.error;
|
|
122
113
|
return {
|
|
123
114
|
state: status.state,
|
|
124
115
|
...(activity === undefined ? {} : { activity: { kind: activity.kind, text: boundedText(activity.text) } }),
|
|
125
116
|
...(lastEventAt === undefined ? {} : { lastEventAt }),
|
|
126
117
|
...(model === undefined ? {} : { model: { provider: boundedText(model.provider, 256), model: boundedText(model.model, 256), ...(model.thinking === undefined ? {} : { thinking: model.thinking }) } }),
|
|
127
|
-
...(role === "none" ? {} : { role: boundedText(role, 256) }),
|
|
128
118
|
...(tools === undefined ? {} : { tools: tools.slice(0, 256).map((tool) => boundedText(tool, 256)) }),
|
|
129
119
|
...(attempts === undefined ? {} : { attempts }),
|
|
130
120
|
...(status.startedAt === undefined ? {} : { startedAt: status.startedAt }),
|
|
@@ -178,8 +168,7 @@ function standaloneActionContext(manager, inspection, context) {
|
|
|
178
168
|
const session = attempt.session;
|
|
179
169
|
const live = liveData?.liveSession && session && liveData.liveSession.reference.transport === session.transport && liveData.liveSession.reference.sessionId === session.sessionId ? liveData.liveSession : undefined;
|
|
180
170
|
const label = request?.label?.trim();
|
|
181
|
-
const
|
|
182
|
-
const name = label || (role === "none" ? "subagent" : role);
|
|
171
|
+
const name = label || "subagent";
|
|
183
172
|
const ui = {
|
|
184
173
|
notify: (message, level = "info") => { context.ui.notify(message, level); },
|
|
185
174
|
confirm: (title, message) => context.ui.confirm(title, message),
|
|
@@ -42,7 +42,6 @@ type SubagentReceipt = {
|
|
|
42
42
|
readonly label: string;
|
|
43
43
|
readonly state: string;
|
|
44
44
|
readonly model?: string;
|
|
45
|
-
readonly role?: string;
|
|
46
45
|
readonly tools?: readonly string[];
|
|
47
46
|
readonly input: number;
|
|
48
47
|
readonly output: number;
|
|
@@ -65,6 +64,7 @@ export declare function createSubagentBackgroundWidget(host?: ReceiptHost): {
|
|
|
65
64
|
};
|
|
66
65
|
export declare function renderSubagentInspectCall(args: {
|
|
67
66
|
id?: string;
|
|
67
|
+
scope?: string;
|
|
68
68
|
}, theme: Theme): {
|
|
69
69
|
render(width: number): string[];
|
|
70
70
|
invalidate(): void;
|