pi-fabric 0.89.1 → 0.91.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.
Files changed (153) hide show
  1. package/dist/agents/lifecycle.d.ts +32 -0
  2. package/dist/agents/lifecycle.d.ts.map +1 -0
  3. package/dist/agents/manager.d.ts.map +1 -1
  4. package/dist/agents/request.d.ts +13 -0
  5. package/dist/agents/request.d.ts.map +1 -0
  6. package/dist/agents/result.d.ts +8 -0
  7. package/dist/agents/result.d.ts.map +1 -0
  8. package/dist/agents/result.js +9 -0
  9. package/dist/agents/result.js.map +7 -0
  10. package/dist/agents/service-provider.d.ts +9 -0
  11. package/dist/agents/service-provider.d.ts.map +1 -0
  12. package/dist/agents/service-schema.d.ts +6 -0
  13. package/dist/agents/service-schema.d.ts.map +1 -0
  14. package/dist/agents/service-types.d.ts +127 -0
  15. package/dist/agents/service-types.d.ts.map +1 -0
  16. package/dist/agents/service.d.ts +23 -0
  17. package/dist/agents/service.d.ts.map +1 -0
  18. package/dist/agents/types.d.ts +2 -0
  19. package/dist/agents/types.d.ts.map +1 -1
  20. package/dist/agents.d.ts +8 -0
  21. package/dist/agents.d.ts.map +1 -0
  22. package/dist/agents.js +615 -0
  23. package/dist/agents.js.map +7 -0
  24. package/dist/chunks/chunk-3H7SDWZI.js +467 -0
  25. package/dist/chunks/chunk-3H7SDWZI.js.map +7 -0
  26. package/dist/chunks/chunk-3QECYQGA.js +70 -0
  27. package/dist/chunks/chunk-3QECYQGA.js.map +7 -0
  28. package/dist/chunks/chunk-4S5PVL7Y.js +91 -0
  29. package/dist/chunks/chunk-4S5PVL7Y.js.map +7 -0
  30. package/dist/chunks/{chunk-7X72JCGN.js → chunk-5JEOABJ7.js} +42 -14
  31. package/dist/chunks/{chunk-7X72JCGN.js.map → chunk-5JEOABJ7.js.map} +3 -3
  32. package/dist/chunks/{chunk-CGIPKJSC.js → chunk-6LLUZUH4.js} +11 -9
  33. package/dist/chunks/chunk-6LLUZUH4.js.map +7 -0
  34. package/dist/chunks/chunk-AAXQR7SZ.js +732 -0
  35. package/dist/chunks/chunk-AAXQR7SZ.js.map +7 -0
  36. package/dist/chunks/{chunk-QSBUP4ZD.js → chunk-CGPK5WHX.js} +1 -50
  37. package/dist/chunks/chunk-CGPK5WHX.js.map +7 -0
  38. package/dist/chunks/{chunk-M3R56VXZ.js → chunk-CHNDPTCW.js} +7 -7
  39. package/dist/chunks/chunk-DBNZVS2S.js +931 -0
  40. package/dist/chunks/chunk-DBNZVS2S.js.map +7 -0
  41. package/dist/chunks/{chunk-YIDC2IVN.js → chunk-F64KOMNS.js} +4 -4
  42. package/dist/chunks/chunk-F64KOMNS.js.map +7 -0
  43. package/dist/chunks/{chunk-J7BQS5XH.js → chunk-HTKYFUKU.js} +10 -3
  44. package/dist/chunks/chunk-HTKYFUKU.js.map +7 -0
  45. package/dist/chunks/{chunk-GUQT67PQ.js → chunk-IRPPGNUF.js} +15 -218
  46. package/dist/chunks/chunk-IRPPGNUF.js.map +7 -0
  47. package/dist/chunks/{chunk-Z43ZKIZT.js → chunk-J2HV2URQ.js} +2 -2
  48. package/dist/chunks/{chunk-G23OLG5P.js → chunk-LJ6FJRFH.js} +71 -197
  49. package/dist/chunks/chunk-LJ6FJRFH.js.map +7 -0
  50. package/dist/chunks/{chunk-HDPGQRHV.js → chunk-NGAUBL2M.js} +13 -11
  51. package/dist/chunks/{chunk-HDPGQRHV.js.map → chunk-NGAUBL2M.js.map} +1 -1
  52. package/dist/chunks/chunk-NQOEHX62.js +215 -0
  53. package/dist/chunks/chunk-NQOEHX62.js.map +7 -0
  54. package/dist/chunks/chunk-OTCASLY2.js +52 -0
  55. package/dist/chunks/{chunk-QSBUP4ZD.js.map → chunk-OTCASLY2.js.map} +3 -3
  56. package/dist/chunks/{chunk-7MP2EBWH.js → chunk-P22OSVIC.js} +6 -4
  57. package/dist/chunks/{chunk-7MP2EBWH.js.map → chunk-P22OSVIC.js.map} +1 -1
  58. package/dist/chunks/{chunk-GSOL7EZB.js → chunk-TAJUG2Q3.js} +16 -464
  59. package/dist/chunks/chunk-TAJUG2Q3.js.map +7 -0
  60. package/dist/chunks/{chunk-JQJBQA2C.js → chunk-TMMK5L63.js} +2 -2
  61. package/dist/chunks/{chunk-TQR7IE6H.js → chunk-UVUWHPAO.js} +5 -5
  62. package/dist/chunks/{chunk-BOCWQOTG.js → chunk-V7RXK6MR.js} +2 -2
  63. package/dist/chunks/chunk-YDM3MYCO.js +208 -0
  64. package/dist/chunks/chunk-YDM3MYCO.js.map +7 -0
  65. package/dist/compaction/hook.js +2 -1
  66. package/dist/core/action-registry.js +1 -1
  67. package/dist/core/action-repair.d.ts +0 -5
  68. package/dist/core/action-repair.d.ts.map +1 -1
  69. package/dist/core/approval-controller.d.ts +2 -1
  70. package/dist/core/approval-controller.d.ts.map +1 -1
  71. package/dist/entropy/index.js +2 -2
  72. package/dist/execution-service.d.ts +2 -1
  73. package/dist/execution-service.d.ts.map +1 -1
  74. package/dist/fabric-runtime-state.d.ts.map +1 -1
  75. package/dist/fabric-runtime-state.js +2201 -3763
  76. package/dist/fabric-runtime-state.js.map +4 -4
  77. package/dist/index.js +23 -17
  78. package/dist/index.js.map +2 -2
  79. package/dist/managed-host.d.ts +2 -0
  80. package/dist/managed-host.d.ts.map +1 -1
  81. package/dist/mcp.d.ts +9 -0
  82. package/dist/mcp.d.ts.map +1 -0
  83. package/dist/mcp.js +21 -0
  84. package/dist/mcp.js.map +7 -0
  85. package/dist/memory/host-source.d.ts +1 -0
  86. package/dist/memory/host-source.d.ts.map +1 -1
  87. package/dist/memory/lineage.d.ts +1 -1
  88. package/dist/memory/lineage.d.ts.map +1 -1
  89. package/dist/memory/portable.d.ts +2 -0
  90. package/dist/memory/portable.d.ts.map +1 -1
  91. package/dist/memory/provider.d.ts +15 -0
  92. package/dist/memory/provider.d.ts.map +1 -0
  93. package/dist/memory/search.js +1 -1
  94. package/dist/memory.d.ts +2 -0
  95. package/dist/memory.d.ts.map +1 -1
  96. package/dist/memory.js +40 -2
  97. package/dist/memory.js.map +3 -3
  98. package/dist/providers/agents-provider.d.ts.map +1 -1
  99. package/dist/providers/mcp-provider.d.ts +21 -1
  100. package/dist/providers/mcp-provider.d.ts.map +1 -1
  101. package/dist/providers/memory-provider.d.ts +1 -0
  102. package/dist/providers/memory-provider.d.ts.map +1 -1
  103. package/dist/providers/memory-provider.js +5 -2
  104. package/dist/residency/host.js +13 -10
  105. package/dist/residency/pi-entry.js +13 -10
  106. package/dist/residency/pi-entry.js.map +1 -1
  107. package/dist/runtime/core-override-guest-types.js +2 -2
  108. package/dist/runtime/cpython-runtime.d.ts.map +1 -1
  109. package/dist/runtime/cpython-runtime.js +2 -2
  110. package/dist/runtime/cpython-runtime.js.map +2 -2
  111. package/dist/runtime/guest-types.d.ts +1 -1
  112. package/dist/runtime/guest-types.d.ts.map +1 -1
  113. package/dist/runtime/guest-types.js +1 -1
  114. package/dist/runtime/monty-bridge.d.ts.map +1 -1
  115. package/dist/runtime/monty-runtime.js +9 -89
  116. package/dist/runtime/monty-runtime.js.map +3 -3
  117. package/dist/runtime/python-arguments.d.ts +2 -0
  118. package/dist/runtime/python-arguments.d.ts.map +1 -0
  119. package/dist/runtime/typescript-kernel.js +5 -5
  120. package/dist/runtime-state-speculation.d.ts +1 -1
  121. package/dist/runtime-state-speculation.d.ts.map +1 -1
  122. package/dist/speculation/python-scanner.d.ts +7 -0
  123. package/dist/speculation/python-scanner.d.ts.map +1 -0
  124. package/dist/speculation/python-scanner.js +166 -0
  125. package/dist/speculation/python-scanner.js.map +7 -0
  126. package/dist/speculation/stream-tap.d.ts +5 -2
  127. package/dist/speculation/stream-tap.d.ts.map +1 -1
  128. package/dist/ui/dashboard.js +6 -5
  129. package/dist/ui/dashboard.js.map +1 -1
  130. package/dist/ui/settings.js +4 -4
  131. package/dist/worker/model-control.d.ts +14 -0
  132. package/dist/worker/model-control.d.ts.map +1 -0
  133. package/dist/worker/model-control.js +109 -0
  134. package/dist/worker/model-control.js.map +7 -0
  135. package/dist/worker/run-record.js +1 -1
  136. package/dist/worker/run-record.js.map +2 -2
  137. package/dist/worker.js +75 -65
  138. package/dist/worker.js.map +2 -2
  139. package/docs/agents.md +10 -0
  140. package/docs/kernels.md +1 -1
  141. package/docs/speculation.md +30 -23
  142. package/package.json +11 -1
  143. package/dist/chunks/chunk-CGIPKJSC.js.map +0 -7
  144. package/dist/chunks/chunk-G23OLG5P.js.map +0 -7
  145. package/dist/chunks/chunk-GSOL7EZB.js.map +0 -7
  146. package/dist/chunks/chunk-GUQT67PQ.js.map +0 -7
  147. package/dist/chunks/chunk-J7BQS5XH.js.map +0 -7
  148. package/dist/chunks/chunk-YIDC2IVN.js.map +0 -7
  149. /package/dist/chunks/{chunk-M3R56VXZ.js.map → chunk-CHNDPTCW.js.map} +0 -0
  150. /package/dist/chunks/{chunk-Z43ZKIZT.js.map → chunk-J2HV2URQ.js.map} +0 -0
  151. /package/dist/chunks/{chunk-JQJBQA2C.js.map → chunk-TMMK5L63.js.map} +0 -0
  152. /package/dist/chunks/{chunk-TQR7IE6H.js.map → chunk-UVUWHPAO.js.map} +0 -0
  153. /package/dist/chunks/{chunk-BOCWQOTG.js.map → chunk-V7RXK6MR.js.map} +0 -0
package/dist/agents.js ADDED
@@ -0,0 +1,615 @@
1
+ import {
2
+ validateAgentResult
3
+ } from "./chunks/chunk-3QECYQGA.js";
4
+ import {
5
+ AGENTS_ACTION_DESCRIPTORS,
6
+ normalizeAgentRunRequest
7
+ } from "./chunks/chunk-AAXQR7SZ.js";
8
+ import {
9
+ actionArgNormalizer
10
+ } from "./chunks/chunk-NQOEHX62.js";
11
+ import {
12
+ AgentAdmission,
13
+ assertAgentTask,
14
+ beginAgentSettlement,
15
+ createAgentLifecycle,
16
+ finishAgentSettlement,
17
+ terminalAgentStatuses,
18
+ waitForAgent
19
+ } from "./chunks/chunk-YDM3MYCO.js";
20
+ import "./chunks/chunk-OTCASLY2.js";
21
+ import "./chunks/chunk-MGWQOKBV.js";
22
+ import "./chunks/chunk-3H7SDWZI.js";
23
+
24
+ // src/agents/service-schema.ts
25
+ import { Value } from "typebox/value";
26
+ var native = (name) => {
27
+ const descriptor = AGENTS_ACTION_DESCRIPTORS.find((entry) => entry.name === name);
28
+ if (!descriptor) throw new Error(`Missing native agent descriptor: ${name}`);
29
+ return structuredClone(descriptor);
30
+ };
31
+ var run = native("run");
32
+ var properties = { ...run.inputSchema.properties };
33
+ for (const key of ["transport", "persona"]) delete properties[key];
34
+ Object.assign(properties, {
35
+ runner: { type: "string", enum: ["pi"] },
36
+ kernel: { type: "string", enum: ["typescript", "inherit"] },
37
+ extensions: { type: "boolean", const: true },
38
+ worktree: { type: "boolean", const: false },
39
+ timeoutMs: { type: "number", minimum: 1 },
40
+ cwd: { type: "string", description: "Host-authorized placement selector; never resolved by Fabric" },
41
+ images: { type: "array", items: { type: "object", properties: { type: { const: "image" }, data: { type: "string" }, mimeType: { type: "string" } }, required: ["type", "data", "mimeType"], additionalProperties: false } },
42
+ systemPrompt: { type: "string" }
43
+ });
44
+ var runSchema = { type: "object", properties, required: ["task"], additionalProperties: false };
45
+ var id = { type: "string", minLength: 1 };
46
+ var object = (properties2, required = []) => ({ type: "object", properties: properties2, required, additionalProperties: false });
47
+ function agentServiceDescriptors(capabilities = {}) {
48
+ const descriptors2 = [
49
+ { ...run, description: "Run one host-authorized Pi child and wait for its result or pause", inputSchema: runSchema },
50
+ { ...native("spawn"), description: "Admit one host-authorized Pi child and return its record", inputSchema: runSchema },
51
+ ...["wait", "status", "stop"].map((name) => ({ ...native(name), inputSchema: object({ id }, ["id"]) })),
52
+ { ...native("list"), description: "List only the authenticated caller's direct children", inputSchema: object({}) }
53
+ ];
54
+ if (capabilities.steer) descriptors2.push({ ...native("steer"), inputSchema: object({ id, message: { type: "string", minLength: 1 } }, ["id", "message"]) });
55
+ if (capabilities.compact) descriptors2.push({ ...native("compact"), inputSchema: object({ id, instructions: { type: "string" } }, ["id"]) });
56
+ if (capabilities.resume) descriptors2.push({ name: "resume", description: "Continue a paused, completed or failed direct child from its host checkpoint and wait for result or pause", risk: "agent", inputSchema: object({ id, task: { type: "string", minLength: 1 } }, ["id"]) });
57
+ return descriptors2;
58
+ }
59
+ var descriptors = agentServiceDescriptors({ steer: true, compact: true, resume: true });
60
+ var normalize = actionArgNormalizer(() => descriptors);
61
+ function agentServiceArgs(action, input) {
62
+ const descriptor = descriptors.find((entry) => entry.name === action);
63
+ if (!descriptor) throw new Error(`Unsupported hosted agents action: ${action}`);
64
+ const args = normalize(action, input);
65
+ if (!Value.Check(descriptor.inputSchema, args)) {
66
+ const reasons = [...Value.Errors(descriptor.inputSchema, args)].slice(0, 5).map((error) => `${error.instancePath}: ${error.message}`);
67
+ throw new Error(`Invalid hosted agents.${action} arguments: ${reasons.join("; ")}`);
68
+ }
69
+ return args;
70
+ }
71
+ function normalizeAgentServiceRequest(input) {
72
+ const args = agentServiceArgs("run", input);
73
+ const request = normalizeAgentRunRequest(args, { runner: "pi", timeoutMs: 0 });
74
+ if (args.images !== void 0) request.images = structuredClone(args.images);
75
+ if (args.systemPrompt !== void 0) request.systemPrompt = args.systemPrompt;
76
+ assertAgentTask(request);
77
+ return structuredClone(request);
78
+ }
79
+
80
+ // src/agents/service.ts
81
+ var copy = (value) => structuredClone(value);
82
+ var publicRecord = (record) => {
83
+ const keys = ["id", "rootId", "parentId", "depth", "generation", "name", "task", "status", "runner", "kernel", "cwd", "model", "thinking", "recursive", "startedAt", "updatedAt", "finishedAt", "currentTool", "turns", "toolCalls", "text", "value", "error", "usage", "sessionId"];
84
+ return copy(Object.fromEntries(keys.filter((key) => record[key] !== void 0).map((key) => [key, record[key]])));
85
+ };
86
+ var errorText = (error) => error instanceof Error ? error.message : String(error);
87
+ var idle = () => ({ settled: true, result: void 0, resolve: void 0, release() {
88
+ }, abortSignal: void 0, abortHandler: void 0 });
89
+ var AgentService = class {
90
+ #options;
91
+ #entries = /* @__PURE__ */ new Map();
92
+ #admission;
93
+ #pending = /* @__PURE__ */ new Map();
94
+ #closing = new AbortController();
95
+ #close;
96
+ #suspend;
97
+ #suspended = false;
98
+ #sequence = 0;
99
+ #publication = Promise.resolve();
100
+ capabilities;
101
+ constructor(options) {
102
+ if (!options.rootId) throw new Error("Agent service requires a trusted rootId");
103
+ for (const [key, value] of Object.entries({ maxStarts: options.maxStarts ?? 8, maxDepth: options.maxDepth ?? 3, maxConcurrent: options.maxConcurrent ?? 4 })) {
104
+ if (!Number.isSafeInteger(value) || value < 1) throw new Error(`${key} must be a positive integer`);
105
+ }
106
+ this.#options = { ...options, port: options.port };
107
+ this.#admission = new AgentAdmission(options.maxConcurrent ?? 4, options.maxStarts ?? 8, options.maxDepth ?? 3);
108
+ this.capabilities = Object.freeze({ steer: Boolean(options.port.steer), compact: Boolean(options.port.compact), resume: Boolean(options.port.resume) });
109
+ if (options.snapshot) this.#restore(options.snapshot);
110
+ }
111
+ snapshot() {
112
+ return copy({
113
+ version: 1,
114
+ rootId: this.#options.rootId,
115
+ starts: this.#admission.starts,
116
+ sequence: this.#sequence,
117
+ records: [...this.#entries.values()].map(({ request, record }) => ({ request, record }))
118
+ });
119
+ }
120
+ async run(callerId, request, signal) {
121
+ const handle = await this.spawn(callerId, request, signal);
122
+ return this.wait(callerId, handle.id, signal);
123
+ }
124
+ async spawn(callerId, request, signal) {
125
+ return this.#start(callerId, normalizeAgentServiceRequest(request), void 0, signal);
126
+ }
127
+ async wait(callerId, id2, signal) {
128
+ await this.#authorize(callerId);
129
+ const entry = this.#child(callerId, id2);
130
+ const result = entry.lifecycle.result ?? Promise.resolve(copy(entry.record));
131
+ const record = await waitForAgent(result, signal);
132
+ await this.#authorize(callerId);
133
+ return publicRecord(record);
134
+ }
135
+ async status(callerId, id2) {
136
+ await this.#authorize(callerId);
137
+ return publicRecord(this.#child(callerId, id2).record);
138
+ }
139
+ async list(callerId) {
140
+ await this.#authorize(callerId);
141
+ return [...this.#entries.values()].filter((entry) => entry.record.parentId === callerId).map((entry) => publicRecord(entry.record));
142
+ }
143
+ async stop(callerId, id2) {
144
+ await this.#authorize(callerId);
145
+ const result = await this.#stop(this.#child(callerId, id2));
146
+ await this.#authorize(callerId);
147
+ return publicRecord(result);
148
+ }
149
+ async steer(callerId, id2, message) {
150
+ if (!this.#options.port.steer) throw new Error("Hosted agents.steer is unsupported");
151
+ if (!message.trim()) throw new Error("Steering message must not be empty");
152
+ return this.#control(callerId, id2, "steer", (request) => this.#options.port.steer({ ...request, message }));
153
+ }
154
+ async compact(callerId, id2, instructions) {
155
+ if (!this.#options.port.compact) throw new Error("Hosted agents.compact is unsupported");
156
+ return this.#control(callerId, id2, "compact", (request) => this.#options.port.compact({ ...request, ...instructions !== void 0 ? { instructions } : {} }));
157
+ }
158
+ async resume(callerId, id2, task, signal) {
159
+ if (!this.#options.port.resume) throw new Error("Hosted agents.resume is unsupported");
160
+ await this.#authorize(callerId);
161
+ const entry = this.#child(callerId, id2);
162
+ if (!["paused", "completed", "failed"].includes(entry.record.status) || !entry.lifecycle.settled || entry.resuming || entry.stopping) throw new Error("Only an idle paused, completed or failed agent can resume");
163
+ entry.resuming = true;
164
+ try {
165
+ const request = normalizeAgentServiceRequest({ ...entry.request, ...task !== void 0 ? { task } : {} });
166
+ await this.#start(callerId, request, entry, signal);
167
+ return await this.wait(callerId, id2, signal);
168
+ } finally {
169
+ entry.resuming = false;
170
+ }
171
+ }
172
+ /** Natural root completion waits for all background descendants without fencing live parents. */
173
+ async drain() {
174
+ for (; ; ) {
175
+ const work = [...this.#pending.values()];
176
+ for (const entry of this.#entries.values()) {
177
+ if (entry.lifecycle.result && entry.done) work.push(entry.done);
178
+ }
179
+ if (work.length === 0) return;
180
+ await Promise.allSettled(work);
181
+ }
182
+ }
183
+ /** Host-only graceful pause. The port, not the owner signal, quiesces participant effects. */
184
+ suspend() {
185
+ if (this.#suspend) return this.#suspend;
186
+ if (this.#closing.signal.aborted) return Promise.reject(new Error("Agent service is closed"));
187
+ if (!this.#options.port.pause && [...this.#entries.values()].some((entry) => !entry.lifecycle.settled)) {
188
+ return Promise.reject(new Error("Hosted agent suspension requires port.pause"));
189
+ }
190
+ this.#suspended = true;
191
+ for (const entry of this.#entries.values()) {
192
+ if (!entry.lifecycle.settled && !terminalAgentStatuses.has(entry.record.status)) entry.suspendRequested = true;
193
+ }
194
+ for (const controller of this.#pending.keys()) controller.abort();
195
+ this.#suspend = (async () => {
196
+ const roots = [...this.#entries.values()].filter((entry) => entry.record.parentId === this.#options.rootId);
197
+ const paused = await Promise.allSettled(roots.map((entry) => this.#pause(entry)));
198
+ await Promise.allSettled([...this.#pending.values()]);
199
+ const errors = paused.filter((result) => result.status === "rejected");
200
+ if (errors.length) throw new AggregateError(errors.map((result) => result.reason), "Agent suspension failed");
201
+ await this.drain();
202
+ })();
203
+ return this.#suspend;
204
+ }
205
+ async #pause(entry) {
206
+ const children = [...this.#entries.values()].filter((child) => child.record.parentId === entry.record.id);
207
+ const paused = await Promise.allSettled(children.map((child) => this.#pause(child)));
208
+ const errors = paused.filter((result) => result.status === "rejected").map((result) => result.reason);
209
+ if (errors.length) throw new AggregateError(errors, "Agent descendant suspension failed");
210
+ if (entry.executing && !entry.stopping) {
211
+ entry.pauseAck = Promise.resolve().then(async () => {
212
+ if (entry.executing && !entry.stopping) await this.#options.port.pause(this.#identity(entry));
213
+ });
214
+ try {
215
+ await entry.pauseAck;
216
+ } catch (error) {
217
+ throw new AggregateError([...errors, error], "Agent pause acknowledgment failed");
218
+ }
219
+ }
220
+ await entry.done;
221
+ }
222
+ close() {
223
+ if (this.#close) return this.#close;
224
+ this.#closing.abort();
225
+ for (const controller of this.#pending.keys()) controller.abort();
226
+ this.#close = (async () => {
227
+ const errors = [];
228
+ const stopped = await Promise.allSettled([...this.#entries.values()].map((entry) => this.#stop(entry, true)));
229
+ for (const result of stopped) if (result.status === "rejected") errors.push(result.reason);
230
+ await Promise.allSettled([...this.#pending.values()]);
231
+ if (errors.length) throw new AggregateError(errors, "Agent shutdown failed");
232
+ })();
233
+ return this.#close;
234
+ }
235
+ #start(callerId, request, previous, signal) {
236
+ const controller = new AbortController();
237
+ const abort = () => controller.abort();
238
+ signal?.addEventListener("abort", abort, { once: true });
239
+ if (signal?.aborted || this.#closing.signal.aborted || this.#suspended) controller.abort();
240
+ const operation = (async () => {
241
+ let release;
242
+ try {
243
+ await this.#authorize(callerId);
244
+ const depth = this.#depth(callerId);
245
+ if (controller.signal.aborted) throw new Error("Operation aborted");
246
+ if (depth > this.#admission.maxDepth) throw new Error(`Fabric agent depth limit reached (${this.#admission.maxDepth})`);
247
+ const id2 = previous?.record.id ?? crypto.randomUUID().replaceAll("-", "");
248
+ const generation = (previous?.record.generation ?? 0) + 1;
249
+ const prepare = { id: id2, generation, rootId: this.#options.rootId, parentId: callerId, depth, request: copy(request), signal: controller.signal };
250
+ const binding = await this.#options.port.prepare?.(prepare);
251
+ release = await this.#admission.acquire(callerId, controller.signal);
252
+ await this.#authorize(callerId);
253
+ this.#depth(callerId);
254
+ if (controller.signal.aborted || this.#closing.signal.aborted || previous?.stopping) throw new Error("Agent admission aborted");
255
+ this.#admission.admit(depth);
256
+ const now = Date.now();
257
+ const record = previous ? {
258
+ ...previous.record,
259
+ task: request.task,
260
+ status: "queued",
261
+ generation: previous.record.generation + 1,
262
+ text: "",
263
+ turns: 0,
264
+ toolCalls: 0,
265
+ updatedAt: now
266
+ } : {
267
+ id: id2,
268
+ rootId: this.#options.rootId,
269
+ parentId: callerId,
270
+ depth,
271
+ generation: 1,
272
+ name: (request.name ?? request.task.split("\n", 1)[0] ?? "Fabric agent").replace(/[\r\n\t]+/g, " ").trim().slice(0, 60) || "Fabric agent",
273
+ task: request.task,
274
+ status: "queued",
275
+ runner: "pi",
276
+ kernel: "typescript",
277
+ startedAt: now,
278
+ updatedAt: now,
279
+ turns: 0,
280
+ toolCalls: 0,
281
+ text: "",
282
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 },
283
+ ...request.model ? { model: request.model } : {},
284
+ ...request.thinking ? { thinking: request.thinking } : {},
285
+ ...request.cwd !== void 0 ? { cwd: request.cwd } : {},
286
+ ...request.recursive !== void 0 ? { recursive: request.recursive } : {}
287
+ };
288
+ delete record.finishedAt;
289
+ delete record.error;
290
+ delete record.value;
291
+ delete record.currentTool;
292
+ const entry = previous ?? { request, record, lifecycle: idle(), controller };
293
+ entry.request = copy(request);
294
+ entry.record = record;
295
+ entry.controller = controller;
296
+ entry.lifecycle = createAgentLifecycle(release);
297
+ release = void 0;
298
+ this.#entries.set(record.id, entry);
299
+ this.#pending.delete(controller);
300
+ signal?.removeEventListener("abort", abort);
301
+ let acknowledge;
302
+ const admitted = new Promise((resolve) => {
303
+ acknowledge = resolve;
304
+ });
305
+ entry.done = this.#drive(entry, binding, Boolean(previous), acknowledge);
306
+ await admitted;
307
+ await this.#authorize(callerId);
308
+ return publicRecord(record);
309
+ } finally {
310
+ release?.();
311
+ signal?.removeEventListener("abort", abort);
312
+ }
313
+ })();
314
+ this.#pending.set(controller, operation);
315
+ void operation.finally(() => this.#pending.delete(controller)).catch(() => {
316
+ });
317
+ return operation;
318
+ }
319
+ async #drive(entry, binding, resume, admitted) {
320
+ const generation = entry.record.generation;
321
+ let timer;
322
+ let timeout = false;
323
+ let responded = false;
324
+ try {
325
+ await this.#publish("admitted", entry);
326
+ admitted();
327
+ await this.#authorize(entry.record.parentId);
328
+ if (entry.controller.signal.aborted) throw new Error("Agent start aborted");
329
+ entry.record.status = "running";
330
+ await this.#publish("running", entry);
331
+ await this.#authorize(entry.record.parentId);
332
+ if (entry.controller.signal.aborted) throw new Error("Agent start aborted");
333
+ const request = {
334
+ ...this.#identity(entry),
335
+ depth: entry.record.depth,
336
+ request: copy(entry.request),
337
+ signal: entry.controller.signal,
338
+ binding,
339
+ ...entry.record.checkpoint !== void 0 ? { checkpoint: copy(entry.record.checkpoint) } : {},
340
+ emit: async (event) => {
341
+ const assertCurrent = () => {
342
+ if (!entry.executing || entry.lifecycle.settled || entry.controller.signal.aborted || entry.record.generation !== generation || entry.record.status !== "running") throw new Error("Stale agent execution event");
343
+ };
344
+ assertCurrent();
345
+ if (event.type !== "checkpoint" && event.type !== "progress") throw new Error("Unsupported agent execution event");
346
+ const saved = copy(event);
347
+ await this.#publish(saved.type, entry, void 0, () => {
348
+ if (saved.type === "checkpoint") entry.record.checkpoint = saved.checkpoint;
349
+ else {
350
+ for (const key of ["text", "turns", "toolCalls", "currentTool", "usage"]) {
351
+ if (saved[key] !== void 0) Object.assign(entry.record, { [key]: saved[key] });
352
+ }
353
+ }
354
+ }, assertCurrent);
355
+ }
356
+ };
357
+ if (entry.request.timeoutMs) timer = setTimeout(() => {
358
+ if (entry.suspendRequested) return;
359
+ timeout = true;
360
+ void this.#stop(entry).catch(() => {
361
+ });
362
+ }, entry.request.timeoutMs);
363
+ const execute = resume ? this.#options.port.resume : this.#options.port.execute;
364
+ entry.executing = true;
365
+ let response;
366
+ try {
367
+ response = await execute.call(this.#options.port, request);
368
+ } finally {
369
+ entry.executing = false;
370
+ }
371
+ if (!["completed", "failed", "stopped", "timed_out", "paused"].includes(response.status)) throw new Error("Invalid agent execution response status");
372
+ await this.#authorize(entry.record.parentId, response.status === "paused" ? { checkpoint: true } : void 0);
373
+ if (entry.record.generation !== generation || entry.lifecycle.settled) throw new Error("Stale agent execution response");
374
+ this.#applyResponse(entry, response);
375
+ responded = true;
376
+ } catch (error) {
377
+ entry.record.status = "failed";
378
+ entry.record.error = errorText(error);
379
+ } finally {
380
+ admitted();
381
+ if (timer) clearTimeout(timer);
382
+ await Promise.allSettled([...entry.controls ?? [], ...entry.stopAck ? [entry.stopAck] : [], ...entry.pauseAck ? [entry.pauseAck] : []]);
383
+ if (entry.suspendRequested && !entry.controller.signal.aborted) {
384
+ entry.record.status = "paused";
385
+ delete entry.record.error;
386
+ delete entry.record.finishedAt;
387
+ }
388
+ if (entry.controller.signal.aborted) {
389
+ if (entry.stopReason === "close") {
390
+ if (!responded || !["completed", "failed"].includes(entry.record.status)) {
391
+ entry.record.status = "paused";
392
+ delete entry.record.error;
393
+ }
394
+ } else entry.record.status = timeout ? "timed_out" : "stopped";
395
+ }
396
+ try {
397
+ await this.#options.port.cleanup?.(this.#identity(entry));
398
+ } catch (error) {
399
+ entry.record.status = "failed";
400
+ entry.record.error = `Agent cleanup failed: ${errorText(error)}`;
401
+ }
402
+ validateAgentResult(entry.record, entry.request.schema);
403
+ delete entry.record.currentTool;
404
+ if (terminalAgentStatuses.has(entry.record.status)) entry.record.finishedAt = Date.now();
405
+ if (beginAgentSettlement(entry.lifecycle)) {
406
+ try {
407
+ await this.#publish("settled", entry);
408
+ } catch (error) {
409
+ entry.record.status = "failed";
410
+ entry.record.error = `Agent publication failed: ${errorText(error)}`;
411
+ }
412
+ finishAgentSettlement(entry.lifecycle, copy(entry.record));
413
+ }
414
+ }
415
+ }
416
+ #applyResponse(entry, response) {
417
+ entry.record.status = response.status;
418
+ for (const key of ["text", "value", "error", "usage", "checkpoint", "sessionId"]) {
419
+ if (response[key] !== void 0) Object.assign(entry.record, { [key]: copy(response[key]) });
420
+ }
421
+ }
422
+ #stop(entry, preservePaused = false) {
423
+ if (entry.stopping) return entry.stopping;
424
+ entry.stopReason = preservePaused ? "close" : "stop";
425
+ const work = (async () => {
426
+ const active = !entry.lifecycle.settled;
427
+ entry.controller.abort();
428
+ const descendants = [...this.#entries.values()].filter((child) => child.record.parentId === entry.record.id);
429
+ const operations = descendants.map((child) => this.#stop(child, preservePaused));
430
+ if (active && this.#options.port.stop) {
431
+ entry.stopAck = Promise.resolve().then(() => this.#options.port.stop(this.#identity(entry)));
432
+ operations.push(entry.stopAck);
433
+ }
434
+ if (entry.done) operations.push(entry.done);
435
+ const settled = await Promise.allSettled(operations);
436
+ if (entry.record.status === "paused" && !preservePaused) {
437
+ entry.record.status = "stopped";
438
+ entry.record.finishedAt = Date.now();
439
+ await this.#publish("settled", entry);
440
+ }
441
+ const errors = settled.filter((result) => result.status === "rejected");
442
+ if (errors.length) throw new AggregateError(errors.map((result) => result.reason), "Agent stop failed");
443
+ return publicRecord(entry.record);
444
+ })();
445
+ entry.stopping = work;
446
+ return work;
447
+ }
448
+ async #control(callerId, id2, control, invoke) {
449
+ await this.#authorize(callerId);
450
+ const entry = this.#child(callerId, id2);
451
+ if (entry.record.status !== "running" || entry.stopping) throw new Error("Agent is not running");
452
+ const generation = entry.record.generation;
453
+ const pending = Promise.resolve().then(async () => {
454
+ await this.#authorize(callerId);
455
+ if (entry.record.generation !== generation || entry.controller.signal.aborted || entry.lifecycle.settled) throw new Error("Stale agent control");
456
+ await invoke(this.#identity(entry));
457
+ });
458
+ (entry.controls ??= /* @__PURE__ */ new Set()).add(pending);
459
+ try {
460
+ await pending;
461
+ } finally {
462
+ entry.controls.delete(pending);
463
+ }
464
+ await this.#authorize(callerId);
465
+ if (entry.record.generation !== generation || entry.controller.signal.aborted) throw new Error("Stale agent control acknowledgment");
466
+ await this.#publish("control", entry, control);
467
+ return publicRecord(entry.record);
468
+ }
469
+ #identity(entry) {
470
+ const { id: id2, rootId, parentId, generation } = entry.record;
471
+ return { id: id2, rootId, parentId, generation };
472
+ }
473
+ async #authorize(callerId, boundary) {
474
+ if (callerId !== this.#options.rootId && !this.#entries.has(callerId)) throw new Error("Unknown agent caller");
475
+ if (this.#suspended && !boundary?.checkpoint) throw new Error("Agent service is paused");
476
+ await this.#options.assertAuthority?.(callerId, boundary);
477
+ if (this.#suspended && !boundary?.checkpoint) throw new Error("Agent service is paused");
478
+ }
479
+ #child(callerId, id2) {
480
+ const entry = this.#entries.get(id2);
481
+ if (!entry || entry.record.parentId !== callerId) throw new Error(`Unknown direct child agent: ${id2}`);
482
+ return entry;
483
+ }
484
+ #depth(callerId) {
485
+ if (this.#closing.signal.aborted) throw new Error("Agent service is closed");
486
+ if (this.#suspended) throw new Error("Agent service is paused");
487
+ if (callerId === this.#options.rootId) return 1;
488
+ const parent = this.#entries.get(callerId);
489
+ if (!parent || parent.record.status !== "running" || parent.stopping || parent.controller.signal.aborted || parent.request.recursive === false) throw new Error("Agent parent cannot admit children");
490
+ return parent.record.depth + 1;
491
+ }
492
+ async #publish(type, entry, control, update, assertCurrent) {
493
+ const boundary = type === "checkpoint" || type === "settled" ? { checkpoint: true } : void 0;
494
+ const generation = entry.record.generation;
495
+ await this.#authorize(entry.record.parentId, boundary);
496
+ const publication = this.#publication.then(async () => {
497
+ await this.#authorize(entry.record.parentId, boundary);
498
+ if (entry.record.generation !== generation) throw new Error("Stale agent publication");
499
+ assertCurrent?.();
500
+ update?.();
501
+ entry.record.updatedAt = Date.now();
502
+ const event = { version: 1, sequence: ++this.#sequence, type, record: copy(entry.record), ...control ? { control } : {} };
503
+ await this.#options.onEvent?.(event);
504
+ });
505
+ this.#publication = publication.catch(() => {
506
+ });
507
+ await publication;
508
+ }
509
+ #restore(snapshot) {
510
+ const saved = copy(snapshot);
511
+ const newRoot = this.#options.restorePolicy === "new-root";
512
+ if (newRoot && saved.rootId !== this.#options.rootId) {
513
+ const oldRoot = saved.rootId;
514
+ saved.rootId = this.#options.rootId;
515
+ for (const { record } of saved.records) {
516
+ if (record.rootId !== oldRoot) throw new Error("Invalid agent snapshot root");
517
+ record.rootId = saved.rootId;
518
+ if (record.parentId === oldRoot) record.parentId = saved.rootId;
519
+ }
520
+ }
521
+ if (saved.version !== 1 || saved.rootId !== this.#options.rootId || !Number.isSafeInteger(saved.starts) || saved.starts < 0 || !newRoot && saved.starts > this.#admission.maxStarts || !Number.isSafeInteger(saved.sequence) || saved.sequence < 0 || !Array.isArray(saved.records)) throw new Error("Invalid agent service snapshot");
522
+ let generations = 0;
523
+ for (const item of saved.records) {
524
+ const request = normalizeAgentServiceRequest(item.request);
525
+ const record = item.record;
526
+ if (!record.id || record.id === saved.rootId || this.#entries.has(record.id) || record.rootId !== saved.rootId || !Number.isSafeInteger(record.depth) || record.depth < 1 || record.depth > this.#admission.maxDepth || !Number.isSafeInteger(record.generation) || record.generation < 1 || !["queued", "running", "paused", ...terminalAgentStatuses].includes(record.status)) throw new Error("Invalid agent snapshot record");
527
+ generations += record.generation;
528
+ if (record.status === "running" || record.status === "queued") {
529
+ record.status = "paused";
530
+ delete record.finishedAt;
531
+ }
532
+ this.#entries.set(record.id, { request, record, lifecycle: idle(), controller: new AbortController() });
533
+ }
534
+ for (const { record } of this.#entries.values()) {
535
+ const parent = this.#entries.get(record.parentId);
536
+ if (record.parentId === saved.rootId ? record.depth !== 1 : !parent || parent.record.depth + 1 !== record.depth) throw new Error("Invalid agent snapshot lineage");
537
+ }
538
+ if (saved.starts > generations) throw new Error("Invalid agent snapshot admission count");
539
+ this.#admission.starts = newRoot ? 0 : saved.starts;
540
+ this.#sequence = saved.sequence;
541
+ }
542
+ };
543
+
544
+ // src/agents/service-provider.ts
545
+ function createAgentServiceHandler(service, callerId) {
546
+ return async (action, input, signal) => {
547
+ const args = agentServiceArgs(action, input);
548
+ switch (action) {
549
+ case "run":
550
+ return service.run(callerId, args, signal);
551
+ case "spawn":
552
+ return service.spawn(callerId, args, signal);
553
+ case "wait":
554
+ return service.wait(callerId, args.id, signal);
555
+ case "status":
556
+ return service.status(callerId, args.id);
557
+ case "list":
558
+ return service.list(callerId);
559
+ case "stop":
560
+ return service.stop(callerId, args.id);
561
+ case "steer":
562
+ return service.steer(callerId, args.id, args.message);
563
+ case "compact":
564
+ return service.compact(callerId, args.id, args.instructions);
565
+ case "resume":
566
+ return service.resume(callerId, args.id, args.task, signal);
567
+ default:
568
+ throw new Error(`Unsupported hosted agents action: ${String(action)}`);
569
+ }
570
+ };
571
+ }
572
+ function createAgentServiceClient(dispatch, capabilities = {}) {
573
+ const record = (action, args, signal) => dispatch(action, args, signal);
574
+ return {
575
+ capabilities: Object.freeze({ ...capabilities }),
576
+ dispatch,
577
+ run: (request, signal) => record("run", request, signal),
578
+ spawn: (request, signal) => record("spawn", request, signal),
579
+ wait: (id2, signal) => record("wait", { id: id2 }, signal),
580
+ status: (id2) => record("status", { id: id2 }),
581
+ list: () => dispatch("list", {}),
582
+ stop: (id2) => record("stop", { id: id2 }),
583
+ steer: (id2, message) => record("steer", { id: id2, message }),
584
+ compact: (id2, instructions) => record("compact", { id: id2, ...instructions !== void 0 ? { instructions } : {} }),
585
+ resume: (id2, task, signal) => record("resume", { id: id2, ...task !== void 0 ? { task } : {} }, signal)
586
+ };
587
+ }
588
+ function createAgentsProvider(client) {
589
+ const descriptors2 = agentServiceDescriptors(client.capabilities);
590
+ const allowed = new Set(descriptors2.map((descriptor) => descriptor.name));
591
+ const validate = (action, args) => {
592
+ if (!allowed.has(action)) throw new Error(`Unsupported hosted agents action: ${action}`);
593
+ return agentServiceArgs(action, args);
594
+ };
595
+ return {
596
+ name: "agents",
597
+ description: "Fabric host-authorized Pi agents",
598
+ list: async () => structuredClone(descriptors2),
599
+ describe: async (name) => structuredClone(descriptors2.find((descriptor) => descriptor.name === name)),
600
+ prepareArguments: (action, args) => validate(action, args),
601
+ invoke: async (action, args, context) => client.dispatch(action, validate(action, args), context.signal)
602
+ };
603
+ }
604
+
605
+ // src/agents.ts
606
+ var HOSTED_AGENTS_PROTOCOL_VERSION = 1;
607
+ export {
608
+ AgentService,
609
+ HOSTED_AGENTS_PROTOCOL_VERSION,
610
+ agentServiceDescriptors,
611
+ createAgentServiceClient,
612
+ createAgentServiceHandler,
613
+ createAgentsProvider
614
+ };
615
+ //# sourceMappingURL=agents.js.map