@fradser/pi-agent-teams 0.5.3 → 0.7.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/.memory/MEMORY.md +3 -1
- package/.memory/node-terminal-followups.md +3 -2
- package/.memory/team-centric-design.md +21 -0
- package/README.md +103 -63
- package/package.json +4 -4
- package/references/agent-roles.md +77 -0
- package/src/activity.ts +86 -0
- package/src/agents.ts +93 -24
- package/src/follow-up-queue.ts +94 -26
- package/src/guidance.ts +96 -61
- package/src/index.ts +114 -28
- package/src/spawner.ts +194 -350
- package/src/state.ts +252 -565
- package/src/statefile.ts +209 -46
- package/src/team-machine.ts +968 -0
- package/src/tools.ts +160 -175
- package/src/types.ts +153 -189
- package/src/ui.ts +459 -226
- package/src/worker.ts +174 -34
- package/src/worktree.ts +20 -8
- package/.memory/run-centric-design.md +0 -22
- package/agents/observer.md +0 -10
- package/agents/reviewer.md +0 -11
- package/agents/specialist.md +0 -10
- package/agents/worker.md +0 -11
- package/src/run-machine.ts +0 -606
- package/src/terminal.ts +0 -34
package/src/types.ts
CHANGED
|
@@ -1,103 +1,102 @@
|
|
|
1
1
|
import type { Static } from "typebox";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
|
|
4
|
-
// ──
|
|
4
|
+
// ── Teammate ──────────────────────────────────────────────────────
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const TeammateStatus = Type.Union(
|
|
7
7
|
[
|
|
8
|
-
Type.Literal("
|
|
9
|
-
Type.Literal("
|
|
10
|
-
Type.Literal("
|
|
11
|
-
Type.Literal("
|
|
12
|
-
Type.Literal("cancelled"),
|
|
8
|
+
Type.Literal("starting"),
|
|
9
|
+
Type.Literal("idle"),
|
|
10
|
+
Type.Literal("working"),
|
|
11
|
+
Type.Literal("stopped"),
|
|
13
12
|
],
|
|
14
|
-
{ description: "
|
|
13
|
+
{ description: "Lifecycle of a resident teammate" },
|
|
15
14
|
);
|
|
16
|
-
export type
|
|
15
|
+
export type TeammateStatus = Static<typeof TeammateStatus>;
|
|
16
|
+
|
|
17
|
+
/** A named, long-lived child Pi process on the team roster. */
|
|
18
|
+
export interface Teammate {
|
|
19
|
+
/** Unique among living teammates; also the mailbox and roster key. */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Resolved agent definition name. */
|
|
22
|
+
agent: string;
|
|
23
|
+
/** Per-spawn capability identity, regenerated for every process. */
|
|
24
|
+
spawnId: string;
|
|
25
|
+
pid: number;
|
|
26
|
+
status: TeammateStatus;
|
|
27
|
+
/** Working directory (the worktree root when isolated). */
|
|
28
|
+
cwd?: string;
|
|
29
|
+
/** Whether this teammate owns a dedicated Git worktree. */
|
|
30
|
+
isolation: "worktree" | "none";
|
|
31
|
+
/** Board task currently claimed by this teammate, if any. */
|
|
32
|
+
currentTaskId?: string;
|
|
33
|
+
/** Live assistant text assembled from the RPC stream. */
|
|
34
|
+
liveText?: string;
|
|
35
|
+
/** Current child tool name, if a tool is executing. */
|
|
36
|
+
activeTool?: string;
|
|
37
|
+
/** Live assistant reasoning streamed while no tool runs. */
|
|
38
|
+
liveThinking?: string;
|
|
39
|
+
/** Assistant turns observed in the current wake-up sequence. */
|
|
40
|
+
turns?: number;
|
|
41
|
+
/** The child finished its current sequence and awaits the next prompt. */
|
|
42
|
+
sequenceEnded?: boolean;
|
|
43
|
+
/** When the harness last sent a claimable-task notice to this teammate. */
|
|
44
|
+
lastNoticeAt?: number;
|
|
45
|
+
usage?: WorkerUsage;
|
|
46
|
+
error?: string;
|
|
47
|
+
createdAt: number;
|
|
48
|
+
updatedAt: number;
|
|
49
|
+
stoppedAt?: number;
|
|
50
|
+
/** Last wall-clock time output was observed (any stream event or prompt delivery). */
|
|
51
|
+
lastOutputAt?: number;
|
|
52
|
+
/** When the current stall episode notice was sent (one per episode). */
|
|
53
|
+
stallNoticeSentAt?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ── Task board ────────────────────────────────────────────────────
|
|
17
57
|
|
|
18
|
-
export const
|
|
58
|
+
export const TaskStatus = Type.Union(
|
|
19
59
|
[
|
|
20
|
-
Type.Literal("
|
|
60
|
+
Type.Literal("pending"),
|
|
61
|
+
Type.Literal("claimed"),
|
|
21
62
|
Type.Literal("completed"),
|
|
22
|
-
Type.Literal("failed"),
|
|
23
|
-
Type.Literal("cancelled"),
|
|
24
63
|
],
|
|
25
|
-
{ description: "
|
|
64
|
+
{ description: "Board lifecycle of a task" },
|
|
26
65
|
);
|
|
27
|
-
export type
|
|
66
|
+
export type TaskStatus = Static<typeof TaskStatus>;
|
|
28
67
|
|
|
29
|
-
/** One task
|
|
30
|
-
export interface
|
|
31
|
-
/** User-chosen id, unique within the run. */
|
|
68
|
+
/** One task on the shared board. Only the leader process writes board state. */
|
|
69
|
+
export interface BoardTask {
|
|
32
70
|
id: string;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
agent: string;
|
|
37
|
-
/** The specific task text handed to the worker. */
|
|
38
|
-
prompt: string;
|
|
39
|
-
/** Repository-relative paths used to coordinate this node. */
|
|
40
|
-
paths: string[];
|
|
41
|
-
/** Read nodes may overlap; write nodes need shared-workspace conflict protection. */
|
|
42
|
-
access: "read" | "write";
|
|
43
|
-
/** Optional per-node model pin (provider/model). */
|
|
44
|
-
model?: string;
|
|
45
|
-
/** RPC mode keeps stdin available for runtime steering. */
|
|
46
|
-
mode?: "json" | "rpc";
|
|
47
|
-
/** Optional maximum number of assistant turns before the worker is stopped. */
|
|
48
|
-
turnBudget?: number;
|
|
49
|
-
/** Node ids that must complete before this node may start. */
|
|
71
|
+
subject: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
/** Task ids that must complete before this task is claimable. */
|
|
50
74
|
dependsOn: string[];
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
status: NodeStatus;
|
|
75
|
+
/** Deterministic completion gate; overrides the agent-role default. */
|
|
76
|
+
verify?: string;
|
|
77
|
+
status: TaskStatus;
|
|
78
|
+
claimedBy?: string;
|
|
56
79
|
result?: string;
|
|
57
|
-
/** Named structured outputs emitted through teammate_message. */
|
|
58
|
-
namedOutputs?: Record<string, string>;
|
|
59
|
-
/** Bounded JSON output emitted through teammate_message for downstream data flow. */
|
|
60
|
-
structuredOutput?: unknown;
|
|
61
80
|
errorMessage?: string;
|
|
62
|
-
/** True once the terminal node follow-up has been delivered. */
|
|
63
|
-
nodeFollowUpSent?: boolean;
|
|
64
|
-
/** Real child-process execution info when this node was spawned. */
|
|
65
|
-
spawn?: SpawnInfo;
|
|
66
81
|
createdAt: number;
|
|
67
82
|
updatedAt: number;
|
|
68
83
|
completedAt?: number;
|
|
69
84
|
}
|
|
70
85
|
|
|
71
|
-
/** A
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
background: boolean;
|
|
81
|
-
/** Run-level failure detail. */
|
|
82
|
-
errorMessage?: string;
|
|
83
|
-
nodes: Record<string, Node>;
|
|
84
|
-
createdAt: number;
|
|
85
|
-
updatedAt: number;
|
|
86
|
-
finishedAt?: number;
|
|
87
|
-
/** True once the run-completion follow-up was delivered, or claimed by wait/foreground gather. */
|
|
88
|
-
completionNotified?: boolean;
|
|
89
|
-
/** True once the run-settled leader summary was sent (onRunSettled is idempotent). */
|
|
90
|
-
settledMessageSent?: boolean;
|
|
91
|
-
/** Synthesized final summary produced by the optional __summary node. */
|
|
92
|
-
summary?: string;
|
|
86
|
+
/** A claim or submission intent expressed by a worker through marker files.
|
|
87
|
+
* Workers never write the board file itself. `status` applies to submissions. */
|
|
88
|
+
export interface TaskIntent {
|
|
89
|
+
taskId: string;
|
|
90
|
+
worker: string;
|
|
91
|
+
spawnId: string;
|
|
92
|
+
status?: "completed" | "failed";
|
|
93
|
+
result?: string;
|
|
94
|
+
timestamp: number;
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
// ── Spawn ─────────────────────────────────────────────────────────
|
|
96
98
|
|
|
97
|
-
/**
|
|
98
|
-
export type SpawnStatus = "running" | "completed" | "failed";
|
|
99
|
-
|
|
100
|
-
/** Token/cost usage reported by a finished worker (from JSON-mode output). */
|
|
99
|
+
/** Token/cost usage reported by a teammate (accumulated across sequences). */
|
|
101
100
|
export interface WorkerUsage {
|
|
102
101
|
input: number;
|
|
103
102
|
output: number;
|
|
@@ -107,38 +106,6 @@ export interface WorkerUsage {
|
|
|
107
106
|
cost: number;
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
export interface SpawnInfo {
|
|
111
|
-
/** Per-spawn capability identity, regenerated for every worker process. */
|
|
112
|
-
spawnId: string;
|
|
113
|
-
mode?: "json" | "rpc";
|
|
114
|
-
pid: number;
|
|
115
|
-
status: SpawnStatus;
|
|
116
|
-
startedAt: number;
|
|
117
|
-
/** Live assistant text assembled from JSON-mode stream events. */
|
|
118
|
-
liveText?: string;
|
|
119
|
-
/** Current child tool name, if a tool is executing. */
|
|
120
|
-
activeTool?: string;
|
|
121
|
-
/** Live assistant reasoning streamed from the child (shown while no tool runs). */
|
|
122
|
-
liveThinking?: string;
|
|
123
|
-
/** Number of assistant turns observed from the child JSON stream. */
|
|
124
|
-
turns?: number;
|
|
125
|
-
/** The child emitted a final successful assistant response and should close promptly. */
|
|
126
|
-
finalResponse?: boolean;
|
|
127
|
-
finishedAt?: number;
|
|
128
|
-
exitCode?: number;
|
|
129
|
-
/** Truncated stdout of the child process. */
|
|
130
|
-
stdout?: string;
|
|
131
|
-
/** Truncated stderr of the child process. */
|
|
132
|
-
stderr?: string;
|
|
133
|
-
/** Spawn-level error (e.g. CLI resolution failure). */
|
|
134
|
-
error?: string;
|
|
135
|
-
/** Token/cost usage reported by the worker, when available. */
|
|
136
|
-
usage?: WorkerUsage;
|
|
137
|
-
timedOut?: boolean;
|
|
138
|
-
/** Whether this spawn owns a dedicated Git worktree. */
|
|
139
|
-
isolation?: "worktree" | "none";
|
|
140
|
-
}
|
|
141
|
-
|
|
142
109
|
// ── Mailbox ───────────────────────────────────────────────────────
|
|
143
110
|
|
|
144
111
|
export interface MailboxMessage {
|
|
@@ -146,124 +113,121 @@ export interface MailboxMessage {
|
|
|
146
113
|
from: string;
|
|
147
114
|
subject: string;
|
|
148
115
|
body: string;
|
|
149
|
-
|
|
116
|
+
status?: "in_progress" | "completed" | "failed";
|
|
150
117
|
timestamp: number;
|
|
151
118
|
}
|
|
152
119
|
|
|
153
|
-
/** Append-only event emitted by a
|
|
154
|
-
|
|
120
|
+
/** Append-only report event emitted by a teammate to the leader. The title
|
|
121
|
+
* is derived by the harness from the first line of the body. */
|
|
122
|
+
export interface WorkerReportEvent {
|
|
155
123
|
id: string;
|
|
156
124
|
type: "message";
|
|
157
125
|
worker: string;
|
|
158
126
|
spawnId: string;
|
|
159
|
-
subject: string;
|
|
160
127
|
body: string;
|
|
161
128
|
status?: "in_progress" | "completed" | "failed";
|
|
162
|
-
data?: {
|
|
163
|
-
kind?: "named_output" | "output";
|
|
164
|
-
name?: string;
|
|
165
|
-
value?: string;
|
|
166
|
-
output?: unknown;
|
|
167
|
-
message?: string;
|
|
168
|
-
};
|
|
169
129
|
}
|
|
170
130
|
|
|
171
|
-
export type WorkerEvent =
|
|
131
|
+
export type WorkerEvent = WorkerReportEvent;
|
|
132
|
+
|
|
133
|
+
/** Structural guard applied to every outbox record before it is trusted. */
|
|
134
|
+
export function isWorkerEvent(value: unknown): value is WorkerReportEvent {
|
|
135
|
+
if (!value || typeof value !== "object") return false;
|
|
136
|
+
const event = value as Partial<WorkerReportEvent>;
|
|
137
|
+
return typeof event.id === "string"
|
|
138
|
+
&& event.type === "message"
|
|
139
|
+
&& typeof event.worker === "string"
|
|
140
|
+
&& typeof event.spawnId === "string"
|
|
141
|
+
&& typeof event.body === "string"
|
|
142
|
+
&& (event.status === undefined || ["in_progress", "completed", "failed"].includes(event.status));
|
|
143
|
+
}
|
|
172
144
|
|
|
173
|
-
|
|
145
|
+
/** Derive a display title from the first non-empty line of a message. */
|
|
146
|
+
export function messageTitle(body: string): string {
|
|
147
|
+
for (const line of body.split("\n")) {
|
|
148
|
+
const trimmed = line.replace(/\s+/g, " ").trim();
|
|
149
|
+
if (trimmed) return trimmed.slice(0, 120);
|
|
150
|
+
}
|
|
151
|
+
return "(no content)";
|
|
152
|
+
}
|
|
174
153
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
154
|
+
/** One message in a teammate inbox (peer-to-peer or harness feedback). */
|
|
155
|
+
export interface InboxMessage {
|
|
156
|
+
id: string;
|
|
157
|
+
from: string;
|
|
158
|
+
subject: string;
|
|
159
|
+
body: string;
|
|
160
|
+
timestamp: number;
|
|
161
|
+
}
|
|
179
162
|
|
|
180
|
-
|
|
181
|
-
export const RunTaskSpec = Type.Object({
|
|
182
|
-
id: Type.String({ description: "Node id, unique within this run" }),
|
|
183
|
-
agent: Type.String({ description: "Agent definition name (bundled, user, or project scope)" }),
|
|
184
|
-
prompt: Type.String({ minLength: 1, description: "The specific task text handed to this worker" }),
|
|
185
|
-
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Node ids that must complete before this node starts" })),
|
|
186
|
-
paths: Type.Array(Type.String({ description: "Repository-relative path this node may inspect or modify" }), {
|
|
187
|
-
minItems: 1,
|
|
188
|
-
description: "Repository-relative paths used to coordinate this node",
|
|
189
|
-
}),
|
|
190
|
-
access: Type.Optional(NodeAccess),
|
|
191
|
-
model: Type.Optional(Type.String({ description: "Optional per-node provider/model pin" })),
|
|
192
|
-
mode: Type.Optional(Type.Union([Type.Literal("json"), Type.Literal("rpc")], { description: "Worker process mode; rpc enables runtime steering" })),
|
|
193
|
-
turnBudget: Type.Optional(Type.Integer({ minimum: 1, description: "Optional maximum assistant turns before the worker is stopped (default: 100; high safety cap for edge cases)" })),
|
|
194
|
-
forkContext: Type.Optional(Type.Array(Type.String(), { description: "Named upstream node ids whose results are included as fork context" })),
|
|
195
|
-
inputBindings: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "Named inputs bound from dependency outputs using nodeId#/json/pointer" })),
|
|
196
|
-
});
|
|
163
|
+
// ── Tool parameter schemas (typebox) ──────────────────────────────
|
|
197
164
|
|
|
198
|
-
/**
|
|
199
|
-
export const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
description: "Task graph to dispatch; dependsOn edges must form a DAG",
|
|
204
|
-
}),
|
|
205
|
-
concurrency: Type.Optional(Type.Integer({ minimum: 1, maximum: 32, description: "Max nodes running at once (default: 4)" })),
|
|
206
|
-
worktree: Type.Optional(Type.Boolean({ description: "Run every node in its own git worktree (default: false)" })),
|
|
207
|
-
background: Type.Optional(Type.Boolean({ default: true, description: "Return immediately and deliver one completion follow-up. Default: true — teammates always run in the background; workers message team-leader with deliverables upon completion." })),
|
|
208
|
-
summarize: Type.Optional(Type.Boolean({ description: "Append a __summary node after all leaf nodes. Default: true when the run has more than one user task, false for a single task." })),
|
|
209
|
-
summaryAgent: Type.Optional(Type.String({ description: "Agent used for the summary node when summarize is on (default: observer)" })),
|
|
210
|
-
cwd: Type.Optional(Type.String({ description: "Working directory for this run (default: the session cwd)" })),
|
|
165
|
+
/** Spawn one named resident teammate. */
|
|
166
|
+
export const TeammateSpawnParams = Type.Object({
|
|
167
|
+
name: Type.String({ minLength: 1, description: "Teammate name, unique among living teammates; used for messaging and claiming" }),
|
|
168
|
+
agent: Type.String({ description: "Agent definition name (from user, project, or project-local scopes); its frontmatter pins model and optional worktree isolation" }),
|
|
169
|
+
prompt: Type.Optional(Type.String({ description: "Optional kickoff prompt delivered as the teammate's first turn; omit to let it wait for messages or board claims" })),
|
|
211
170
|
});
|
|
212
171
|
|
|
213
|
-
/**
|
|
214
|
-
export const
|
|
215
|
-
|
|
216
|
-
nodeId: Type.Optional(Type.String({ description: "Cancel one node (and its not-yet-started dependents) instead of the whole run; the run continues" })),
|
|
172
|
+
/** Shut down one living teammate. */
|
|
173
|
+
export const TeammateShutdownParams = Type.Object({
|
|
174
|
+
name: Type.String({ description: "Teammate name on the roster" }),
|
|
217
175
|
});
|
|
218
176
|
|
|
219
|
-
/**
|
|
220
|
-
export const
|
|
221
|
-
|
|
222
|
-
|
|
177
|
+
/** Create a board task (leader-only). */
|
|
178
|
+
export const TaskCreateParams = Type.Object({
|
|
179
|
+
subject: Type.String({ minLength: 1, description: "Short task title shown on the board" }),
|
|
180
|
+
description: Type.Optional(Type.String({ description: "Full task description for the claiming teammate" }),
|
|
181
|
+
),
|
|
182
|
+
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Task ids that must complete before this task is claimable" })),
|
|
183
|
+
verify: Type.Optional(Type.String({ description: "Deterministic completion gate command; zero exit completes the task. Overrides any agent-role default verify." })),
|
|
223
184
|
});
|
|
224
185
|
|
|
225
|
-
/**
|
|
226
|
-
export const
|
|
227
|
-
|
|
228
|
-
|
|
186
|
+
/** Shared leader/worker read-only board view. */
|
|
187
|
+
export const TaskListParams = Type.Object({});
|
|
188
|
+
|
|
189
|
+
/** The reserved recipient name for reports to the team leader. */
|
|
190
|
+
export const LEADER_RECIPIENT = "leader";
|
|
191
|
+
|
|
192
|
+
/** The single messaging primitive: addressed peer mail and leader reports.
|
|
193
|
+
* `status` is honored only for to="leader" terminal reports. */
|
|
194
|
+
export const SendMessageParams = Type.Object({
|
|
195
|
+
to: Type.String({ minLength: 1, description: 'Recipient: a teammate name on the roster, or "leader" to report to the team leader' }),
|
|
196
|
+
message: Type.String({ description: "Message content; the first line becomes the title shown in the console" }),
|
|
229
197
|
status: Type.Optional(Type.Union([
|
|
230
198
|
Type.Literal("in_progress"),
|
|
231
199
|
Type.Literal("completed"),
|
|
232
200
|
Type.Literal("failed"),
|
|
233
|
-
], { description:
|
|
234
|
-
data: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Structured teammate data: named_output or output" })),
|
|
201
|
+
], { description: 'Only for to="leader": completed or failed ends the current assignment and triggers immediate follow-up delivery' })),
|
|
235
202
|
});
|
|
236
203
|
|
|
237
|
-
/**
|
|
238
|
-
export const
|
|
239
|
-
|
|
240
|
-
nodeId: Type.String({ description: "Completed source node whose structured output is an array" }),
|
|
241
|
-
agent: Type.String({ description: "Agent to run for each item" }),
|
|
242
|
-
prompt: Type.String({ minLength: 1, description: "Task prompt; each item is appended as JSON" }),
|
|
243
|
-
paths: Type.Array(Type.String(), { minItems: 1, description: "Repository-relative paths for each child run" }),
|
|
244
|
-
access: Type.Optional(NodeAccess),
|
|
245
|
-
model: Type.Optional(Type.String()),
|
|
246
|
-
turnBudget: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
247
|
-
concurrency: Type.Optional(Type.Integer({ minimum: 1, maximum: 32 })),
|
|
248
|
-
background: Type.Optional(Type.Boolean({ default: true })),
|
|
204
|
+
/** Self-claim a pending board task. */
|
|
205
|
+
export const TaskClaimParams = Type.Object({
|
|
206
|
+
taskId: Type.Optional(Type.String({ description: "Specific task id to claim; omit to claim the first claimable task" })),
|
|
249
207
|
});
|
|
250
208
|
|
|
251
|
-
/**
|
|
252
|
-
export const
|
|
253
|
-
|
|
254
|
-
|
|
209
|
+
/** Submit a claimed task outcome. Completion passes through the verify gate. */
|
|
210
|
+
export const TaskSubmitParams = Type.Object({
|
|
211
|
+
taskId: Type.String({ description: "The claimed task id" }),
|
|
212
|
+
status: Type.Union([Type.Literal("completed"), Type.Literal("failed")], { description: "Outcome of the claimed task" }),
|
|
213
|
+
result: Type.Optional(Type.String({ description: "Result summary recorded on the board when completed" })),
|
|
255
214
|
});
|
|
256
215
|
|
|
257
216
|
// ── State snapshot for persistence ────────────────────────────────
|
|
258
217
|
|
|
259
|
-
export interface
|
|
260
|
-
|
|
261
|
-
|
|
218
|
+
export interface TeamState {
|
|
219
|
+
teammates: Record<string, Teammate>;
|
|
220
|
+
tasks: Record<string, BoardTask>;
|
|
221
|
+
/** Single leader inbox for teammate reports and harness diagnostics. */
|
|
262
222
|
leaderMailbox: MailboxMessage[];
|
|
263
223
|
messageCounter: number;
|
|
264
|
-
|
|
265
|
-
/** Byte offsets consumed by the parent from each
|
|
224
|
+
taskCounter: number;
|
|
225
|
+
/** Byte offsets consumed by the parent from each teammate's outbox. */
|
|
266
226
|
workerEventOffsets: Record<string, number>;
|
|
267
|
-
/**
|
|
227
|
+
/** Report event ids already applied, keyed by teammate spawn. */
|
|
268
228
|
workerEventIds: Record<string, string>;
|
|
229
|
+
/** Consumed byte offsets per peer inbox file. */
|
|
230
|
+
peerInboxOffsets: Record<string, number>;
|
|
231
|
+
/** Delivered peer message ids per inbox, capped FIFO for deduplication. */
|
|
232
|
+
peerDeliveredIds: Record<string, string[]>;
|
|
269
233
|
}
|