@ian-pascoe/pi-minimal-subagents 0.1.0 → 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 +77 -9
- package/package.json +6 -6
- package/src/minimal-subagents-capabilities.ts +8 -8
- package/src/minimal-subagents-config.ts +222 -73
- package/src/minimal-subagents-context.ts +7 -1
- package/src/minimal-subagents-coordinator.ts +943 -116
- 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 +437 -101
- package/src/minimal-subagents-shutdown.ts +1 -1
- package/src/minimal-subagents-tool-schemas.ts +21 -7
- package/src/minimal-subagents-tools.ts +75 -25
- package/src/minimal-subagents-types.ts +76 -21
- package/src/minimal-subagents-ui.ts +214 -23
|
@@ -21,9 +21,9 @@ export async function shutdownMinimalSubagentsSession(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
while (true) {
|
|
24
|
+
if (!rootIdleGate.isRootIdle()) await rootIdleGate.waitForRootIdle();
|
|
24
25
|
await coordinator.waitForSettledOperations();
|
|
25
26
|
if (rootIdleGate.isRootIdle()) break;
|
|
26
|
-
await rootIdleGate.waitForRootIdle();
|
|
27
27
|
}
|
|
28
28
|
await coordinator.shutdownAfterSettling();
|
|
29
29
|
}
|
|
@@ -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,16 +53,38 @@ 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 {
|
|
42
80
|
if (modelRoles.length === 0) return undefined;
|
|
43
|
-
const roleLines = modelRoles.map(
|
|
44
|
-
|
|
45
|
-
|
|
81
|
+
const roleLines = modelRoles.map((role) => {
|
|
82
|
+
const thinkingGuidance = role.thinkingLevel ? `, thinking_level=${role.thinkingLevel}` : "";
|
|
83
|
+
return ` - ${role.name} → model=${role.model}${thinkingGuidance}${role.hint ? ` — ${role.hint}` : ""}`;
|
|
84
|
+
});
|
|
46
85
|
return [
|
|
47
86
|
["Configured model roles are guidance, not constraints:", ...roleLines].join("\n"),
|
|
48
|
-
"Choose a model based on the task.
|
|
87
|
+
"Choose a model based on the task. A listed thinking_level is a preference, not a constraint. Callers choose thinking_level independently for roles without one.",
|
|
49
88
|
];
|
|
50
89
|
}
|
|
51
90
|
|
|
@@ -60,15 +99,24 @@ async function runCoordinatorToolActivity<T>(
|
|
|
60
99
|
}
|
|
61
100
|
}
|
|
62
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
|
+
|
|
63
111
|
function createCoordinatorToolRendering(toolName: CoordinatorToolName) {
|
|
64
112
|
return {
|
|
65
|
-
renderCall: (args:
|
|
113
|
+
renderCall: (args: CoordinatorToolCallInput, theme: Theme) =>
|
|
66
114
|
renderCoordinatorToolCall(toolName, args, theme),
|
|
67
115
|
renderResult: (
|
|
68
|
-
result: AgentToolResult<
|
|
116
|
+
result: AgentToolResult<CoordinatorToolResultDetails>,
|
|
69
117
|
renderOptions: ToolRenderResultOptions,
|
|
70
118
|
theme: Theme,
|
|
71
|
-
context: { args:
|
|
119
|
+
context: { args: CoordinatorToolCallInput; isError: boolean },
|
|
72
120
|
) =>
|
|
73
121
|
renderCoordinatorToolResult(
|
|
74
122
|
toolName,
|
|
@@ -81,7 +129,9 @@ function createCoordinatorToolRendering(toolName: CoordinatorToolName) {
|
|
|
81
129
|
};
|
|
82
130
|
}
|
|
83
131
|
|
|
84
|
-
function structuredToolResult
|
|
132
|
+
function structuredToolResult<TDetails extends CoordinatorToolResultDetails>(
|
|
133
|
+
result: TDetails,
|
|
134
|
+
): AgentToolResult<TDetails> {
|
|
85
135
|
const json = JSON.stringify(result, null, 2);
|
|
86
136
|
const truncated = truncateHead(json, {
|
|
87
137
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
@@ -93,7 +143,7 @@ function structuredToolResult(result: unknown) {
|
|
|
93
143
|
};
|
|
94
144
|
}
|
|
95
145
|
|
|
96
|
-
function failedStructuredOperation(prefix: string, result:
|
|
146
|
+
function failedStructuredOperation(prefix: string, result: DeleteResult): never {
|
|
97
147
|
const json = JSON.stringify(result);
|
|
98
148
|
const truncated = truncateHead(json, {
|
|
99
149
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
@@ -103,7 +153,7 @@ function failedStructuredOperation(prefix: string, result: unknown): never {
|
|
|
103
153
|
}
|
|
104
154
|
|
|
105
155
|
function callerSourceTurnId(
|
|
106
|
-
coordinator:
|
|
156
|
+
coordinator: CoordinatorToolOperations,
|
|
107
157
|
callerId: string,
|
|
108
158
|
toolCallId: string,
|
|
109
159
|
): string {
|
|
@@ -131,17 +181,17 @@ export function createCoordinatorToolDefinitions(
|
|
|
131
181
|
return runCoordinatorToolActivity(options, async () => {
|
|
132
182
|
const result = await options.coordinator.spawn(
|
|
133
183
|
options.callerId,
|
|
134
|
-
parameters
|
|
184
|
+
parameters,
|
|
135
185
|
options.captureCaller(context),
|
|
136
186
|
);
|
|
137
187
|
const status = options.coordinator.inspectStatus(result.agent_id);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
...(status && "agent" in status ? { agent: status.agent } : {}),
|
|
143
|
-
},
|
|
188
|
+
const details: SpawnResult & {
|
|
189
|
+
agent?: import("./minimal-subagents-types.js").AgentDetail;
|
|
190
|
+
} = {
|
|
191
|
+
...result,
|
|
144
192
|
};
|
|
193
|
+
if (status && "agent" in status) details.agent = status.agent;
|
|
194
|
+
return structuredToolResult(details);
|
|
145
195
|
});
|
|
146
196
|
},
|
|
147
197
|
...createCoordinatorToolRendering("subagent"),
|
|
@@ -151,7 +201,7 @@ export function createCoordinatorToolDefinitions(
|
|
|
151
201
|
name: "agent_message",
|
|
152
202
|
label: "Agent Message",
|
|
153
203
|
description:
|
|
154
|
-
"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.",
|
|
155
205
|
promptSnippet: "Coordinate required mid-turn action with one adjacent agent",
|
|
156
206
|
parameters: options.schemas.agent_message,
|
|
157
207
|
async execute(toolCallId, parameters) {
|
|
@@ -174,7 +224,7 @@ export function createCoordinatorToolDefinitions(
|
|
|
174
224
|
name: "subagent_wait",
|
|
175
225
|
label: "Subagent Wait",
|
|
176
226
|
description:
|
|
177
|
-
"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.",
|
|
178
228
|
promptSnippet: "Wait for one direct child's exact turn",
|
|
179
229
|
parameters: options.schemas.subagent_wait,
|
|
180
230
|
async execute(_toolCallId, parameters, signal, onUpdate) {
|
|
@@ -193,10 +243,10 @@ export function createCoordinatorToolDefinitions(
|
|
|
193
243
|
waitingInterval.unref?.();
|
|
194
244
|
try {
|
|
195
245
|
return await runCoordinatorToolActivity(options, async () => {
|
|
196
|
-
const result = await
|
|
246
|
+
const result = await executeCoordinatorWaitTool(
|
|
247
|
+
options.coordinator,
|
|
197
248
|
options.callerId,
|
|
198
|
-
parameters
|
|
199
|
-
parameters.timeout_ms,
|
|
249
|
+
parameters,
|
|
200
250
|
signal,
|
|
201
251
|
);
|
|
202
252
|
return {
|
|
@@ -22,6 +22,12 @@ export type AgentAvailability = "available" | "unavailable";
|
|
|
22
22
|
/** Classifies active and terminal persistent subagent turn outcomes. */
|
|
23
23
|
export type TurnStatus = "running" | "completed" | "failed" | "cancelled" | "interrupted";
|
|
24
24
|
|
|
25
|
+
/** Describes the canonical model and resolved thinking level currently used by a Child Agent. */
|
|
26
|
+
export interface RuntimeProfile {
|
|
27
|
+
model: string;
|
|
28
|
+
thinking_level: ThinkingLevel;
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
/** Defines the validated launch contract accepted by the subagent tool. */
|
|
26
32
|
export interface SpawnParameters {
|
|
27
33
|
task: string;
|
|
@@ -52,23 +58,37 @@ export interface TurnResult {
|
|
|
52
58
|
elapsed_ms?: number;
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
/** 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
|
+
|
|
56
64
|
export interface AgentMessageResult {
|
|
57
65
|
agent_id: string;
|
|
58
|
-
|
|
66
|
+
message_id: string;
|
|
67
|
+
disposition: AgentMessageDisposition;
|
|
59
68
|
error?: string;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
/**
|
|
63
|
-
export interface
|
|
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
|
+
|
|
84
|
+
/** Provides bounded hierarchy, usage, and best-known Runtime Profile data for one persistent agent. */
|
|
85
|
+
export interface AgentSummary extends RuntimeProfile {
|
|
64
86
|
agent_id: string;
|
|
65
87
|
parent_id: string;
|
|
66
88
|
state: AgentState;
|
|
67
89
|
availability: AgentAvailability;
|
|
68
90
|
active_turn_id?: string;
|
|
69
91
|
latest_turn?: Pick<TurnResult, "turn_id" | "status">;
|
|
70
|
-
model: string;
|
|
71
|
-
thinking_level: ThinkingLevel;
|
|
72
92
|
tools: string[];
|
|
73
93
|
elapsed_ms?: number;
|
|
74
94
|
latest_activity?: string;
|
|
@@ -88,7 +108,7 @@ export interface RecentAgentMessage {
|
|
|
88
108
|
/** Extends summary status with launch, dependency, and recent-message diagnostics. */
|
|
89
109
|
export interface AgentDetail extends AgentSummary {
|
|
90
110
|
session_file?: string;
|
|
91
|
-
launch_contract:
|
|
111
|
+
launch_contract: LaunchContract;
|
|
92
112
|
capability_ceiling: string[];
|
|
93
113
|
spawn_entry_id: string;
|
|
94
114
|
recent_messages: RecentAgentMessage[];
|
|
@@ -125,11 +145,9 @@ export interface DeleteResult {
|
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
/** Persists immutable context, model, thinking, and ordinary-tool launch choices. */
|
|
128
|
-
export interface LaunchContract {
|
|
148
|
+
export interface LaunchContract extends RuntimeProfile {
|
|
129
149
|
session_context: SessionContextMode;
|
|
130
150
|
project_context: ProjectContextMode;
|
|
131
|
-
model: string;
|
|
132
|
-
thinking_level: ThinkingLevel;
|
|
133
151
|
tools: ToolSelection | undefined;
|
|
134
152
|
ordinary_tools: string[];
|
|
135
153
|
delegation?: DelegationMode;
|
|
@@ -162,6 +180,8 @@ export interface CoordinatorMessage {
|
|
|
162
180
|
source_agent_id: string;
|
|
163
181
|
destination_agent_id?: string;
|
|
164
182
|
source_turn_id: string;
|
|
183
|
+
message_id: string;
|
|
184
|
+
delivery_id?: string;
|
|
165
185
|
status?: TurnStatus;
|
|
166
186
|
elapsed_ms?: number;
|
|
167
187
|
usage?: Usage;
|
|
@@ -172,6 +192,7 @@ export interface CoordinatorMessage {
|
|
|
172
192
|
export interface ChildAgentRuntime {
|
|
173
193
|
readonly sessionFile: string;
|
|
174
194
|
readonly sessionId: string;
|
|
195
|
+
readonly sessionLeafId: string | undefined;
|
|
175
196
|
readonly isRunning: boolean;
|
|
176
197
|
runPrompt(
|
|
177
198
|
task: string,
|
|
@@ -180,20 +201,22 @@ export interface ChildAgentRuntime {
|
|
|
180
201
|
callerThinkingLevel: ThinkingLevel,
|
|
181
202
|
): Promise<RuntimeTurnOutcome>;
|
|
182
203
|
runMessage(message: CoordinatorMessage): Promise<RuntimeTurnOutcome>;
|
|
183
|
-
/**
|
|
184
|
-
|
|
204
|
+
/** Queue one typed coordinator message into the child session. */
|
|
205
|
+
queueCoordinatorMessage(message: CoordinatorMessage): Promise<void>;
|
|
185
206
|
abort(): Promise<void>;
|
|
186
207
|
dispose(): void;
|
|
208
|
+
/** Return the live Runtime Profile, or undefined when the SDK session has no model. */
|
|
209
|
+
getRuntimeProfile(): RuntimeProfile | undefined;
|
|
187
210
|
snapshotCommittedMessages(): AgentMessage[];
|
|
188
|
-
hasDeliveryEvidence(sourceAgentId: string, sourceTurnId: string): boolean;
|
|
211
|
+
hasDeliveryEvidence(sourceAgentId: string, sourceTurnId: string, deliveryId?: string): boolean;
|
|
189
212
|
getUsage(): Usage | undefined;
|
|
190
|
-
cloneSession(): Promise<{ sessionFile: string; sessionId: string }>;
|
|
191
213
|
}
|
|
192
214
|
|
|
193
215
|
/** Identifies one writable child JSONL session owned by a coordinator root. */
|
|
194
216
|
export interface PersistedSessionIdentity {
|
|
195
217
|
sessionFile: string;
|
|
196
218
|
sessionId: string;
|
|
219
|
+
sessionLeafId?: string;
|
|
197
220
|
}
|
|
198
221
|
|
|
199
222
|
/** Combines a persisted agent record with first-launch imported context. */
|
|
@@ -211,15 +234,28 @@ export interface AgentSessionFactory {
|
|
|
211
234
|
resolveRestorationMissingDependencies(agent: PersistedAgent): Promise<string[]>;
|
|
212
235
|
resolveThinkingLevel(modelId: string, requested: ThinkingLevel): ThinkingLevel;
|
|
213
236
|
modelSupportsImages(modelId: string): boolean;
|
|
237
|
+
/** Clone a child leaf owned by the active source root during confirmed shutdown. */
|
|
214
238
|
cloneSession(agent: PersistedAgent): Promise<PersistedSessionIdentity>;
|
|
215
|
-
|
|
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>;
|
|
216
250
|
}
|
|
217
251
|
|
|
218
252
|
/** Abstracts root message delivery and durable delivery-evidence lookup. */
|
|
219
253
|
export interface RootConversationEndpoint {
|
|
220
|
-
/**
|
|
221
|
-
|
|
222
|
-
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;
|
|
223
259
|
}
|
|
224
260
|
|
|
225
261
|
/** Stores root-owned agent identity, launch contract, availability, and latest activity. */
|
|
@@ -233,6 +269,7 @@ export interface PersistedAgent {
|
|
|
233
269
|
spawn_entry_id: string;
|
|
234
270
|
session_file?: string;
|
|
235
271
|
session_id?: string;
|
|
272
|
+
session_leaf_id?: string;
|
|
236
273
|
clone_error?: string;
|
|
237
274
|
launch_contract: LaunchContract;
|
|
238
275
|
capability_ceiling: string[];
|
|
@@ -246,7 +283,7 @@ export interface PersistedAgent {
|
|
|
246
283
|
deleted?: boolean;
|
|
247
284
|
}
|
|
248
285
|
|
|
249
|
-
/** Records
|
|
286
|
+
/** Records which conversation path owns one successful terminal result. */
|
|
250
287
|
export type DeliveryPath = "wait" | "message";
|
|
251
288
|
|
|
252
289
|
/** Stores a keyed successful result until destination evidence settles delivery. */
|
|
@@ -256,26 +293,44 @@ export interface PersistedDelivery {
|
|
|
256
293
|
destination_agent_id: string;
|
|
257
294
|
path: DeliveryPath;
|
|
258
295
|
settled: boolean;
|
|
296
|
+
sequence?: number;
|
|
259
297
|
result?: TurnResult;
|
|
260
298
|
error?: string;
|
|
261
299
|
}
|
|
262
300
|
|
|
263
|
-
/**
|
|
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. */
|
|
264
313
|
export interface RegistrySnapshot {
|
|
265
314
|
agents: PersistedAgent[];
|
|
266
315
|
tombstones: string[];
|
|
267
316
|
deliveries: PersistedDelivery[];
|
|
317
|
+
coordination_deliveries?: PersistedCoordinationDelivery[];
|
|
318
|
+
wait_claimed_turns?: string[];
|
|
319
|
+
next_delivery_sequence?: number;
|
|
268
320
|
}
|
|
269
321
|
|
|
270
322
|
/** Clones a registry snapshot while recording the source root session file. */
|
|
271
323
|
export interface ForkSnapshot extends RegistrySnapshot {
|
|
324
|
+
/** Canonical Pi root session file from which the selected fork branch originated. */
|
|
272
325
|
source_root_session_file: string;
|
|
326
|
+
/** Root identity that every cloned Child Session provenance record must match. */
|
|
327
|
+
source_root_session_id: string;
|
|
273
328
|
}
|
|
274
329
|
|
|
275
330
|
/** Appends root-owned registry events to the active root conversation branch. */
|
|
276
331
|
export interface RegistryWriter {
|
|
277
332
|
readonly rootSessionId: string;
|
|
278
|
-
append(event: import("./minimal-subagents-registry.js").
|
|
333
|
+
append(event: import("./minimal-subagents-registry.js").RegistryEventV2): void;
|
|
279
334
|
}
|
|
280
335
|
|
|
281
336
|
/** Describes concise lifecycle notices surfaced through Pi UI notifications. */
|