@tangle-network/agent-runtime 0.43.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 +96 -202
  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-MJDGCRAT.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-C5HMTTNY.js → chunk-NYN5RTLP.js} +13 -12
  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-MNCB4SJ5.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 +407 -19
  39. package/dist/index.js.map +1 -1
  40. package/dist/{kb-gate-DTBum3vH.d.ts → kb-gate-D9GBocLN.d.ts} +82 -5
  41. package/dist/{loop-runner-bin-CVoCBmYk.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 -371
  45. package/dist/loops.js +96 -19
  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-BzvF1Ela.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--hSoIknW.d.ts +112 -0
  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-Bcp071Jg.d.ts → types-DdzkffAm.d.ts} +95 -1
  67. package/dist/workflow.d.ts +551 -0
  68. package/dist/workflow.js +1778 -0
  69. package/dist/workflow.js.map +1 -0
  70. package/package.json +53 -16
  71. package/skills/agent-runtime-adoption/SKILL.md +29 -26
  72. package/dist/chunk-3HMHSN22.js.map +0 -1
  73. package/dist/chunk-C5HMTTNY.js.map +0 -1
  74. package/dist/chunk-EKBSQYZE.js +0 -813
  75. package/dist/chunk-EKBSQYZE.js.map +0 -1
  76. package/dist/chunk-HVYOHJHK.js.map +0 -1
  77. package/dist/chunk-MJDGCRAT.js.map +0 -1
  78. package/dist/chunk-MNCB4SJ5.js.map +0 -1
  79. package/dist/chunk-PY6NMZYX.js +0 -52
  80. package/dist/chunk-PY6NMZYX.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-B_7GgCwu.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,813 +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/refine.ts
108
- function createRefineDriver(options = {}) {
109
- const maxIterations = options.maxIterations ?? 5;
110
- if (!Number.isFinite(maxIterations) || maxIterations <= 0) {
111
- throw new ValidationError("createRefineDriver: maxIterations must be > 0");
112
- }
113
- const refineTask = options.refineTask;
114
- return {
115
- name: options.name ?? "refine",
116
- async plan(task, history) {
117
- if (history.length >= maxIterations) return [];
118
- if (history.length === 0) return [task];
119
- const prior = history.at(-1);
120
- if (!prior) return [task];
121
- if (prior.verdict?.valid === true) return [];
122
- if (!refineTask || !prior.verdict) return [prior.task];
123
- return [refineTask(prior.task, prior.verdict)];
124
- },
125
- decide(history) {
126
- const last = history.at(-1);
127
- if (!last) return "continue";
128
- if (last.verdict?.valid === true) return "stop";
129
- if (history.length >= maxIterations) return "stop";
130
- return "continue";
131
- }
132
- };
133
- }
134
- function refineWinnerIndex(iterations) {
135
- for (let i = iterations.length - 1; i >= 0; i -= 1) {
136
- if (iterations[i]?.verdict?.valid) return i;
137
- }
138
- return iterations.length > 0 ? iterations.length - 1 : void 0;
139
- }
140
-
141
- // src/loops/drivers/sandbox-planner.ts
142
- function createSandboxPlanner(opts) {
143
- if (!opts.client || typeof opts.client.create !== "function") {
144
- throw new ValidationError("createSandboxPlanner: client.create is required");
145
- }
146
- if (typeof opts.decodeTask !== "function") {
147
- throw new ValidationError("createSandboxPlanner: decodeTask is required");
148
- }
149
- const buildPrompt = opts.buildPrompt ?? defaultBuildPrompt;
150
- const parseEnvelope = opts.parseEnvelope ?? defaultParseEnvelope;
151
- return async (ctx) => {
152
- const box = await opts.client.create(buildSandboxOptions(opts.profile, opts.sandboxOverrides));
153
- const events = [];
154
- for await (const event of box.streamPrompt(buildPrompt(ctx), { signal: opts.signal })) {
155
- events.push(event);
156
- }
157
- const envelope = parseEnvelope(events);
158
- if (!envelope) {
159
- throw new PlannerError("sandbox planner emitted no parseable topology-move envelope");
160
- }
161
- return envelopeToMove(envelope, ctx, opts.decodeTask);
162
- };
163
- }
164
- function envelopeToMove(envelope, ctx, decodeTask) {
165
- const kind = String(envelope.kind ?? "").toLowerCase();
166
- const rationale = typeof envelope.rationale === "string" ? envelope.rationale : void 0;
167
- if (kind === "stop") {
168
- return { kind: "stop", rationale };
169
- }
170
- if (kind === "refine") {
171
- const raw = Array.isArray(envelope.tasks) ? envelope.tasks[0] : void 0;
172
- const task = raw === void 0 ? ctx.task : decodeTaskGuarded(decodeTask, raw, ctx);
173
- return { kind: "refine", task, rationale };
174
- }
175
- if (kind === "fanout") {
176
- const tasks = resolveFanoutTasks(envelope, ctx, decodeTask);
177
- return { kind: "fanout", tasks, rationale };
178
- }
179
- throw new PlannerError(
180
- `sandbox planner emitted unknown move kind: ${JSON.stringify(envelope.kind)}`
181
- );
182
- }
183
- function resolveFanoutTasks(envelope, ctx, decodeTask) {
184
- if (Array.isArray(envelope.tasks) && envelope.tasks.length > 0) {
185
- return envelope.tasks.map((raw) => decodeTaskGuarded(decodeTask, raw, ctx));
186
- }
187
- if (typeof envelope.n === "number" && Number.isFinite(envelope.n) && envelope.n >= 1) {
188
- return Array.from({ length: Math.floor(envelope.n) }, () => ctx.task);
189
- }
190
- throw new PlannerError("sandbox planner fanout envelope needs a non-empty tasks[] or n >= 1");
191
- }
192
- function decodeTaskGuarded(decodeTask, raw, ctx) {
193
- try {
194
- return decodeTask(raw, ctx);
195
- } catch (err) {
196
- throw new PlannerError(`sandbox planner decodeTask rejected ${JSON.stringify(raw)}`, {
197
- cause: err
198
- });
199
- }
200
- }
201
- function buildSandboxOptions(profile, overrides) {
202
- const base = overrides ?? {};
203
- const overrideBackend = base.backend;
204
- const explicitType = profile.metadata?.backendType;
205
- return {
206
- ...base,
207
- backend: {
208
- type: overrideBackend?.type ?? explicitType ?? "opencode",
209
- profile,
210
- ...overrideBackend?.model ? { model: overrideBackend.model } : {},
211
- ...overrideBackend?.server ? { server: overrideBackend.server } : {}
212
- }
213
- };
214
- }
215
- function defaultBuildPrompt(ctx) {
216
- const summary = summarizeHistory(ctx.history);
217
- return [
218
- "You are the loop planner. You do not do the work \u2014 you decide the topology of the next round.",
219
- "",
220
- `Root task:
221
- ${safeJson(ctx.task)}`,
222
- "",
223
- `Iterations spent: ${ctx.iterationsSpent}. Remaining before the hard cap: ${ctx.iterationsRemaining}.`,
224
- "",
225
- ctx.history.length === 0 ? "No attempts yet." : `Attempts so far (index, agent, verdict, output):
226
- ${safeJson(summary)}`,
227
- "",
228
- "Choose ONE move and emit it as a fenced JSON block:",
229
- ' - {"kind":"refine","tasks":[<task>],"rationale":"..."} \u2014 one more attempt; omit tasks to replay the root task.',
230
- ' - {"kind":"fanout","tasks":[<task>,<task>],"rationale":"..."} \u2014 N parallel branches (or "n": N for N copies of the root task).',
231
- ' - {"kind":"stop","rationale":"..."} \u2014 a valid result exists or further attempts will not help.',
232
- "",
233
- "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.",
234
- "Emit ONLY the JSON block."
235
- ].join("\n");
236
- }
237
- function defaultParseEnvelope(events) {
238
- for (let i = events.length - 1; i >= 0; i -= 1) {
239
- const event = events[i];
240
- if (!event) continue;
241
- const type = String(event.type ?? "");
242
- const data = isRecord(event.data) ? event.data : void 0;
243
- if (!data) continue;
244
- if (type === "result" || type === "final" || type === "planner.move") {
245
- const direct = coerceEnvelope(data.result ?? data.output ?? data);
246
- if (direct) return direct;
247
- }
248
- }
249
- for (let i = events.length - 1; i >= 0; i -= 1) {
250
- const event = events[i];
251
- if (!event) continue;
252
- const data = isRecord(event.data) ? event.data : void 0;
253
- if (!data) continue;
254
- const text = pickString(data.text) ?? pickString(data.delta) ?? pickString(data.content);
255
- if (!text) continue;
256
- const fenced = extractFencedJson(text);
257
- const coerced = coerceEnvelope(fenced);
258
- if (coerced) return coerced;
259
- }
260
- return void 0;
261
- }
262
- function coerceEnvelope(value) {
263
- if (!isRecord(value)) return void 0;
264
- if (typeof value.kind !== "string" || value.kind.length === 0) return void 0;
265
- const out = { kind: value.kind };
266
- if (Array.isArray(value.tasks)) out.tasks = value.tasks;
267
- if (typeof value.n === "number") out.n = value.n;
268
- if (typeof value.rationale === "string") out.rationale = value.rationale;
269
- return out;
270
- }
271
- function isRecord(value) {
272
- return value !== null && typeof value === "object" && !Array.isArray(value);
273
- }
274
- function pickString(value) {
275
- return typeof value === "string" && value.length > 0 ? value : void 0;
276
- }
277
- function extractFencedJson(text) {
278
- const match = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
279
- const body = (match?.[1] ?? text).trim();
280
- if (!body) return void 0;
281
- try {
282
- return JSON.parse(body);
283
- } catch {
284
- return void 0;
285
- }
286
- }
287
- function safeJson(value) {
288
- try {
289
- return JSON.stringify(value, null, 2) ?? String(value);
290
- } catch {
291
- return String(value);
292
- }
293
- }
294
-
295
- // src/loops/report-usage.ts
296
- function reportLoopUsage(cost, result, source = "loop") {
297
- cost.observe(result.costUsd, source);
298
- cost.observeTokens({ input: result.tokenUsage.input, output: result.tokenUsage.output });
299
- }
300
-
301
- // src/loops/sandbox-events.ts
302
- function extractLlmCallEvent(event, agentRunName) {
303
- if (!event || typeof event !== "object") return void 0;
304
- const type = String(event.type ?? "");
305
- const data = event.data && typeof event.data === "object" ? event.data : {};
306
- if (type === "llm_call" || type === "cost.usage" || type === "usage") {
307
- return buildLlmCall(data, agentRunName);
308
- }
309
- if (type === "message.completed" || type === "result" || type === "final") {
310
- const usage = data.usage;
311
- if (!usage || typeof usage !== "object") return void 0;
312
- return buildLlmCall({ ...usage, model: data.model ?? usage.model }, agentRunName);
313
- }
314
- if (type === "done") {
315
- const usage = data.tokenUsage;
316
- if (!usage || typeof usage !== "object") return void 0;
317
- const out = pickFiniteNumber(usage, ["outputTokens", "completion_tokens", "tokensOut"]);
318
- const reasoning = pickFiniteNumber(usage, ["reasoningTokens"]);
319
- const mergedOut = out !== void 0 || reasoning !== void 0 ? (out ?? 0) + (reasoning ?? 0) : void 0;
320
- return buildLlmCall(
321
- {
322
- inputTokens: usage.inputTokens,
323
- outputTokens: mergedOut,
324
- totalCostUsd: data.totalCostUsd,
325
- model: data.model ?? usage.model
326
- },
327
- agentRunName
328
- );
329
- }
330
- return void 0;
331
- }
332
- function buildLlmCall(data, agentRunName) {
333
- const tokensIn = pickFiniteNumber(data, ["tokensIn", "inputTokens", "prompt_tokens"]);
334
- const tokensOut = pickFiniteNumber(data, ["tokensOut", "outputTokens", "completion_tokens"]);
335
- const costUsd = pickFiniteNumber(data, ["costUsd", "totalCostUsd", "cost_usd", "cost"]);
336
- if (tokensIn === void 0 && tokensOut === void 0 && costUsd === void 0) {
337
- return void 0;
338
- }
339
- const model = typeof data.model === "string" && data.model.length > 0 ? data.model : agentRunName;
340
- const event = {
341
- type: "llm_call",
342
- model
343
- };
344
- if (tokensIn !== void 0) event.tokensIn = tokensIn;
345
- if (tokensOut !== void 0) event.tokensOut = tokensOut;
346
- if (costUsd !== void 0) event.costUsd = costUsd;
347
- return event;
348
- }
349
- function pickFiniteNumber(data, keys) {
350
- for (const key of keys) {
351
- const value = data[key];
352
- if (typeof value === "number" && Number.isFinite(value)) return value;
353
- }
354
- return void 0;
355
- }
356
- function mapSandboxEvent(event, opts = {}) {
357
- if (!event || typeof event !== "object") return void 0;
358
- const type = String(event.type ?? "");
359
- const data = event.data && typeof event.data === "object" ? event.data : {};
360
- if (type === "message.part.updated") {
361
- const part = data.part && typeof data.part === "object" ? data.part : {};
362
- const partType = String(part.type ?? "");
363
- const delta = typeof data.delta === "string" ? data.delta : void 0;
364
- const text = delta ?? (typeof part.text === "string" ? part.text : void 0);
365
- if (text === void 0) return void 0;
366
- if (partType === "text") return { type: "text_delta", text };
367
- if (partType === "reasoning" || partType === "thinking")
368
- return { type: "reasoning_delta", text };
369
- return void 0;
370
- }
371
- return extractLlmCallEvent(event, opts.agentRunName ?? "agent");
372
- }
373
-
374
- // src/loops/run-loop.ts
375
- var DEFAULT_MAX_ITERATIONS = 10;
376
- var DEFAULT_MAX_CONCURRENCY = 4;
377
- async function runLoop(options) {
378
- const specs = resolveAgentRuns(options);
379
- const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
380
- if (!Number.isFinite(maxIterations) || maxIterations <= 0) {
381
- throw new ValidationError("runLoop: maxIterations must be > 0");
382
- }
383
- const maxConcurrency = options.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY;
384
- if (!Number.isFinite(maxConcurrency) || maxConcurrency <= 0) {
385
- throw new ValidationError("runLoop: maxConcurrency must be > 0");
386
- }
387
- if (!options.ctx?.sandboxClient || typeof options.ctx.sandboxClient.create !== "function") {
388
- throw new ValidationError("runLoop: ctx.sandboxClient.create is required");
389
- }
390
- const now = options.now ?? Date.now;
391
- const runId = options.runId ?? `loop-${randomSuffix()}`;
392
- const loopStart = now();
393
- const driverName = options.driver.name ?? "driver";
394
- const iterations = [];
395
- let round = 0;
396
- await emitTrace(options.ctx.traceEmitter, {
397
- kind: "loop.started",
398
- runId,
399
- timestamp: now(),
400
- payload: {
401
- driver: driverName,
402
- agentRunNames: specs.map((spec) => spec.name ?? spec.profile.name ?? "agent"),
403
- maxIterations,
404
- maxConcurrency
405
- }
406
- });
407
- const controller = new AbortController();
408
- const onOuterAbort = () => controller.abort();
409
- if (options.ctx.signal) {
410
- if (options.ctx.signal.aborted) controller.abort();
411
- else options.ctx.signal.addEventListener("abort", onOuterAbort, { once: true });
412
- }
413
- try {
414
- while (iterations.length < maxIterations) {
415
- if (controller.signal.aborted) throwAbort();
416
- const planned = await options.driver.plan(options.task, iterations);
417
- const planDesc = options.driver.describePlan?.();
418
- const roundIndex = round;
419
- const baseIndex = iterations.length;
420
- const remaining = maxIterations - iterations.length;
421
- const slice = planned.slice(0, remaining);
422
- const parentIndex = planDesc?.parentIndex ?? (roundIndex === 0 ? void 0 : branchPoint(iterations));
423
- const childIndices = slice.map((_, i) => baseIndex + i);
424
- await emitTrace(options.ctx.traceEmitter, {
425
- kind: "loop.plan",
426
- runId,
427
- timestamp: now(),
428
- payload: {
429
- roundIndex,
430
- plannedCount: planned.length,
431
- moveKind: planDesc?.kind ?? (planned.length === 0 ? "stop" : planned.length === 1 ? "refine" : "fanout"),
432
- rationale: planDesc?.rationale,
433
- parentIndex,
434
- childIndices
435
- }
436
- });
437
- round += 1;
438
- if (planned.length === 0) break;
439
- for (let i = 0; i < slice.length; i += 1) {
440
- const spec = specs[(baseIndex + i) % specs.length];
441
- iterations.push({
442
- index: baseIndex + i,
443
- task: slice[i],
444
- agentRunName: spec.name ?? spec.profile.name ?? "agent",
445
- events: [],
446
- startedAt: now(),
447
- endedAt: 0,
448
- costUsd: 0,
449
- tokenUsage: { input: 0, output: 0 }
450
- });
451
- }
452
- await runBatch({
453
- slice,
454
- baseIndex,
455
- iterations,
456
- specs,
457
- output: options.output,
458
- validator: options.validator,
459
- maxConcurrency,
460
- signal: controller.signal,
461
- ctx: options.ctx,
462
- runId,
463
- now,
464
- roundIndex,
465
- parentIndex
466
- });
467
- if (controller.signal.aborted) throwAbort();
468
- const decision2 = await options.driver.decide(iterations);
469
- await emitTrace(options.ctx.traceEmitter, {
470
- kind: "loop.decision",
471
- runId,
472
- timestamp: now(),
473
- payload: { decision: serializeDecision(decision2), historyLength: iterations.length }
474
- });
475
- if (isTerminalDecision(decision2)) {
476
- return finalize({
477
- options,
478
- decision: decision2,
479
- iterations,
480
- startMs: loopStart,
481
- now,
482
- runId
483
- });
484
- }
485
- }
486
- if (iterations.length >= maxIterations) {
487
- const decision2 = await options.driver.decide(iterations);
488
- await emitTrace(options.ctx.traceEmitter, {
489
- kind: "loop.decision",
490
- runId,
491
- timestamp: now(),
492
- payload: { decision: serializeDecision(decision2), historyLength: iterations.length }
493
- });
494
- return finalize({ options, decision: decision2, iterations, startMs: loopStart, now, runId });
495
- }
496
- const decision = await options.driver.decide(iterations);
497
- await emitTrace(options.ctx.traceEmitter, {
498
- kind: "loop.decision",
499
- runId,
500
- timestamp: now(),
501
- payload: { decision: serializeDecision(decision), historyLength: iterations.length }
502
- });
503
- return finalize({ options, decision, iterations, startMs: loopStart, now, runId });
504
- } finally {
505
- if (options.ctx.signal) options.ctx.signal.removeEventListener("abort", onOuterAbort);
506
- }
507
- }
508
- async function runBatch(args) {
509
- const queue = args.slice.map((task, offset) => ({ task, index: args.baseIndex + offset }));
510
- const inflight = /* @__PURE__ */ new Set();
511
- while (queue.length > 0 || inflight.size > 0) {
512
- while (inflight.size < args.maxConcurrency && queue.length > 0) {
513
- const item = queue.shift();
514
- const p = executeIteration({ ...args, item }).finally(() => inflight.delete(p));
515
- inflight.add(p);
516
- }
517
- if (inflight.size === 0) break;
518
- await Promise.race(inflight);
519
- }
520
- }
521
- async function executeIteration(args) {
522
- const slot = args.iterations[args.item.index];
523
- if (!slot)
524
- throw new ValidationError(`runLoop: missing iteration slot at index ${args.item.index}`);
525
- const spec = args.specs[args.item.index % args.specs.length];
526
- if (!spec) throw new ValidationError("runLoop: no AgentRunSpec available for iteration");
527
- slot.startedAt = args.now();
528
- slot.agentRunName = spec.name ?? spec.profile.name ?? "agent";
529
- await emitTrace(args.ctx.traceEmitter, {
530
- kind: "loop.iteration.started",
531
- runId: args.runId,
532
- timestamp: args.now(),
533
- payload: {
534
- iterationIndex: args.item.index,
535
- agentRunName: slot.agentRunName,
536
- taskHash: hashJson(args.item.task),
537
- groupId: args.roundIndex,
538
- parentIndex: args.parentIndex
539
- }
540
- });
541
- try {
542
- const box = await createSandboxForSpec(args.ctx.sandboxClient, spec, args.signal);
543
- const placement = describePlacementSafe(args.ctx.sandboxClient, box);
544
- await emitTrace(args.ctx.traceEmitter, {
545
- kind: "loop.iteration.dispatch",
546
- runId: args.runId,
547
- timestamp: args.now(),
548
- payload: {
549
- iterationIndex: args.item.index,
550
- agentRunName: slot.agentRunName,
551
- placement: placement.kind,
552
- sandboxId: placement.sandboxId,
553
- fleetId: placement.fleetId,
554
- machineId: placement.machineId,
555
- groupId: args.roundIndex,
556
- parentIndex: args.parentIndex
557
- }
558
- });
559
- const message = spec.taskToPrompt(args.item.task);
560
- const events = [];
561
- for await (const event of box.streamPrompt(message, { signal: args.signal })) {
562
- events.push(event);
563
- const llmCall = extractLlmCallEvent(event, slot.agentRunName);
564
- if (llmCall) {
565
- slot.costUsd += llmCall.costUsd ?? 0;
566
- slot.tokenUsage.input += llmCall.tokensIn ?? 0;
567
- slot.tokenUsage.output += llmCall.tokensOut ?? 0;
568
- args.ctx.runHandle?.observe(llmCall);
569
- }
570
- }
571
- slot.events = events;
572
- slot.output = args.output.parse(events);
573
- if (args.validator) {
574
- slot.verdict = await args.validator.validate(slot.output, {
575
- iteration: args.item.index,
576
- signal: args.signal,
577
- traceEmitter: args.ctx.traceEmitter
578
- });
579
- }
580
- } catch (err) {
581
- slot.error = err instanceof Error ? err : new Error(String(err));
582
- } finally {
583
- slot.endedAt = args.now();
584
- await emitTrace(args.ctx.traceEmitter, {
585
- kind: "loop.iteration.ended",
586
- runId: args.runId,
587
- timestamp: args.now(),
588
- payload: {
589
- iterationIndex: args.item.index,
590
- agentRunName: slot.agentRunName,
591
- outputHash: slot.output !== void 0 ? hashJson(slot.output) : void 0,
592
- verdict: slot.verdict,
593
- error: slot.error?.message,
594
- costUsd: slot.costUsd,
595
- durationMs: slot.endedAt - slot.startedAt,
596
- tokenUsage: slot.tokenUsage.input || slot.tokenUsage.output ? { ...slot.tokenUsage } : void 0,
597
- groupId: args.roundIndex,
598
- parentIndex: args.parentIndex,
599
- outputPreview: slot.output !== void 0 ? previewOutput(slot.output) : void 0
600
- }
601
- });
602
- }
603
- }
604
- function branchPoint(iterations) {
605
- if (iterations.length === 0) return void 0;
606
- let best = iterations.length - 1;
607
- let bestScore = -Infinity;
608
- for (const iter of iterations) {
609
- if (iter.verdict?.valid !== true) continue;
610
- const score = iter.verdict.score ?? 0;
611
- if (score > bestScore) {
612
- bestScore = score;
613
- best = iter.index;
614
- }
615
- }
616
- return best;
617
- }
618
- function previewOutput(output) {
619
- let s;
620
- try {
621
- s = typeof output === "string" ? output : JSON.stringify(output) ?? String(output);
622
- } catch {
623
- s = String(output);
624
- }
625
- return s.length > 280 ? `${s.slice(0, 280)}\u2026` : s;
626
- }
627
- function describePlacementSafe(client, box) {
628
- if (typeof client.describePlacement === "function") {
629
- try {
630
- const result = client.describePlacement(box);
631
- if (result && typeof result === "object" && (result.kind === "sibling" || result.kind === "fleet")) {
632
- return {
633
- kind: result.kind,
634
- sandboxId: result.sandboxId ?? readSandboxId(box),
635
- fleetId: result.fleetId,
636
- machineId: result.machineId
637
- };
638
- }
639
- } catch {
640
- }
641
- }
642
- return { kind: "sibling", sandboxId: readSandboxId(box) };
643
- }
644
- function readSandboxId(box) {
645
- const raw = box.id;
646
- return typeof raw === "string" && raw.length > 0 ? raw : void 0;
647
- }
648
- async function createSandboxForSpec(client, spec, signal) {
649
- const overrides = spec.sandboxOverrides ?? {};
650
- const overrideBackend = overrides.backend;
651
- const opts = {
652
- ...overrides,
653
- backend: {
654
- type: overrideBackend?.type ?? inferBackendType(spec.profile),
655
- profile: spec.profile,
656
- ...overrideBackend?.model ? { model: overrideBackend.model } : {},
657
- ...overrideBackend?.server ? { server: overrideBackend.server } : {}
658
- }
659
- };
660
- if (signal.aborted) throwAbort();
661
- return client.create(opts);
662
- }
663
- function inferBackendType(profile) {
664
- const explicit = profile.metadata?.backendType;
665
- if (typeof explicit === "string") return explicit;
666
- return "opencode";
667
- }
668
- function finalize(args) {
669
- const winner = (args.options.selectWinner ?? defaultSelectWinner)(args.iterations);
670
- const costUsd = args.iterations.reduce((sum, iter) => sum + (iter.costUsd || 0), 0);
671
- const tokenUsage = args.iterations.reduce(
672
- (acc, iter) => {
673
- acc.input += iter.tokenUsage?.input ?? 0;
674
- acc.output += iter.tokenUsage?.output ?? 0;
675
- return acc;
676
- },
677
- { input: 0, output: 0 }
678
- );
679
- const result = {
680
- decision: args.decision,
681
- iterations: args.iterations,
682
- winner,
683
- durationMs: args.now() - args.startMs,
684
- costUsd,
685
- tokenUsage
686
- };
687
- void emitTrace(args.options.ctx.traceEmitter, {
688
- kind: "loop.ended",
689
- runId: args.runId,
690
- timestamp: args.now(),
691
- payload: {
692
- winnerIterationIndex: winner?.iterationIndex,
693
- totalCostUsd: costUsd,
694
- durationMs: result.durationMs,
695
- iterations: args.iterations.length
696
- }
697
- });
698
- return result;
699
- }
700
- function defaultSelectWinner(iterations) {
701
- const candidates = iterations.filter((iter) => iter.output !== void 0 && !iter.error);
702
- if (candidates.length === 0) return void 0;
703
- const valid = candidates.filter((iter) => iter.verdict?.valid === true);
704
- const pool = valid.length > 0 ? valid : candidates;
705
- const sorted = [...pool].sort(
706
- (a, b) => (b.verdict?.score ?? 0) - (a.verdict?.score ?? 0) || a.index - b.index
707
- );
708
- const top = sorted[0];
709
- if (!top || top.output === void 0) return void 0;
710
- return {
711
- task: top.task,
712
- output: top.output,
713
- verdict: top.verdict,
714
- iterationIndex: top.index,
715
- agentRunName: top.agentRunName
716
- };
717
- }
718
- function resolveAgentRuns(options) {
719
- if (options.agentRun && options.agentRuns) {
720
- throw new ValidationError("runLoop: pass exactly one of `agentRun` or `agentRuns`");
721
- }
722
- if (options.agentRun) return [options.agentRun];
723
- if (options.agentRuns && options.agentRuns.length > 0) return options.agentRuns;
724
- throw new ValidationError("runLoop: `agentRun` or non-empty `agentRuns` is required");
725
- }
726
- function isTerminalDecision(decision) {
727
- return decision === "stop" || decision === "pick-winner" || decision === "fail" || decision === "done";
728
- }
729
- function serializeDecision(decision) {
730
- if (typeof decision === "string") return decision;
731
- if (decision === null || decision === void 0) return "null";
732
- try {
733
- return JSON.stringify(decision);
734
- } catch {
735
- return String(decision);
736
- }
737
- }
738
- async function emitTrace(emitter, event) {
739
- if (!emitter) return;
740
- await emitter.emit(event);
741
- }
742
- function randomSuffix(len = 8) {
743
- return Math.random().toString(36).slice(2, 2 + len);
744
- }
745
- function throwAbort() {
746
- const err = new Error("aborted");
747
- err.name = "AbortError";
748
- throw err;
749
- }
750
- function hashJson(value) {
751
- let str;
752
- try {
753
- str = JSON.stringify(value) ?? String(value);
754
- } catch {
755
- str = String(value);
756
- }
757
- let h = 2166136261;
758
- for (let i = 0; i < str.length; i += 1) {
759
- h ^= str.charCodeAt(i);
760
- h = Math.imul(h, 16777619);
761
- }
762
- return (h >>> 0).toString(16).padStart(8, "0");
763
- }
764
-
765
- // src/loops/loop-dispatch.ts
766
- function campaignTraceToLoopEmitter(trace) {
767
- return {
768
- emit(event) {
769
- trace.span(event.kind, { runId: event.runId, timestamp: event.timestamp, ...event.payload }).end();
770
- }
771
- };
772
- }
773
- async function runLoopForCell(opts, scenario, profile, ctx) {
774
- const loopOptions = opts.toLoopOptions(scenario, profile);
775
- const result = await runLoop({
776
- ...loopOptions,
777
- ctx: {
778
- sandboxClient: opts.sandboxClient,
779
- signal: ctx.signal,
780
- traceEmitter: opts.forwardTrace === false ? void 0 : campaignTraceToLoopEmitter(ctx.trace)
781
- }
782
- });
783
- reportLoopUsage(ctx.cost, result, opts.costSource ?? "loop");
784
- const toArtifact = opts.toArtifact ?? ((r) => r.winner?.output);
785
- return toArtifact(result);
786
- }
787
- function loopDispatch(opts) {
788
- return (profile, scenario, ctx) => runLoopForCell(opts, scenario, profile, ctx);
789
- }
790
- function loopCampaignDispatch(opts) {
791
- const profileSentinel = { id: "loop-campaign", model: "n/a@loop-campaign" };
792
- const profiled = {
793
- ...opts,
794
- toLoopOptions: (scenario) => opts.toLoopOptions(scenario)
795
- };
796
- return (scenario, ctx) => runLoopForCell(profiled, scenario, profileSentinel, ctx);
797
- }
798
-
799
- export {
800
- createDynamicDriver,
801
- summarizeHistory,
802
- createRefineDriver,
803
- refineWinnerIndex,
804
- createSandboxPlanner,
805
- reportLoopUsage,
806
- extractLlmCallEvent,
807
- mapSandboxEvent,
808
- runLoop,
809
- createSandboxForSpec,
810
- loopDispatch,
811
- loopCampaignDispatch
812
- };
813
- //# sourceMappingURL=chunk-EKBSQYZE.js.map