@ian-pascoe/pi-minimal-subagents 0.1.1 → 0.2.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/README.md +58 -5
- package/package.json +1 -1
- package/src/minimal-subagents-capabilities.ts +7 -0
- package/src/minimal-subagents-config.ts +182 -65
- package/src/minimal-subagents-context.ts +7 -1
- package/src/minimal-subagents-coordinator.ts +938 -114
- package/src/minimal-subagents-delivery-ledger.ts +529 -0
- package/src/minimal-subagents-extension.ts +382 -64
- package/src/minimal-subagents-fork-lifecycle.ts +22 -12
- package/src/minimal-subagents-message-envelope.ts +20 -0
- package/src/minimal-subagents-registry-wire.ts +269 -0
- package/src/minimal-subagents-registry.ts +1505 -132
- package/src/minimal-subagents-render-contract.ts +301 -0
- package/src/minimal-subagents-rendering.ts +513 -372
- package/src/minimal-subagents-session-wire.ts +42 -0
- package/src/minimal-subagents-sessions.ts +427 -101
- package/src/minimal-subagents-shutdown.ts +1 -1
- package/src/minimal-subagents-tool-schemas.ts +21 -7
- package/src/minimal-subagents-tools.ts +70 -21
- package/src/minimal-subagents-types.ts +65 -14
- package/src/minimal-subagents-ui.ts +8 -5
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
|
-
import { Type
|
|
2
|
+
import { Type } from "typebox";
|
|
3
3
|
import { THINKING_LEVELS } from "./minimal-subagents-capabilities.js";
|
|
4
4
|
|
|
5
5
|
const SessionContextSchema = StringEnum(["inherit", "compact", "omit"] as const);
|
|
6
6
|
const ProjectContextSchema = StringEnum(["inherit", "omit"] as const);
|
|
7
7
|
const DelegationSchema = StringEnum(["none", "fanout"] as const);
|
|
8
8
|
const ThinkingLevelSchema = StringEnum(THINKING_LEVELS);
|
|
9
|
-
const ToolSelectionSchema = Type.Union(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const ToolSelectionSchema = Type.Union(
|
|
10
|
+
[
|
|
11
|
+
StringEnum(["none", "read", "modify"] as const),
|
|
12
|
+
Type.Array(Type.String({ minLength: 1 }), {
|
|
13
|
+
uniqueItems: true,
|
|
14
|
+
description:
|
|
15
|
+
"Exact ordinary tool names. Coordinator tools are injected separately and must not appear here. Arrays are not bundle names; use the string preset `read` or `modify` for bundled capabilities.",
|
|
16
|
+
}),
|
|
17
|
+
],
|
|
18
|
+
{
|
|
19
|
+
description:
|
|
20
|
+
'Use the string preset "read" for read, grep, find, and ls; use "modify" for the read bundle plus bash, edit, and write. An array grants exactly those named tools (ordinary tools only); coordinator tools are injected separately.',
|
|
21
|
+
},
|
|
22
|
+
);
|
|
13
23
|
const FRIENDLY_AGENT_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$";
|
|
14
24
|
const CANONICAL_AGENT_ID_PATTERN =
|
|
15
25
|
"^(?:root\\.)?[A-Za-z0-9][A-Za-z0-9_-]{0,63}(?:\\.[A-Za-z0-9][A-Za-z0-9_-]{0,63})*$";
|
|
@@ -20,8 +30,9 @@ function canonicalAgentIdSchema(description?: string) {
|
|
|
20
30
|
|
|
21
31
|
/** Build all six strict TypeBox schemas, including the refreshed runtime model enum. */
|
|
22
32
|
export function createCoordinatorToolSchemas(modelIds: readonly string[]) {
|
|
23
|
-
const
|
|
24
|
-
|
|
33
|
+
const [firstModelId, ...remainingModelIds] = modelIds;
|
|
34
|
+
const explicitModelSchema =
|
|
35
|
+
firstModelId === undefined ? Type.Never() : StringEnum([firstModelId, ...remainingModelIds]);
|
|
25
36
|
return {
|
|
26
37
|
subagent: Type.Object({
|
|
27
38
|
task: Type.String({ minLength: 1, description: "Task for the persistent child agent" }),
|
|
@@ -49,6 +60,9 @@ export function createCoordinatorToolSchemas(modelIds: readonly string[]) {
|
|
|
49
60
|
}),
|
|
50
61
|
subagent_wait: Type.Object({
|
|
51
62
|
agent_id: canonicalAgentIdSchema("Direct child canonical agent ID"),
|
|
63
|
+
turn_id: Type.Optional(
|
|
64
|
+
Type.String({ minLength: 1, description: "Exact retained child turn ID" }),
|
|
65
|
+
),
|
|
52
66
|
timeout_ms: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
53
67
|
}),
|
|
54
68
|
subagent_status: Type.Object({
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type ToolDefinition,
|
|
10
10
|
type ToolRenderResultOptions,
|
|
11
11
|
} from "@earendil-works/pi-coding-agent";
|
|
12
|
+
import type { Static } from "typebox";
|
|
12
13
|
import type { MinimalSubagentsCoordinator } from "./minimal-subagents-coordinator.js";
|
|
13
14
|
import type { MinimalSubagentsModelRole } from "./minimal-subagents-config.js";
|
|
14
15
|
import {
|
|
@@ -16,8 +17,17 @@ import {
|
|
|
16
17
|
renderCoordinatorToolResult,
|
|
17
18
|
type CoordinatorToolName,
|
|
18
19
|
} from "./minimal-subagents-rendering.js";
|
|
20
|
+
import type { CoordinatorToolCallInput } from "./minimal-subagents-render-contract.js";
|
|
19
21
|
import type { createCoordinatorToolSchemas } from "./minimal-subagents-tool-schemas.js";
|
|
20
|
-
import type {
|
|
22
|
+
import type {
|
|
23
|
+
AgentMessageResult,
|
|
24
|
+
CallerSnapshot,
|
|
25
|
+
CancelResult,
|
|
26
|
+
DeleteResult,
|
|
27
|
+
SpawnResult,
|
|
28
|
+
StatusResult,
|
|
29
|
+
WaitResult,
|
|
30
|
+
} from "./minimal-subagents-types.js";
|
|
21
31
|
|
|
22
32
|
const ORDINARY_CHILD_COORDINATOR_TOOL_NAMES = new Set([
|
|
23
33
|
"agent_message",
|
|
@@ -25,8 +35,15 @@ const ORDINARY_CHILD_COORDINATOR_TOOL_NAMES = new Set([
|
|
|
25
35
|
"subagent_status",
|
|
26
36
|
]);
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
/** Coordinator operations consumed by the six public coordinator tool definitions. */
|
|
39
|
+
export type CoordinatorToolOperations = Pick<
|
|
40
|
+
MinimalSubagentsCoordinator,
|
|
41
|
+
"spawn" | "inspectStatus" | "sendAgentMessage" | "wait" | "status" | "cancel" | "delete"
|
|
42
|
+
>;
|
|
43
|
+
|
|
44
|
+
/** Dependencies and caller policy used to create caller-bound coordinator tools. */
|
|
45
|
+
export interface CoordinatorToolDefinitionOptions {
|
|
46
|
+
coordinator: CoordinatorToolOperations;
|
|
30
47
|
callerId: string;
|
|
31
48
|
allowFanoutTools?: boolean;
|
|
32
49
|
modelRoles?: readonly MinimalSubagentsModelRole[];
|
|
@@ -36,6 +53,27 @@ interface CoordinatorToolDefinitionOptions {
|
|
|
36
53
|
onAttention?: (message: string) => void;
|
|
37
54
|
}
|
|
38
55
|
|
|
56
|
+
/** Arguments consumed by the wait tool's narrow coordinator execution seam. */
|
|
57
|
+
export type CoordinatorWaitToolParameters = Static<
|
|
58
|
+
ReturnType<typeof createCoordinatorToolSchemas>["subagent_wait"]
|
|
59
|
+
>;
|
|
60
|
+
|
|
61
|
+
/** Forward one typed wait-tool request without requiring an unrelated Pi execution context. */
|
|
62
|
+
export function executeCoordinatorWaitTool(
|
|
63
|
+
coordinator: Pick<CoordinatorToolOperations, "wait">,
|
|
64
|
+
callerId: string,
|
|
65
|
+
parameters: CoordinatorWaitToolParameters,
|
|
66
|
+
signal: AbortSignal | undefined,
|
|
67
|
+
): Promise<WaitResult> {
|
|
68
|
+
return coordinator.wait(
|
|
69
|
+
callerId,
|
|
70
|
+
parameters.agent_id,
|
|
71
|
+
parameters.timeout_ms,
|
|
72
|
+
signal,
|
|
73
|
+
parameters.turn_id,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
39
77
|
function buildModelRolePromptGuidelines(
|
|
40
78
|
modelRoles: readonly MinimalSubagentsModelRole[],
|
|
41
79
|
): string[] | undefined {
|
|
@@ -61,15 +99,24 @@ async function runCoordinatorToolActivity<T>(
|
|
|
61
99
|
}
|
|
62
100
|
}
|
|
63
101
|
|
|
102
|
+
type CoordinatorToolResultDetails =
|
|
103
|
+
| SpawnResult
|
|
104
|
+
| AgentMessageResult
|
|
105
|
+
| WaitResult
|
|
106
|
+
| StatusResult
|
|
107
|
+
| CancelResult
|
|
108
|
+
| DeleteResult
|
|
109
|
+
| { agent_id: string; status: "waiting"; elapsed_ms: number };
|
|
110
|
+
|
|
64
111
|
function createCoordinatorToolRendering(toolName: CoordinatorToolName) {
|
|
65
112
|
return {
|
|
66
|
-
renderCall: (args:
|
|
113
|
+
renderCall: (args: CoordinatorToolCallInput, theme: Theme) =>
|
|
67
114
|
renderCoordinatorToolCall(toolName, args, theme),
|
|
68
115
|
renderResult: (
|
|
69
|
-
result: AgentToolResult<
|
|
116
|
+
result: AgentToolResult<CoordinatorToolResultDetails>,
|
|
70
117
|
renderOptions: ToolRenderResultOptions,
|
|
71
118
|
theme: Theme,
|
|
72
|
-
context: { args:
|
|
119
|
+
context: { args: CoordinatorToolCallInput; isError: boolean },
|
|
73
120
|
) =>
|
|
74
121
|
renderCoordinatorToolResult(
|
|
75
122
|
toolName,
|
|
@@ -82,7 +129,9 @@ function createCoordinatorToolRendering(toolName: CoordinatorToolName) {
|
|
|
82
129
|
};
|
|
83
130
|
}
|
|
84
131
|
|
|
85
|
-
function structuredToolResult
|
|
132
|
+
function structuredToolResult<TDetails extends CoordinatorToolResultDetails>(
|
|
133
|
+
result: TDetails,
|
|
134
|
+
): AgentToolResult<TDetails> {
|
|
86
135
|
const json = JSON.stringify(result, null, 2);
|
|
87
136
|
const truncated = truncateHead(json, {
|
|
88
137
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
@@ -94,7 +143,7 @@ function structuredToolResult(result: unknown) {
|
|
|
94
143
|
};
|
|
95
144
|
}
|
|
96
145
|
|
|
97
|
-
function failedStructuredOperation(prefix: string, result:
|
|
146
|
+
function failedStructuredOperation(prefix: string, result: DeleteResult): never {
|
|
98
147
|
const json = JSON.stringify(result);
|
|
99
148
|
const truncated = truncateHead(json, {
|
|
100
149
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
@@ -104,7 +153,7 @@ function failedStructuredOperation(prefix: string, result: unknown): never {
|
|
|
104
153
|
}
|
|
105
154
|
|
|
106
155
|
function callerSourceTurnId(
|
|
107
|
-
coordinator:
|
|
156
|
+
coordinator: CoordinatorToolOperations,
|
|
108
157
|
callerId: string,
|
|
109
158
|
toolCallId: string,
|
|
110
159
|
): string {
|
|
@@ -132,17 +181,17 @@ export function createCoordinatorToolDefinitions(
|
|
|
132
181
|
return runCoordinatorToolActivity(options, async () => {
|
|
133
182
|
const result = await options.coordinator.spawn(
|
|
134
183
|
options.callerId,
|
|
135
|
-
parameters
|
|
184
|
+
parameters,
|
|
136
185
|
options.captureCaller(context),
|
|
137
186
|
);
|
|
138
187
|
const status = options.coordinator.inspectStatus(result.agent_id);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
...(status && "agent" in status ? { agent: status.agent } : {}),
|
|
144
|
-
},
|
|
188
|
+
const details: SpawnResult & {
|
|
189
|
+
agent?: import("./minimal-subagents-types.js").AgentDetail;
|
|
190
|
+
} = {
|
|
191
|
+
...result,
|
|
145
192
|
};
|
|
193
|
+
if (status && "agent" in status) details.agent = status.agent;
|
|
194
|
+
return structuredToolResult(details);
|
|
146
195
|
});
|
|
147
196
|
},
|
|
148
197
|
...createCoordinatorToolRendering("subagent"),
|
|
@@ -152,7 +201,7 @@ export function createCoordinatorToolDefinitions(
|
|
|
152
201
|
name: "agent_message",
|
|
153
202
|
label: "Agent Message",
|
|
154
203
|
description:
|
|
155
|
-
"Send one mid-turn coordination message to a direct parent, direct sibling, or direct child
|
|
204
|
+
"Send one mid-turn coordination message to a direct parent, direct sibling, or direct child. The result says whether it was delivered through an active wait, queued for the recipient, or failed.",
|
|
156
205
|
promptSnippet: "Coordinate required mid-turn action with one adjacent agent",
|
|
157
206
|
parameters: options.schemas.agent_message,
|
|
158
207
|
async execute(toolCallId, parameters) {
|
|
@@ -175,7 +224,7 @@ export function createCoordinatorToolDefinitions(
|
|
|
175
224
|
name: "subagent_wait",
|
|
176
225
|
label: "Subagent Wait",
|
|
177
226
|
description:
|
|
178
|
-
"Wait for one direct child's
|
|
227
|
+
"Wait for one direct child's oldest observable turn, or select an exact retained turn_id. A Wait Event containing a Coordination Message may arrive first as event=message; call again for the terminal turn result. A successful wait durably claims that turn so later messages and its terminal result return through wait without duplicate automatic delivery. Timeout never cancels the child.",
|
|
179
228
|
promptSnippet: "Wait for one direct child's exact turn",
|
|
180
229
|
parameters: options.schemas.subagent_wait,
|
|
181
230
|
async execute(_toolCallId, parameters, signal, onUpdate) {
|
|
@@ -194,10 +243,10 @@ export function createCoordinatorToolDefinitions(
|
|
|
194
243
|
waitingInterval.unref?.();
|
|
195
244
|
try {
|
|
196
245
|
return await runCoordinatorToolActivity(options, async () => {
|
|
197
|
-
const result = await
|
|
246
|
+
const result = await executeCoordinatorWaitTool(
|
|
247
|
+
options.coordinator,
|
|
198
248
|
options.callerId,
|
|
199
|
-
parameters
|
|
200
|
-
parameters.timeout_ms,
|
|
249
|
+
parameters,
|
|
201
250
|
signal,
|
|
202
251
|
);
|
|
203
252
|
return {
|
|
@@ -58,13 +58,29 @@ export interface TurnResult {
|
|
|
58
58
|
elapsed_ms?: number;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/** Reports
|
|
61
|
+
/** Reports whether one direct message was handed to a wait, queued, or failed. */
|
|
62
|
+
export type AgentMessageDisposition = "delivered-via-wait" | "queued" | "failed";
|
|
63
|
+
|
|
62
64
|
export interface AgentMessageResult {
|
|
63
65
|
agent_id: string;
|
|
64
|
-
|
|
66
|
+
message_id: string;
|
|
67
|
+
disposition: AgentMessageDisposition;
|
|
65
68
|
error?: string;
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/** Reports one coordination message returned before the source turn settles. */
|
|
72
|
+
export interface WaitMessageResult {
|
|
73
|
+
event: "message";
|
|
74
|
+
agent_id: string;
|
|
75
|
+
turn_id: string;
|
|
76
|
+
message_id: string;
|
|
77
|
+
delivery_id?: string;
|
|
78
|
+
message: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Reports one terminal child turn returned by subagent_wait. */
|
|
82
|
+
export type WaitResult = WaitMessageResult | ({ event: "turn" } & TurnResult);
|
|
83
|
+
|
|
68
84
|
/** Provides bounded hierarchy, usage, and best-known Runtime Profile data for one persistent agent. */
|
|
69
85
|
export interface AgentSummary extends RuntimeProfile {
|
|
70
86
|
agent_id: string;
|
|
@@ -92,7 +108,7 @@ export interface RecentAgentMessage {
|
|
|
92
108
|
/** Extends summary status with launch, dependency, and recent-message diagnostics. */
|
|
93
109
|
export interface AgentDetail extends AgentSummary {
|
|
94
110
|
session_file?: string;
|
|
95
|
-
launch_contract:
|
|
111
|
+
launch_contract: LaunchContract;
|
|
96
112
|
capability_ceiling: string[];
|
|
97
113
|
spawn_entry_id: string;
|
|
98
114
|
recent_messages: RecentAgentMessage[];
|
|
@@ -164,6 +180,8 @@ export interface CoordinatorMessage {
|
|
|
164
180
|
source_agent_id: string;
|
|
165
181
|
destination_agent_id?: string;
|
|
166
182
|
source_turn_id: string;
|
|
183
|
+
message_id: string;
|
|
184
|
+
delivery_id?: string;
|
|
167
185
|
status?: TurnStatus;
|
|
168
186
|
elapsed_ms?: number;
|
|
169
187
|
usage?: Usage;
|
|
@@ -174,6 +192,7 @@ export interface CoordinatorMessage {
|
|
|
174
192
|
export interface ChildAgentRuntime {
|
|
175
193
|
readonly sessionFile: string;
|
|
176
194
|
readonly sessionId: string;
|
|
195
|
+
readonly sessionLeafId: string | undefined;
|
|
177
196
|
readonly isRunning: boolean;
|
|
178
197
|
runPrompt(
|
|
179
198
|
task: string,
|
|
@@ -182,22 +201,22 @@ export interface ChildAgentRuntime {
|
|
|
182
201
|
callerThinkingLevel: ThinkingLevel,
|
|
183
202
|
): Promise<RuntimeTurnOutcome>;
|
|
184
203
|
runMessage(message: CoordinatorMessage): Promise<RuntimeTurnOutcome>;
|
|
185
|
-
/**
|
|
186
|
-
|
|
204
|
+
/** Queue one typed coordinator message into the child session. */
|
|
205
|
+
queueCoordinatorMessage(message: CoordinatorMessage): Promise<void>;
|
|
187
206
|
abort(): Promise<void>;
|
|
188
207
|
dispose(): void;
|
|
189
208
|
/** Return the live Runtime Profile, or undefined when the SDK session has no model. */
|
|
190
209
|
getRuntimeProfile(): RuntimeProfile | undefined;
|
|
191
210
|
snapshotCommittedMessages(): AgentMessage[];
|
|
192
|
-
hasDeliveryEvidence(sourceAgentId: string, sourceTurnId: string): boolean;
|
|
211
|
+
hasDeliveryEvidence(sourceAgentId: string, sourceTurnId: string, deliveryId?: string): boolean;
|
|
193
212
|
getUsage(): Usage | undefined;
|
|
194
|
-
cloneSession(): Promise<{ sessionFile: string; sessionId: string }>;
|
|
195
213
|
}
|
|
196
214
|
|
|
197
215
|
/** Identifies one writable child JSONL session owned by a coordinator root. */
|
|
198
216
|
export interface PersistedSessionIdentity {
|
|
199
217
|
sessionFile: string;
|
|
200
218
|
sessionId: string;
|
|
219
|
+
sessionLeafId?: string;
|
|
201
220
|
}
|
|
202
221
|
|
|
203
222
|
/** Combines a persisted agent record with first-launch imported context. */
|
|
@@ -215,15 +234,28 @@ export interface AgentSessionFactory {
|
|
|
215
234
|
resolveRestorationMissingDependencies(agent: PersistedAgent): Promise<string[]>;
|
|
216
235
|
resolveThinkingLevel(modelId: string, requested: ThinkingLevel): ThinkingLevel;
|
|
217
236
|
modelSupportsImages(modelId: string): boolean;
|
|
237
|
+
/** Clone a child leaf owned by the active source root during confirmed shutdown. */
|
|
218
238
|
cloneSession(agent: PersistedAgent): Promise<PersistedSessionIdentity>;
|
|
219
|
-
|
|
239
|
+
/** Clone a source-owned leaf recovered from a proven destination branch. */
|
|
240
|
+
cloneForkSourceSession(
|
|
241
|
+
agent: PersistedAgent,
|
|
242
|
+
sourceRootSessionId: string,
|
|
243
|
+
): Promise<PersistedSessionIdentity>;
|
|
244
|
+
/** Append and verify destination-root ownership for one fork clone. */
|
|
245
|
+
adoptForkSessionOwnership(
|
|
246
|
+
agent: PersistedAgent,
|
|
247
|
+
sourceRootSessionId: string,
|
|
248
|
+
): Promise<PersistedSessionIdentity>;
|
|
249
|
+
trashSession(agent: PersistedAgent): Promise<void>;
|
|
220
250
|
}
|
|
221
251
|
|
|
222
252
|
/** Abstracts root message delivery and durable delivery-evidence lookup. */
|
|
223
253
|
export interface RootConversationEndpoint {
|
|
224
|
-
/**
|
|
225
|
-
|
|
226
|
-
hasDeliveryEvidence(sourceAgentId: string, sourceTurnId: string): boolean;
|
|
254
|
+
/** Queue one typed coordinator message into the root conversation. */
|
|
255
|
+
queueCoordinatorMessage(message: CoordinatorMessage): Promise<void>;
|
|
256
|
+
hasDeliveryEvidence(sourceAgentId: string, sourceTurnId: string, deliveryId?: string): boolean;
|
|
257
|
+
/** Report whether automatic delivery can start a new root turn without racing an active wait. */
|
|
258
|
+
isIdle(): boolean;
|
|
227
259
|
}
|
|
228
260
|
|
|
229
261
|
/** Stores root-owned agent identity, launch contract, availability, and latest activity. */
|
|
@@ -237,6 +269,7 @@ export interface PersistedAgent {
|
|
|
237
269
|
spawn_entry_id: string;
|
|
238
270
|
session_file?: string;
|
|
239
271
|
session_id?: string;
|
|
272
|
+
session_leaf_id?: string;
|
|
240
273
|
clone_error?: string;
|
|
241
274
|
launch_contract: LaunchContract;
|
|
242
275
|
capability_ceiling: string[];
|
|
@@ -250,7 +283,7 @@ export interface PersistedAgent {
|
|
|
250
283
|
deleted?: boolean;
|
|
251
284
|
}
|
|
252
285
|
|
|
253
|
-
/** Records
|
|
286
|
+
/** Records which conversation path owns one successful terminal result. */
|
|
254
287
|
export type DeliveryPath = "wait" | "message";
|
|
255
288
|
|
|
256
289
|
/** Stores a keyed successful result until destination evidence settles delivery. */
|
|
@@ -260,26 +293,44 @@ export interface PersistedDelivery {
|
|
|
260
293
|
destination_agent_id: string;
|
|
261
294
|
path: DeliveryPath;
|
|
262
295
|
settled: boolean;
|
|
296
|
+
sequence?: number;
|
|
263
297
|
result?: TurnResult;
|
|
264
298
|
error?: string;
|
|
265
299
|
}
|
|
266
300
|
|
|
267
|
-
/**
|
|
301
|
+
/** Stores one durable Coordination Message until destination evidence settles it. */
|
|
302
|
+
export interface PersistedCoordinationDelivery {
|
|
303
|
+
delivery_id: string;
|
|
304
|
+
sequence: number;
|
|
305
|
+
destination_agent_id: string;
|
|
306
|
+
path: DeliveryPath;
|
|
307
|
+
settled: boolean;
|
|
308
|
+
message: CoordinatorMessage;
|
|
309
|
+
error?: string;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Checkpoints live agents, tombstones, and only pending delivery-ledger items for one root. */
|
|
268
313
|
export interface RegistrySnapshot {
|
|
269
314
|
agents: PersistedAgent[];
|
|
270
315
|
tombstones: string[];
|
|
271
316
|
deliveries: PersistedDelivery[];
|
|
317
|
+
coordination_deliveries?: PersistedCoordinationDelivery[];
|
|
318
|
+
wait_claimed_turns?: string[];
|
|
319
|
+
next_delivery_sequence?: number;
|
|
272
320
|
}
|
|
273
321
|
|
|
274
322
|
/** Clones a registry snapshot while recording the source root session file. */
|
|
275
323
|
export interface ForkSnapshot extends RegistrySnapshot {
|
|
324
|
+
/** Canonical Pi root session file from which the selected fork branch originated. */
|
|
276
325
|
source_root_session_file: string;
|
|
326
|
+
/** Root identity that every cloned Child Session provenance record must match. */
|
|
327
|
+
source_root_session_id: string;
|
|
277
328
|
}
|
|
278
329
|
|
|
279
330
|
/** Appends root-owned registry events to the active root conversation branch. */
|
|
280
331
|
export interface RegistryWriter {
|
|
281
332
|
readonly rootSessionId: string;
|
|
282
|
-
append(event: import("./minimal-subagents-registry.js").
|
|
333
|
+
append(event: import("./minimal-subagents-registry.js").RegistryEventV2): void;
|
|
283
334
|
}
|
|
284
335
|
|
|
285
336
|
/** Describes concise lifecycle notices surfaced through Pi UI notifications. */
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
/** Theme operations used by the Minimal Subagents widget renderer. */
|
|
4
|
+
export type MinimalSubagentsWidgetTheme = Pick<Theme, "fg" | "bold">;
|
|
2
5
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
6
|
import {
|
|
4
7
|
sliceByColumn,
|
|
@@ -195,7 +198,7 @@ function renderMinimalSubagentsWidgetRowParts(
|
|
|
195
198
|
task: string | undefined,
|
|
196
199
|
duration: string | undefined,
|
|
197
200
|
profile: string,
|
|
198
|
-
theme:
|
|
201
|
+
theme: MinimalSubagentsWidgetTheme,
|
|
199
202
|
): MinimalSubagentsWidgetRowParts {
|
|
200
203
|
const branch = row.depth > 0 ? `${" ".repeat(row.depth)}╰─ ` : " ";
|
|
201
204
|
const styledBranch = theme.fg("borderMuted", branch);
|
|
@@ -225,7 +228,7 @@ function minimalSubagentsWidgetProfileBudget(
|
|
|
225
228
|
task: string | undefined,
|
|
226
229
|
duration: string | undefined,
|
|
227
230
|
separator: string,
|
|
228
|
-
theme:
|
|
231
|
+
theme: MinimalSubagentsWidgetTheme,
|
|
229
232
|
width: number,
|
|
230
233
|
): number {
|
|
231
234
|
const fixedParts = renderMinimalSubagentsWidgetRowParts(row, task, duration, "", theme);
|
|
@@ -235,7 +238,7 @@ function minimalSubagentsWidgetProfileBudget(
|
|
|
235
238
|
function renderMinimalSubagentsWidgetRow(
|
|
236
239
|
row: MinimalSubagentsWidgetRow,
|
|
237
240
|
width: number,
|
|
238
|
-
theme:
|
|
241
|
+
theme: MinimalSubagentsWidgetTheme,
|
|
239
242
|
): string {
|
|
240
243
|
const separator = theme.fg("dim", MINIMAL_SUBAGENTS_WIDGET_SEPARATOR_TEXT);
|
|
241
244
|
const task = row.task?.replace(/\s+/g, " ").trim() || undefined;
|
|
@@ -336,7 +339,7 @@ function renderMinimalSubagentsWidgetRow(
|
|
|
336
339
|
export function renderMinimalSubagentsWidgetLines(
|
|
337
340
|
view: MinimalSubagentsWidgetView,
|
|
338
341
|
width: number,
|
|
339
|
-
theme:
|
|
342
|
+
theme: MinimalSubagentsWidgetTheme,
|
|
340
343
|
): string[] {
|
|
341
344
|
if (width <= 0) return [];
|
|
342
345
|
const separator = theme.fg("dim", MINIMAL_SUBAGENTS_WIDGET_SEPARATOR_TEXT);
|
|
@@ -376,7 +379,7 @@ class MinimalSubagentsWidgetComponent implements Component {
|
|
|
376
379
|
constructor(
|
|
377
380
|
private view: MinimalSubagentsWidgetView,
|
|
378
381
|
private readonly tui: TUI,
|
|
379
|
-
private readonly theme:
|
|
382
|
+
private readonly theme: MinimalSubagentsWidgetTheme,
|
|
380
383
|
) {}
|
|
381
384
|
|
|
382
385
|
update(view: MinimalSubagentsWidgetView): void {
|