@tangle-network/agent-runtime 0.44.0 → 0.45.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 (89) hide show
  1. package/README.md +95 -203
  2. package/dist/agent.d.ts +5 -4
  3. package/dist/agent.js +5 -7
  4. package/dist/agent.js.map +1 -1
  5. package/dist/analyst-loop.d.ts +65 -4
  6. package/dist/analyst-loop.js +6 -1
  7. package/dist/audit.d.ts +93 -0
  8. package/dist/audit.js +312 -0
  9. package/dist/audit.js.map +1 -0
  10. package/dist/chunk-4B6U4CVQ.js +15 -0
  11. package/dist/chunk-4B6U4CVQ.js.map +1 -0
  12. package/dist/chunk-FK53TXOP.js +603 -0
  13. package/dist/chunk-FK53TXOP.js.map +1 -0
  14. package/dist/{chunk-SKUZZCHE.js → chunk-IJ6FGOPO.js} +5 -5
  15. package/dist/chunk-IJ6FGOPO.js.map +1 -0
  16. package/dist/{chunk-HVYOHJHK.js → chunk-IJGS6J7X.js} +2 -2
  17. package/dist/chunk-IJGS6J7X.js.map +1 -0
  18. package/dist/chunk-KEWO4KI6.js +3599 -0
  19. package/dist/chunk-KEWO4KI6.js.map +1 -0
  20. package/dist/{chunk-NRZOXCJK.js → chunk-KSMX62JF.js} +2 -2
  21. package/dist/{chunk-GFKVVRQ7.js → chunk-NYN5RTLP.js} +11 -10
  22. package/dist/chunk-NYN5RTLP.js.map +1 -0
  23. package/dist/chunk-PRX45WE2.js +264 -0
  24. package/dist/chunk-PRX45WE2.js.map +1 -0
  25. package/dist/{chunk-3HMHSN22.js → chunk-QR4UUC5P.js} +6 -6
  26. package/dist/chunk-QR4UUC5P.js.map +1 -0
  27. package/dist/chunk-WIR4HOOJ.js +27 -0
  28. package/dist/chunk-WIR4HOOJ.js.map +1 -0
  29. package/dist/{chunk-KDMRUD2P.js → chunk-Z2QXVBA6.js} +296 -8
  30. package/dist/chunk-Z2QXVBA6.js.map +1 -0
  31. package/dist/coder-CczgMqFx.d.ts +114 -0
  32. package/dist/dynamic-BvllHV6M.d.ts +221 -0
  33. package/dist/{improvement-adapter-BC4HhuAR.d.ts → improvement-adapter-CWegd3vw.d.ts} +1 -1
  34. package/dist/improvement.d.ts +2 -3
  35. package/dist/improvement.js +0 -5
  36. package/dist/improvement.js.map +1 -1
  37. package/dist/index.d.ts +123 -10
  38. package/dist/index.js +398 -10
  39. package/dist/index.js.map +1 -1
  40. package/dist/{kb-gate-D0ZIhFOU.d.ts → kb-gate-D9GBocLN.d.ts} +82 -5
  41. package/dist/{loop-runner-bin-BLMa8He3.d.ts → loop-runner-bin-CPrCoKqC.d.ts} +14 -10
  42. package/dist/loop-runner-bin.d.ts +9 -7
  43. package/dist/loop-runner-bin.js +6 -8
  44. package/dist/loops.d.ts +7 -393
  45. package/dist/loops.js +94 -25
  46. package/dist/mcp/bin.js +7 -7
  47. package/dist/mcp/bin.js.map +1 -1
  48. package/dist/mcp/index.d.ts +284 -11
  49. package/dist/mcp/index.js +341 -9
  50. package/dist/mcp/index.js.map +1 -1
  51. package/dist/{otel-export-wFDmmurL.d.ts → otel-export-Dy2DyUCU.d.ts} +1 -1
  52. package/dist/profiles.d.ts +385 -86
  53. package/dist/profiles.js +549 -4
  54. package/dist/profiles.js.map +1 -1
  55. package/dist/{run-loop-C4L1Sted.d.ts → run-loop--hSoIknW.d.ts} +35 -12
  56. package/dist/runtime-hooks-C7JwKb9E.d.ts +70 -0
  57. package/dist/runtime.d.ts +1860 -0
  58. package/dist/runtime.js +114 -0
  59. package/dist/runtime.js.map +1 -0
  60. package/dist/substrate-CUgk7F7s.d.ts +77 -0
  61. package/dist/topology.d.ts +73 -0
  62. package/dist/topology.js +111 -0
  63. package/dist/topology.js.map +1 -0
  64. package/dist/types-1HbsFa7H.d.ts +438 -0
  65. package/dist/{types-p8dWBIXL.d.ts → types-BtRLF2U3.d.ts} +1 -1
  66. package/dist/{types-DbJzz2uf.d.ts → types-DdzkffAm.d.ts} +95 -1
  67. package/dist/workflow.d.ts +3 -2
  68. package/dist/workflow.js +4 -5
  69. package/dist/workflow.js.map +1 -1
  70. package/package.json +26 -6
  71. package/skills/agent-runtime-adoption/SKILL.md +29 -26
  72. package/dist/chunk-3HMHSN22.js.map +0 -1
  73. package/dist/chunk-GFKVVRQ7.js.map +0 -1
  74. package/dist/chunk-HVYOHJHK.js.map +0 -1
  75. package/dist/chunk-KDMRUD2P.js.map +0 -1
  76. package/dist/chunk-PY6NMZYX.js +0 -52
  77. package/dist/chunk-PY6NMZYX.js.map +0 -1
  78. package/dist/chunk-S7JXV32P.js +0 -947
  79. package/dist/chunk-S7JXV32P.js.map +0 -1
  80. package/dist/chunk-SKUZZCHE.js.map +0 -1
  81. package/dist/chunk-SQSCRJ7U.js +0 -65
  82. package/dist/chunk-SQSCRJ7U.js.map +0 -1
  83. package/dist/chunk-VOX6Z3II.js +0 -90
  84. package/dist/chunk-VOX6Z3II.js.map +0 -1
  85. package/dist/chunk-XBUG326M.js +0 -261
  86. package/dist/chunk-XBUG326M.js.map +0 -1
  87. package/dist/dynamic-wUgp6UKs.d.ts +0 -108
  88. package/dist/optimize-prompt-D-urF2wW.d.ts +0 -129
  89. /package/dist/{chunk-NRZOXCJK.js.map → chunk-KSMX62JF.js.map} +0 -0
@@ -1,947 +0,0 @@
1
- import {
2
- PlannerError,
3
- ValidationError
4
- } from "./chunk-SQSCRJ7U.js";
5
-
6
- // src/loops/drivers/dynamic.ts
7
- function createDynamicDriver(options) {
8
- if (typeof options.planner !== "function") {
9
- throw new ValidationError("createDynamicDriver: planner must be a function");
10
- }
11
- const maxIterations = options.maxIterations ?? 8;
12
- if (!Number.isFinite(maxIterations) || maxIterations <= 0) {
13
- throw new ValidationError("createDynamicDriver: maxIterations must be > 0");
14
- }
15
- const maxFanout = options.maxFanout ?? 4;
16
- if (!Number.isFinite(maxFanout) || maxFanout < 1) {
17
- throw new ValidationError("createDynamicDriver: maxFanout must be >= 1");
18
- }
19
- let pending;
20
- return {
21
- name: options.name ?? "dynamic",
22
- async plan(task, history) {
23
- if (history.length >= maxIterations) {
24
- pending = { kind: "stop", rationale: `maxIterations (${maxIterations}) reached` };
25
- return [];
26
- }
27
- const move = await options.planner({
28
- task,
29
- history,
30
- iterationsSpent: history.length,
31
- iterationsRemaining: maxIterations - history.length
32
- });
33
- pending = validateMove(move, maxFanout);
34
- switch (pending.kind) {
35
- case "refine":
36
- return [pending.task];
37
- case "fanout":
38
- return pending.tasks;
39
- case "stop":
40
- return [];
41
- }
42
- },
43
- decide() {
44
- return pending?.kind === "stop" ? "done" : "continue";
45
- },
46
- describePlan() {
47
- if (!pending) return void 0;
48
- const out = { kind: pending.kind };
49
- if (pending.rationale !== void 0) out.rationale = pending.rationale;
50
- if (pending.kind !== "stop" && pending.parentIndex !== void 0) {
51
- out.parentIndex = pending.parentIndex;
52
- }
53
- return out;
54
- }
55
- };
56
- }
57
- function validateMove(move, maxFanout) {
58
- if (!move || typeof move !== "object" || typeof move.kind !== "string") {
59
- throw new PlannerError(`dynamic planner returned a non-move value: ${describe(move)}`);
60
- }
61
- switch (move.kind) {
62
- case "refine":
63
- return move;
64
- case "stop":
65
- return move;
66
- case "fanout": {
67
- if (!Array.isArray(move.tasks) || move.tasks.length === 0) {
68
- throw new PlannerError("dynamic planner fanout move must carry a non-empty tasks[]");
69
- }
70
- if (move.tasks.length <= maxFanout) return move;
71
- return {
72
- kind: "fanout",
73
- tasks: move.tasks.slice(0, maxFanout),
74
- rationale: `${move.rationale ?? ""} [clamped ${move.tasks.length}\u2192${maxFanout}]`.trim()
75
- };
76
- }
77
- default:
78
- throw new PlannerError(
79
- `dynamic planner returned unknown move kind: ${describe(move.kind)}`
80
- );
81
- }
82
- }
83
- function describe(value) {
84
- try {
85
- return JSON.stringify(value) ?? String(value);
86
- } catch {
87
- return String(value);
88
- }
89
- }
90
- function summarizeHistory(history, opts = {}) {
91
- const maxOutputChars = opts.maxOutputChars ?? 600;
92
- return history.map((iter) => {
93
- const row = { index: iter.index, agentRunName: iter.agentRunName };
94
- if (iter.verdict) {
95
- row.valid = iter.verdict.valid;
96
- if (typeof iter.verdict.score === "number") row.score = iter.verdict.score;
97
- }
98
- if (iter.error) row.error = iter.error.message;
99
- if (iter.output !== void 0) {
100
- const serialized = describe(iter.output);
101
- row.output = serialized.length > maxOutputChars ? `${serialized.slice(0, maxOutputChars)}\u2026` : serialized;
102
- }
103
- return row;
104
- });
105
- }
106
-
107
- // src/loops/drivers/planners.ts
108
- var blind = ({ task, history }) => history.length === 0 ? { kind: "refine", task, rationale: "blind: single attempt" } : { kind: "stop", rationale: "blind: one attempt only" };
109
- var PROMPT_PLANNERS = {
110
- blind
111
- };
112
- function resolvePlanner(name) {
113
- const planner = PROMPT_PLANNERS[name];
114
- if (!planner) {
115
- throw new Error(
116
- `planners: unknown driver '${name}' (have: ${Object.keys(PROMPT_PLANNERS).join(", ")})`
117
- );
118
- }
119
- return planner;
120
- }
121
-
122
- // src/loops/drivers/refine.ts
123
- function createRefineDriver(options = {}) {
124
- const maxIterations = options.maxIterations ?? 5;
125
- if (!Number.isFinite(maxIterations) || maxIterations <= 0) {
126
- throw new ValidationError("createRefineDriver: maxIterations must be > 0");
127
- }
128
- const refineTask = options.refineTask;
129
- return {
130
- name: options.name ?? "refine",
131
- async plan(task, history) {
132
- if (history.length >= maxIterations) return [];
133
- if (history.length === 0) return [task];
134
- const prior = history.at(-1);
135
- if (!prior) return [task];
136
- if (prior.verdict?.valid === true) return [];
137
- if (!refineTask || !prior.verdict) return [prior.task];
138
- return [refineTask(prior.task, prior.verdict)];
139
- },
140
- decide(history) {
141
- const last = history.at(-1);
142
- if (!last) return "continue";
143
- if (last.verdict?.valid === true) return "stop";
144
- if (history.length >= maxIterations) return "stop";
145
- return "continue";
146
- }
147
- };
148
- }
149
- function refineWinnerIndex(iterations) {
150
- for (let i = iterations.length - 1; i >= 0; i -= 1) {
151
- if (iterations[i]?.verdict?.valid) return i;
152
- }
153
- return iterations.length > 0 ? iterations.length - 1 : void 0;
154
- }
155
-
156
- // src/loops/drivers/sandbox-planner.ts
157
- function createSandboxPlanner(opts) {
158
- if (!opts.client || typeof opts.client.create !== "function") {
159
- throw new ValidationError("createSandboxPlanner: client.create is required");
160
- }
161
- if (typeof opts.decodeTask !== "function") {
162
- throw new ValidationError("createSandboxPlanner: decodeTask is required");
163
- }
164
- const buildPrompt = opts.buildPrompt ?? defaultBuildPrompt;
165
- const parseEnvelope = opts.parseEnvelope ?? defaultParseEnvelope;
166
- return async (ctx) => {
167
- const reused = opts.reuseBox ? await opts.reuseBox() : void 0;
168
- const box = reused ?? await opts.client.create(buildSandboxOptions(opts.profile, opts.sandboxOverrides));
169
- const plannerOwnsBox = reused === void 0;
170
- try {
171
- const prompt = await buildPrompt(ctx);
172
- const events = [];
173
- for await (const event of box.streamPrompt(prompt, { signal: opts.signal })) {
174
- events.push(event);
175
- }
176
- const envelope = parseEnvelope(events);
177
- if (!envelope) {
178
- throw new PlannerError("sandbox planner emitted no parseable topology-move envelope");
179
- }
180
- return envelopeToMove(envelope, ctx, opts.decodeTask);
181
- } finally {
182
- if (plannerOwnsBox) {
183
- try {
184
- if (typeof box.delete === "function") await box.delete();
185
- } catch {
186
- }
187
- }
188
- }
189
- };
190
- }
191
- function envelopeToMove(envelope, ctx, decodeTask) {
192
- const kind = String(envelope.kind ?? "").toLowerCase();
193
- const rationale = typeof envelope.rationale === "string" ? envelope.rationale : void 0;
194
- if (kind === "stop") {
195
- return { kind: "stop", rationale };
196
- }
197
- if (kind === "refine") {
198
- const raw = Array.isArray(envelope.tasks) ? envelope.tasks[0] : void 0;
199
- const task = raw === void 0 ? ctx.task : decodeTaskGuarded(decodeTask, raw, ctx);
200
- return { kind: "refine", task, rationale };
201
- }
202
- if (kind === "fanout") {
203
- const tasks = resolveFanoutTasks(envelope, ctx, decodeTask);
204
- return { kind: "fanout", tasks, rationale };
205
- }
206
- throw new PlannerError(
207
- `sandbox planner emitted unknown move kind: ${JSON.stringify(envelope.kind)}`
208
- );
209
- }
210
- function resolveFanoutTasks(envelope, ctx, decodeTask) {
211
- if (Array.isArray(envelope.tasks) && envelope.tasks.length > 0) {
212
- return envelope.tasks.map((raw) => decodeTaskGuarded(decodeTask, raw, ctx));
213
- }
214
- if (typeof envelope.n === "number" && Number.isFinite(envelope.n) && envelope.n >= 1) {
215
- return Array.from({ length: Math.floor(envelope.n) }, () => ctx.task);
216
- }
217
- throw new PlannerError("sandbox planner fanout envelope needs a non-empty tasks[] or n >= 1");
218
- }
219
- function decodeTaskGuarded(decodeTask, raw, ctx) {
220
- try {
221
- return decodeTask(raw, ctx);
222
- } catch (err) {
223
- throw new PlannerError(`sandbox planner decodeTask rejected ${JSON.stringify(raw)}`, {
224
- cause: err
225
- });
226
- }
227
- }
228
- function buildSandboxOptions(profile, overrides) {
229
- const base = overrides ?? {};
230
- const overrideBackend = base.backend;
231
- const explicitType = profile.metadata?.backendType;
232
- return {
233
- ...base,
234
- backend: {
235
- type: overrideBackend?.type ?? explicitType ?? "opencode",
236
- profile,
237
- ...overrideBackend?.model ? { model: overrideBackend.model } : {},
238
- ...overrideBackend?.server ? { server: overrideBackend.server } : {}
239
- }
240
- };
241
- }
242
- function defaultBuildPrompt(ctx) {
243
- const summary = summarizeHistory(ctx.history);
244
- return [
245
- "You are the loop planner. You do not do the work \u2014 you decide the topology of the next round.",
246
- "",
247
- `Root task:
248
- ${safeJson(ctx.task)}`,
249
- "",
250
- `Iterations spent: ${ctx.iterationsSpent}. Remaining before the hard cap: ${ctx.iterationsRemaining}.`,
251
- "",
252
- ctx.history.length === 0 ? "No attempts yet." : `Attempts so far (index, agent, verdict, output):
253
- ${safeJson(summary)}`,
254
- "",
255
- "Choose ONE move and emit it as a fenced JSON block:",
256
- ' - {"kind":"refine","tasks":[<task>],"rationale":"..."} \u2014 one more attempt; omit tasks to replay the root task.',
257
- ' - {"kind":"fanout","tasks":[<task>,<task>],"rationale":"..."} \u2014 N parallel branches (or "n": N for N copies of the root task).',
258
- ' - {"kind":"stop","rationale":"..."} \u2014 a valid result exists or further attempts will not help.',
259
- "",
260
- "Stop as soon as an attempt is valid. Prefer refine when an attempt is close; fan out when attempts disagree or the approach is uncertain.",
261
- "Emit ONLY the JSON block."
262
- ].join("\n");
263
- }
264
- var TERMINAL_EVENT_TYPES = /* @__PURE__ */ new Set(["result", "final", "planner.move", "done"]);
265
- function defaultParseEnvelope(events) {
266
- const moveText = (data) => pickString(data.finalText) ?? pickString(data.text) ?? pickString(data.delta) ?? pickString(data.content) ?? pickString(data.message);
267
- for (let i = events.length - 1; i >= 0; i -= 1) {
268
- const event = events[i];
269
- if (!event) continue;
270
- const data = isRecord(event.data) ? event.data : void 0;
271
- if (!data) continue;
272
- if (!TERMINAL_EVENT_TYPES.has(String(event.type ?? ""))) continue;
273
- const structured = coerceEnvelope(data.result ?? data.output ?? data.move ?? data);
274
- if (structured) return structured;
275
- const fromText = coerceEnvelope(extractFencedJson(moveText(data) ?? ""));
276
- if (fromText) return fromText;
277
- }
278
- for (let i = events.length - 1; i >= 0; i -= 1) {
279
- const event = events[i];
280
- if (!event) continue;
281
- const data = isRecord(event.data) ? event.data : void 0;
282
- if (!data) continue;
283
- const text = moveText(data);
284
- if (!text) continue;
285
- const coerced = coerceEnvelope(extractFencedJson(text));
286
- if (coerced) return coerced;
287
- }
288
- return void 0;
289
- }
290
- function coerceEnvelope(value) {
291
- if (!isRecord(value)) return void 0;
292
- if (typeof value.kind !== "string" || value.kind.length === 0) return void 0;
293
- const out = { kind: value.kind };
294
- if (Array.isArray(value.tasks)) out.tasks = value.tasks;
295
- if (typeof value.n === "number") out.n = value.n;
296
- if (typeof value.rationale === "string") out.rationale = value.rationale;
297
- return out;
298
- }
299
- function isRecord(value) {
300
- return value !== null && typeof value === "object" && !Array.isArray(value);
301
- }
302
- function pickString(value) {
303
- return typeof value === "string" && value.length > 0 ? value : void 0;
304
- }
305
- function extractFencedJson(text) {
306
- const match = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
307
- const body = (match?.[1] ?? text).trim();
308
- if (!body) return void 0;
309
- try {
310
- return JSON.parse(body);
311
- } catch {
312
- return void 0;
313
- }
314
- }
315
- function safeJson(value) {
316
- try {
317
- return JSON.stringify(value, null, 2) ?? String(value);
318
- } catch {
319
- return String(value);
320
- }
321
- }
322
-
323
- // src/loops/report-usage.ts
324
- function reportLoopUsage(cost, result, source = "loop") {
325
- cost.observe(result.costUsd, source);
326
- cost.observeTokens({ input: result.tokenUsage.input, output: result.tokenUsage.output });
327
- }
328
-
329
- // src/loops/sandbox-acquire.ts
330
- var RETRYABLE_HTTP = /* @__PURE__ */ new Set([502, 503, 504, 522, 524, 408, 425, 429]);
331
- var TERMINAL_STATUS = /* @__PURE__ */ new Set(["failed", "expired", "stopped"]);
332
- async function acquireSandbox(client, options, acquire = {}) {
333
- if (!client || typeof client.create !== "function") {
334
- throw new ValidationError("acquireSandbox: client.create is required");
335
- }
336
- const now = acquire.now ?? Date.now;
337
- const sleep = acquire.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
338
- const pollMs = acquire.pollIntervalMs ?? 3e3;
339
- const deadline = now() + (acquire.readyTimeoutMs ?? 6e5);
340
- const name = options.name ?? acquire.name ?? `loop-sbx-${randomSuffix()}`;
341
- const createOpts = { ...options, name };
342
- const c = client;
343
- let lastErr;
344
- let attempt = 0;
345
- while (now() < deadline) {
346
- throwIfAborted(acquire.signal);
347
- try {
348
- const box = await client.create(createOpts);
349
- return await waitUntilReady(box, deadline, pollMs, acquire.signal, now, sleep);
350
- } catch (err) {
351
- throwIfAborted(acquire.signal);
352
- if (!isRetryable(err)) throw err;
353
- lastErr = err;
354
- if (typeof c.list === "function") {
355
- const found = (await c.list().catch(() => []))?.find((b) => b.name === name);
356
- if (found) return await waitUntilReady(found, deadline, pollMs, acquire.signal, now, sleep);
357
- }
358
- attempt += 1;
359
- await sleep(Math.min(pollMs * attempt, 15e3));
360
- }
361
- }
362
- throw new ValidationError(
363
- `acquireSandbox: could not acquire a running sandbox "${name}" within budget`,
364
- { cause: lastErr instanceof Error ? lastErr : void 0 }
365
- );
366
- }
367
- async function waitUntilReady(box, deadline, pollMs, signal, now, sleep) {
368
- for (; ; ) {
369
- throwIfAborted(signal);
370
- const status = readStatus(box);
371
- if (status === void 0 || status === "running") return box;
372
- if (TERMINAL_STATUS.has(status)) {
373
- throw new ValidationError(
374
- `acquireSandbox: sandbox ${box.id ?? "(unknown)"} is ${status}${box.error ? `: ${box.error}` : ""}`
375
- );
376
- }
377
- if (now() >= deadline) {
378
- throw new ValidationError(
379
- `acquireSandbox: sandbox ${box.id ?? "(unknown)"} not running within budget (last status: ${status})`
380
- );
381
- }
382
- await sleep(pollMs);
383
- if (typeof box.refresh === "function") await box.refresh();
384
- }
385
- }
386
- function readStatus(box) {
387
- const s = box.status;
388
- return typeof s === "string" ? s : void 0;
389
- }
390
- function isRetryable(err) {
391
- if (!err || typeof err !== "object") return false;
392
- const e = err;
393
- const status = e.status ?? e.statusCode;
394
- if (typeof status === "number" && RETRYABLE_HTTP.has(status)) return true;
395
- const name = e.name ?? "";
396
- if (name === "TimeoutError" || name === "ServerError" || name === "NetworkError") return true;
397
- return /\b(timed out|timeout|gateway|temporarily unavailable|ECONNRESET|ETIMEDOUT|EAI_AGAIN)\b/i.test(
398
- e.message ?? ""
399
- );
400
- }
401
- function throwIfAborted(signal) {
402
- if (signal?.aborted) {
403
- const err = new Error("aborted");
404
- err.name = "AbortError";
405
- throw err;
406
- }
407
- }
408
- function randomSuffix(len = 10) {
409
- return Math.random().toString(36).slice(2, 2 + len);
410
- }
411
-
412
- // src/loops/sandbox-events.ts
413
- function extractLlmCallEvent(event, agentRunName) {
414
- if (!event || typeof event !== "object") return void 0;
415
- const type = String(event.type ?? "");
416
- const data = event.data && typeof event.data === "object" ? event.data : {};
417
- if (type === "llm_call" || type === "cost.usage" || type === "usage") {
418
- return buildLlmCall(data, agentRunName);
419
- }
420
- if (type === "message.completed" || type === "result" || type === "final") {
421
- const usage = data.usage;
422
- if (!usage || typeof usage !== "object") return void 0;
423
- return buildLlmCall({ ...usage, model: data.model ?? usage.model }, agentRunName);
424
- }
425
- if (type === "done") {
426
- const usage = data.tokenUsage;
427
- if (!usage || typeof usage !== "object") return void 0;
428
- const out = pickFiniteNumber(usage, ["outputTokens", "completion_tokens", "tokensOut"]);
429
- const reasoning = pickFiniteNumber(usage, ["reasoningTokens"]);
430
- const mergedOut = out !== void 0 || reasoning !== void 0 ? (out ?? 0) + (reasoning ?? 0) : void 0;
431
- return buildLlmCall(
432
- {
433
- inputTokens: usage.inputTokens,
434
- outputTokens: mergedOut,
435
- totalCostUsd: data.totalCostUsd,
436
- model: data.model ?? usage.model
437
- },
438
- agentRunName
439
- );
440
- }
441
- return void 0;
442
- }
443
- function buildLlmCall(data, agentRunName) {
444
- const tokensIn = pickFiniteNumber(data, ["tokensIn", "inputTokens", "prompt_tokens"]);
445
- const tokensOut = pickFiniteNumber(data, ["tokensOut", "outputTokens", "completion_tokens"]);
446
- const costUsd = pickFiniteNumber(data, ["costUsd", "totalCostUsd", "cost_usd", "cost"]);
447
- if (tokensIn === void 0 && tokensOut === void 0 && costUsd === void 0) {
448
- return void 0;
449
- }
450
- const model = typeof data.model === "string" && data.model.length > 0 ? data.model : agentRunName;
451
- const event = {
452
- type: "llm_call",
453
- model
454
- };
455
- if (tokensIn !== void 0) event.tokensIn = tokensIn;
456
- if (tokensOut !== void 0) event.tokensOut = tokensOut;
457
- if (costUsd !== void 0) event.costUsd = costUsd;
458
- return event;
459
- }
460
- function pickFiniteNumber(data, keys) {
461
- for (const key of keys) {
462
- const value = data[key];
463
- if (typeof value === "number" && Number.isFinite(value)) return value;
464
- }
465
- return void 0;
466
- }
467
- function mapSandboxEvent(event, opts = {}) {
468
- if (!event || typeof event !== "object") return void 0;
469
- const type = String(event.type ?? "");
470
- const data = event.data && typeof event.data === "object" ? event.data : {};
471
- if (type === "message.part.updated") {
472
- const part = data.part && typeof data.part === "object" ? data.part : {};
473
- const partType = String(part.type ?? "");
474
- const delta = typeof data.delta === "string" ? data.delta : void 0;
475
- const text = delta ?? (typeof part.text === "string" ? part.text : void 0);
476
- if (text === void 0) return void 0;
477
- if (partType === "text") return { type: "text_delta", text };
478
- if (partType === "reasoning" || partType === "thinking")
479
- return { type: "reasoning_delta", text };
480
- return void 0;
481
- }
482
- return extractLlmCallEvent(event, opts.agentRunName ?? "agent");
483
- }
484
-
485
- // src/loops/run-loop.ts
486
- var DEFAULT_MAX_ITERATIONS = 10;
487
- var DEFAULT_MAX_CONCURRENCY = 4;
488
- async function runLoop(options) {
489
- const specs = resolveAgentRuns(options);
490
- const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
491
- if (!Number.isFinite(maxIterations) || maxIterations <= 0) {
492
- throw new ValidationError("runLoop: maxIterations must be > 0");
493
- }
494
- const maxConcurrency = options.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY;
495
- if (!Number.isFinite(maxConcurrency) || maxConcurrency <= 0) {
496
- throw new ValidationError("runLoop: maxConcurrency must be > 0");
497
- }
498
- if (!options.ctx?.sandboxClient || typeof options.ctx.sandboxClient.create !== "function") {
499
- throw new ValidationError("runLoop: ctx.sandboxClient.create is required");
500
- }
501
- const now = options.now ?? Date.now;
502
- const runId = options.runId ?? `loop-${randomSuffix2()}`;
503
- const loopStart = now();
504
- const driverName = options.driver.name ?? "driver";
505
- const iterations = [];
506
- let round = 0;
507
- const ownedBoxes = [];
508
- const collectBox = options.shareWorkerBox ? (box) => {
509
- ownedBoxes.push(box);
510
- options.shareWorkerBox?.(box);
511
- } : void 0;
512
- await emitTrace(options.ctx.traceEmitter, {
513
- kind: "loop.started",
514
- runId,
515
- timestamp: now(),
516
- payload: {
517
- driver: driverName,
518
- agentRunNames: specs.map((spec) => spec.name ?? spec.profile.name ?? "agent"),
519
- maxIterations,
520
- maxConcurrency
521
- }
522
- });
523
- const controller = new AbortController();
524
- const onOuterAbort = () => controller.abort();
525
- if (options.ctx.signal) {
526
- if (options.ctx.signal.aborted) controller.abort();
527
- else options.ctx.signal.addEventListener("abort", onOuterAbort, { once: true });
528
- }
529
- try {
530
- while (iterations.length < maxIterations) {
531
- if (controller.signal.aborted) throwAbort();
532
- const planned = await options.driver.plan(options.task, iterations);
533
- const planDesc = options.driver.describePlan?.();
534
- const roundIndex = round;
535
- const baseIndex = iterations.length;
536
- const remaining = maxIterations - iterations.length;
537
- const slice = planned.slice(0, remaining);
538
- const parentIndex = planDesc?.parentIndex ?? (roundIndex === 0 ? void 0 : branchPoint(iterations));
539
- const childIndices = slice.map((_, i) => baseIndex + i);
540
- await emitTrace(options.ctx.traceEmitter, {
541
- kind: "loop.plan",
542
- runId,
543
- timestamp: now(),
544
- payload: {
545
- roundIndex,
546
- plannedCount: planned.length,
547
- moveKind: planDesc?.kind ?? (planned.length === 0 ? "stop" : planned.length === 1 ? "refine" : "fanout"),
548
- rationale: planDesc?.rationale,
549
- parentIndex,
550
- childIndices
551
- }
552
- });
553
- round += 1;
554
- if (planned.length === 0) break;
555
- for (let i = 0; i < slice.length; i += 1) {
556
- const spec = specs[(baseIndex + i) % specs.length];
557
- iterations.push({
558
- index: baseIndex + i,
559
- task: slice[i],
560
- agentRunName: spec.name ?? spec.profile.name ?? "agent",
561
- events: [],
562
- startedAt: now(),
563
- endedAt: 0,
564
- costUsd: 0,
565
- tokenUsage: { input: 0, output: 0 }
566
- });
567
- }
568
- await runBatch({
569
- slice,
570
- baseIndex,
571
- iterations,
572
- specs,
573
- output: options.output,
574
- validator: options.validator,
575
- maxConcurrency,
576
- signal: controller.signal,
577
- ctx: options.ctx,
578
- runId,
579
- now,
580
- roundIndex,
581
- parentIndex,
582
- collectBox
583
- });
584
- if (controller.signal.aborted) throwAbort();
585
- const decision2 = await options.driver.decide(iterations);
586
- await emitTrace(options.ctx.traceEmitter, {
587
- kind: "loop.decision",
588
- runId,
589
- timestamp: now(),
590
- payload: { decision: serializeDecision(decision2), historyLength: iterations.length }
591
- });
592
- if (isTerminalDecision(decision2)) {
593
- return finalize({
594
- options,
595
- decision: decision2,
596
- iterations,
597
- startMs: loopStart,
598
- now,
599
- runId
600
- });
601
- }
602
- }
603
- if (iterations.length >= maxIterations) {
604
- const decision2 = await options.driver.decide(iterations);
605
- await emitTrace(options.ctx.traceEmitter, {
606
- kind: "loop.decision",
607
- runId,
608
- timestamp: now(),
609
- payload: { decision: serializeDecision(decision2), historyLength: iterations.length }
610
- });
611
- return finalize({ options, decision: decision2, iterations, startMs: loopStart, now, runId });
612
- }
613
- const decision = await options.driver.decide(iterations);
614
- await emitTrace(options.ctx.traceEmitter, {
615
- kind: "loop.decision",
616
- runId,
617
- timestamp: now(),
618
- payload: { decision: serializeDecision(decision), historyLength: iterations.length }
619
- });
620
- return finalize({ options, decision, iterations, startMs: loopStart, now, runId });
621
- } finally {
622
- if (options.ctx.signal) options.ctx.signal.removeEventListener("abort", onOuterAbort);
623
- for (const b of ownedBoxes) await destroySandboxSafe(b);
624
- if (options.shareWorkerBox) options.shareWorkerBox(void 0);
625
- }
626
- }
627
- async function runBatch(args) {
628
- const queue = args.slice.map((task, offset) => ({ task, index: args.baseIndex + offset }));
629
- const inflight = /* @__PURE__ */ new Set();
630
- while (queue.length > 0 || inflight.size > 0) {
631
- while (inflight.size < args.maxConcurrency && queue.length > 0) {
632
- const item = queue.shift();
633
- const p = executeIteration({ ...args, item }).finally(() => inflight.delete(p));
634
- inflight.add(p);
635
- }
636
- if (inflight.size === 0) break;
637
- await Promise.race(inflight);
638
- }
639
- }
640
- async function executeIteration(args) {
641
- const slot = args.iterations[args.item.index];
642
- if (!slot)
643
- throw new ValidationError(`runLoop: missing iteration slot at index ${args.item.index}`);
644
- const spec = args.specs[args.item.index % args.specs.length];
645
- if (!spec) throw new ValidationError("runLoop: no AgentRunSpec available for iteration");
646
- slot.startedAt = args.now();
647
- slot.agentRunName = spec.name ?? spec.profile.name ?? "agent";
648
- await emitTrace(args.ctx.traceEmitter, {
649
- kind: "loop.iteration.started",
650
- runId: args.runId,
651
- timestamp: args.now(),
652
- payload: {
653
- iterationIndex: args.item.index,
654
- agentRunName: slot.agentRunName,
655
- taskHash: hashJson(args.item.task),
656
- groupId: args.roundIndex,
657
- parentIndex: args.parentIndex
658
- }
659
- });
660
- let box;
661
- try {
662
- box = await createSandboxForSpec(args.ctx.sandboxClient, spec, args.signal);
663
- const placement = describeSandboxPlacement(args.ctx.sandboxClient, box);
664
- await emitTrace(args.ctx.traceEmitter, {
665
- kind: "loop.iteration.dispatch",
666
- runId: args.runId,
667
- timestamp: args.now(),
668
- payload: {
669
- iterationIndex: args.item.index,
670
- agentRunName: slot.agentRunName,
671
- placement: placement.kind,
672
- sandboxId: placement.sandboxId,
673
- fleetId: placement.fleetId,
674
- machineId: placement.machineId,
675
- groupId: args.roundIndex,
676
- parentIndex: args.parentIndex
677
- }
678
- });
679
- const message = spec.taskToPrompt(args.item.task);
680
- const events = [];
681
- for await (const event of box.streamPrompt(message, { signal: args.signal })) {
682
- events.push(event);
683
- const llmCall = extractLlmCallEvent(event, slot.agentRunName);
684
- if (llmCall) {
685
- slot.costUsd += llmCall.costUsd ?? 0;
686
- slot.tokenUsage.input += llmCall.tokensIn ?? 0;
687
- slot.tokenUsage.output += llmCall.tokensOut ?? 0;
688
- args.ctx.runHandle?.observe(llmCall);
689
- }
690
- }
691
- slot.events = events;
692
- slot.output = args.output.parse(events);
693
- if (args.validator) {
694
- slot.verdict = await args.validator.validate(slot.output, {
695
- iteration: args.item.index,
696
- signal: args.signal,
697
- traceEmitter: args.ctx.traceEmitter
698
- });
699
- }
700
- } catch (err) {
701
- slot.error = err instanceof Error ? err : new Error(String(err));
702
- } finally {
703
- slot.endedAt = args.now();
704
- await emitTrace(args.ctx.traceEmitter, {
705
- kind: "loop.iteration.ended",
706
- runId: args.runId,
707
- timestamp: args.now(),
708
- payload: {
709
- iterationIndex: args.item.index,
710
- agentRunName: slot.agentRunName,
711
- outputHash: slot.output !== void 0 ? hashJson(slot.output) : void 0,
712
- verdict: slot.verdict,
713
- error: slot.error?.message,
714
- costUsd: slot.costUsd,
715
- durationMs: slot.endedAt - slot.startedAt,
716
- tokenUsage: slot.tokenUsage.input || slot.tokenUsage.output ? { ...slot.tokenUsage } : void 0,
717
- groupId: args.roundIndex,
718
- parentIndex: args.parentIndex,
719
- outputPreview: slot.output !== void 0 ? previewOutput(slot.output) : void 0
720
- }
721
- });
722
- if (args.collectBox && box) args.collectBox(box);
723
- else await destroySandboxSafe(box);
724
- }
725
- }
726
- async function destroySandboxSafe(box) {
727
- if (!box || typeof box.delete !== "function") return;
728
- try {
729
- await box.delete();
730
- } catch {
731
- }
732
- }
733
- function branchPoint(iterations) {
734
- if (iterations.length === 0) return void 0;
735
- let best = iterations.length - 1;
736
- let bestScore = -Infinity;
737
- for (const iter of iterations) {
738
- if (iter.verdict?.valid !== true) continue;
739
- const score = iter.verdict.score ?? 0;
740
- if (score > bestScore) {
741
- bestScore = score;
742
- best = iter.index;
743
- }
744
- }
745
- return best;
746
- }
747
- function previewOutput(output) {
748
- let s;
749
- try {
750
- s = typeof output === "string" ? output : JSON.stringify(output) ?? String(output);
751
- } catch {
752
- s = String(output);
753
- }
754
- return s.length > 280 ? `${s.slice(0, 280)}\u2026` : s;
755
- }
756
- function describeSandboxPlacement(client, box) {
757
- if (typeof client.describePlacement === "function") {
758
- try {
759
- const result = client.describePlacement(box);
760
- if (result && typeof result === "object" && (result.kind === "sibling" || result.kind === "fleet")) {
761
- return {
762
- kind: result.kind,
763
- sandboxId: result.sandboxId ?? readSandboxId(box),
764
- fleetId: result.fleetId,
765
- machineId: result.machineId
766
- };
767
- }
768
- } catch {
769
- }
770
- }
771
- return { kind: "sibling", sandboxId: readSandboxId(box) };
772
- }
773
- function readSandboxId(box) {
774
- const raw = box.id;
775
- return typeof raw === "string" && raw.length > 0 ? raw : void 0;
776
- }
777
- async function createSandboxForSpec(client, spec, signal) {
778
- const overrides = spec.sandboxOverrides ?? {};
779
- const overrideBackend = overrides.backend;
780
- const opts = {
781
- ...overrides,
782
- backend: {
783
- type: overrideBackend?.type ?? inferBackendType(spec.profile),
784
- profile: spec.profile,
785
- ...overrideBackend?.model ? { model: overrideBackend.model } : {},
786
- ...overrideBackend?.server ? { server: overrideBackend.server } : {}
787
- }
788
- };
789
- if (signal.aborted) throwAbort();
790
- return acquireSandbox(client, opts, { signal });
791
- }
792
- function inferBackendType(profile) {
793
- const explicit = profile.metadata?.backendType;
794
- if (typeof explicit === "string") return explicit;
795
- return "opencode";
796
- }
797
- function finalize(args) {
798
- const winner = (args.options.selectWinner ?? defaultSelectWinner)(args.iterations);
799
- const costUsd = args.iterations.reduce((sum, iter) => sum + (iter.costUsd || 0), 0);
800
- const tokenUsage = args.iterations.reduce(
801
- (acc, iter) => {
802
- acc.input += iter.tokenUsage?.input ?? 0;
803
- acc.output += iter.tokenUsage?.output ?? 0;
804
- return acc;
805
- },
806
- { input: 0, output: 0 }
807
- );
808
- const result = {
809
- decision: args.decision,
810
- iterations: args.iterations,
811
- winner,
812
- durationMs: args.now() - args.startMs,
813
- costUsd,
814
- tokenUsage
815
- };
816
- void emitTrace(args.options.ctx.traceEmitter, {
817
- kind: "loop.ended",
818
- runId: args.runId,
819
- timestamp: args.now(),
820
- payload: {
821
- winnerIterationIndex: winner?.iterationIndex,
822
- totalCostUsd: costUsd,
823
- durationMs: result.durationMs,
824
- iterations: args.iterations.length
825
- }
826
- });
827
- return result;
828
- }
829
- function defaultSelectWinner(iterations) {
830
- const candidates = iterations.filter((iter) => iter.output !== void 0 && !iter.error);
831
- if (candidates.length === 0) return void 0;
832
- const valid = candidates.filter((iter) => iter.verdict?.valid === true);
833
- const pool = valid.length > 0 ? valid : candidates;
834
- const sorted = [...pool].sort(
835
- (a, b) => (b.verdict?.score ?? 0) - (a.verdict?.score ?? 0) || a.index - b.index
836
- );
837
- const top = sorted[0];
838
- if (!top || top.output === void 0) return void 0;
839
- return {
840
- task: top.task,
841
- output: top.output,
842
- verdict: top.verdict,
843
- iterationIndex: top.index,
844
- agentRunName: top.agentRunName
845
- };
846
- }
847
- function resolveAgentRuns(options) {
848
- if (options.agentRun && options.agentRuns) {
849
- throw new ValidationError("runLoop: pass exactly one of `agentRun` or `agentRuns`");
850
- }
851
- if (options.agentRun) return [options.agentRun];
852
- if (options.agentRuns && options.agentRuns.length > 0) return options.agentRuns;
853
- throw new ValidationError("runLoop: `agentRun` or non-empty `agentRuns` is required");
854
- }
855
- function isTerminalDecision(decision) {
856
- return decision === "stop" || decision === "pick-winner" || decision === "fail" || decision === "done";
857
- }
858
- function serializeDecision(decision) {
859
- if (typeof decision === "string") return decision;
860
- if (decision === null || decision === void 0) return "null";
861
- try {
862
- return JSON.stringify(decision);
863
- } catch {
864
- return String(decision);
865
- }
866
- }
867
- async function emitTrace(emitter, event) {
868
- if (!emitter) return;
869
- await emitter.emit(event);
870
- }
871
- function randomSuffix2(len = 8) {
872
- return Math.random().toString(36).slice(2, 2 + len);
873
- }
874
- function throwAbort() {
875
- const err = new Error("aborted");
876
- err.name = "AbortError";
877
- throw err;
878
- }
879
- function hashJson(value) {
880
- let str;
881
- try {
882
- str = JSON.stringify(value) ?? String(value);
883
- } catch {
884
- str = String(value);
885
- }
886
- let h = 2166136261;
887
- for (let i = 0; i < str.length; i += 1) {
888
- h ^= str.charCodeAt(i);
889
- h = Math.imul(h, 16777619);
890
- }
891
- return (h >>> 0).toString(16).padStart(8, "0");
892
- }
893
-
894
- // src/loops/loop-dispatch.ts
895
- function campaignTraceToLoopEmitter(trace) {
896
- return {
897
- emit(event) {
898
- trace.span(event.kind, { runId: event.runId, timestamp: event.timestamp, ...event.payload }).end();
899
- }
900
- };
901
- }
902
- async function runLoopForCell(opts, scenario, profile, ctx) {
903
- const loopOptions = opts.toLoopOptions(scenario, profile);
904
- const result = await runLoop({
905
- ...loopOptions,
906
- ctx: {
907
- sandboxClient: opts.sandboxClient,
908
- signal: ctx.signal,
909
- traceEmitter: opts.forwardTrace === false ? void 0 : campaignTraceToLoopEmitter(ctx.trace)
910
- }
911
- });
912
- reportLoopUsage(ctx.cost, result, opts.costSource ?? "loop");
913
- const toArtifact = opts.toArtifact ?? ((r) => r.winner?.output);
914
- return toArtifact(result);
915
- }
916
- function loopDispatch(opts) {
917
- return (profile, scenario, ctx) => runLoopForCell(opts, scenario, profile, ctx);
918
- }
919
- function loopCampaignDispatch(opts) {
920
- const profileSentinel = { id: "loop-campaign", model: "n/a@loop-campaign" };
921
- const profiled = {
922
- ...opts,
923
- toLoopOptions: (scenario) => opts.toLoopOptions(scenario)
924
- };
925
- return (scenario, ctx) => runLoopForCell(profiled, scenario, profileSentinel, ctx);
926
- }
927
-
928
- export {
929
- createDynamicDriver,
930
- summarizeHistory,
931
- blind,
932
- PROMPT_PLANNERS,
933
- resolvePlanner,
934
- createRefineDriver,
935
- refineWinnerIndex,
936
- createSandboxPlanner,
937
- reportLoopUsage,
938
- acquireSandbox,
939
- extractLlmCallEvent,
940
- mapSandboxEvent,
941
- runLoop,
942
- describeSandboxPlacement,
943
- createSandboxForSpec,
944
- loopDispatch,
945
- loopCampaignDispatch
946
- };
947
- //# sourceMappingURL=chunk-S7JXV32P.js.map