@dogpile/sdk 0.2.1 → 0.3.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 (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +86 -655
  3. package/dist/browser/index.js +337 -22
  4. package/dist/browser/index.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/runtime/broadcast.d.ts +1 -0
  8. package/dist/runtime/broadcast.d.ts.map +1 -1
  9. package/dist/runtime/broadcast.js +27 -6
  10. package/dist/runtime/broadcast.js.map +1 -1
  11. package/dist/runtime/coordinator.d.ts +1 -0
  12. package/dist/runtime/coordinator.d.ts.map +1 -1
  13. package/dist/runtime/coordinator.js +45 -8
  14. package/dist/runtime/coordinator.js.map +1 -1
  15. package/dist/runtime/engine.d.ts.map +1 -1
  16. package/dist/runtime/engine.js +5 -0
  17. package/dist/runtime/engine.js.map +1 -1
  18. package/dist/runtime/sequential.d.ts +1 -0
  19. package/dist/runtime/sequential.d.ts.map +1 -1
  20. package/dist/runtime/sequential.js +24 -6
  21. package/dist/runtime/sequential.js.map +1 -1
  22. package/dist/runtime/shared.d.ts +1 -0
  23. package/dist/runtime/shared.d.ts.map +1 -1
  24. package/dist/runtime/shared.js +24 -6
  25. package/dist/runtime/shared.js.map +1 -1
  26. package/dist/runtime/termination.d.ts +6 -1
  27. package/dist/runtime/termination.d.ts.map +1 -1
  28. package/dist/runtime/termination.js +75 -0
  29. package/dist/runtime/termination.js.map +1 -1
  30. package/dist/runtime/validation.d.ts.map +1 -1
  31. package/dist/runtime/validation.js +22 -0
  32. package/dist/runtime/validation.js.map +1 -1
  33. package/dist/runtime/wrap-up.d.ts +26 -0
  34. package/dist/runtime/wrap-up.d.ts.map +1 -0
  35. package/dist/runtime/wrap-up.js +178 -0
  36. package/dist/runtime/wrap-up.js.map +1 -0
  37. package/dist/types.d.ts +68 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +3 -2
  40. package/src/index.ts +3 -1
  41. package/src/runtime/broadcast.ts +49 -19
  42. package/src/runtime/coordinator.ts +83 -27
  43. package/src/runtime/engine.ts +6 -0
  44. package/src/runtime/sequential.ts +45 -19
  45. package/src/runtime/shared.ts +45 -19
  46. package/src/runtime/termination.ts +100 -0
  47. package/src/runtime/validation.ts +25 -0
  48. package/src/runtime/wrap-up.ts +257 -0
  49. package/src/types.ts +70 -0
@@ -638,6 +638,10 @@ function firstOf(...conditions) {
638
638
  * own normalized inputs so one stop class cannot accidentally satisfy another.
639
639
  */
640
640
  function evaluateTermination(condition, context) {
641
+ if (isTerminationFloorBlocked(condition, context)) return {
642
+ type: "continue",
643
+ condition
644
+ };
641
645
  switch (condition.kind) {
642
646
  case "budget": return evaluateBudget(condition, context);
643
647
  case "firstOf": return evaluateFirstOf(condition, context).decision;
@@ -695,6 +699,17 @@ function evaluateTerminationStop(condition, context) {
695
699
  return stopRecord(condition, decision);
696
700
  }
697
701
  /**
702
+ * Warn when a protocol-level termination floor cannot be satisfied because a
703
+ * lower iteration cap will stop the run first.
704
+ */
705
+ function warnOnProtocolTerminationMisconfiguration(protocol, terminate, warn = console.warn) {
706
+ const minTurns = protocolMinTurns(protocol);
707
+ if (minTurns === void 0 || !terminate) return;
708
+ const limitingIterationBudget = smallestIterationBudget(terminate);
709
+ if (limitingIterationBudget === void 0 || limitingIterationBudget >= minTurns) return;
710
+ warn(`[dogpile] protocol.minTurns (${minTurns}) exceeds terminate budget maxIterations (${limitingIterationBudget}); maxIterations will win.`);
711
+ }
712
+ /**
698
713
  * Combine independently evaluated termination decisions with SDK precedence.
699
714
  *
700
715
  * Budget caps win over judge decisions, and judge decisions win over
@@ -843,6 +858,48 @@ function stopPrecedence(reason) {
843
858
  if (reason.startsWith("judge:")) return 1;
844
859
  return 2;
845
860
  }
861
+ function isTerminationFloorBlocked(condition, context) {
862
+ if (condition.kind !== "convergence" && condition.kind !== "judge") return false;
863
+ const floor = protocolTerminationFloor(context.protocolConfig);
864
+ if (floor === void 0 || floor <= 0) return false;
865
+ return protocolProgress(context) < floor;
866
+ }
867
+ function protocolTerminationFloor(protocol) {
868
+ if (!protocol) return;
869
+ switch (protocol.kind) {
870
+ case "broadcast": return protocol.minRounds;
871
+ case "coordinator":
872
+ case "sequential":
873
+ case "shared": return protocol.minTurns;
874
+ }
875
+ }
876
+ function protocolProgress(context) {
877
+ return context.protocolIteration ?? context.iteration ?? context.transcript.length;
878
+ }
879
+ function protocolMinTurns(protocol) {
880
+ switch (protocol.kind) {
881
+ case "broadcast": return;
882
+ case "coordinator":
883
+ case "sequential":
884
+ case "shared": return protocol.minTurns;
885
+ }
886
+ }
887
+ function smallestIterationBudget(condition) {
888
+ switch (condition.kind) {
889
+ case "budget": return condition.maxIterations;
890
+ case "convergence":
891
+ case "judge": return;
892
+ case "firstOf": {
893
+ let smallest;
894
+ for (const child of condition.conditions) {
895
+ const budget = smallestIterationBudget(child);
896
+ if (budget === void 0) continue;
897
+ smallest = smallest === void 0 ? budget : Math.min(smallest, budget);
898
+ }
899
+ return smallest;
900
+ }
901
+ }
902
+ }
846
903
  function judgeStopDetail(decision, minScore) {
847
904
  return {
848
905
  decision: decision.type,
@@ -921,6 +978,7 @@ function validateDogpileOptions(options) {
921
978
  validateOptionalTemperature(options.temperature, "temperature");
922
979
  validateOptionalBudgetCaps(options.budget, "budget");
923
980
  validateOptionalTerminationCondition(options.terminate, "terminate");
981
+ validateOptionalWrapUpHint(options.wrapUpHint, "wrapUpHint");
924
982
  validateOptionalFunction(options.evaluate, "evaluate");
925
983
  validateOptionalSeed(options.seed, "seed");
926
984
  validateOptionalAbortSignal(options.signal, "signal");
@@ -941,6 +999,7 @@ function validateEngineOptions(options) {
941
999
  validateOptionalTemperature(options.temperature, "temperature");
942
1000
  validateOptionalBudgetCaps(options.budget, "budget");
943
1001
  validateOptionalTerminationCondition(options.terminate, "terminate");
1002
+ validateOptionalWrapUpHint(options.wrapUpHint, "wrapUpHint");
944
1003
  validateOptionalFunction(options.evaluate, "evaluate");
945
1004
  validateOptionalSeed(options.seed, "seed");
946
1005
  validateOptionalAbortSignal(options.signal, "signal");
@@ -973,10 +1032,12 @@ function validateProtocolConfig(value, path) {
973
1032
  case "sequential":
974
1033
  case "shared":
975
1034
  validateOptionalPositiveInteger(record.maxTurns, `${path}.maxTurns`);
1035
+ validateOptionalNonNegativeInteger(record.minTurns, `${path}.minTurns`);
976
1036
  if (kind === "shared") validateOptionalString(record.organizationalMemory, `${path}.organizationalMemory`);
977
1037
  return;
978
1038
  case "broadcast":
979
1039
  validateOptionalPositiveInteger(record.maxRounds, `${path}.maxRounds`);
1040
+ validateOptionalNonNegativeInteger(record.minRounds, `${path}.minRounds`);
980
1041
  return;
981
1042
  }
982
1043
  }
@@ -1144,6 +1205,20 @@ function validateJudgeRubric(value, path) {
1144
1205
  function validateOptionalTemperature(value, path) {
1145
1206
  validateOptionalNumberInRange(value, path, 0, 2);
1146
1207
  }
1208
+ function validateOptionalWrapUpHint(value, path) {
1209
+ if (value === void 0) return;
1210
+ const record = requireRecord(value, path);
1211
+ validateOptionalNonNegativeInteger(record.atIteration, `${path}.atIteration`);
1212
+ validateOptionalNumberInRange(record.atFraction, `${path}.atFraction`, 0, 1);
1213
+ validateOptionalFunction(record.inject, `${path}.inject`);
1214
+ if (record.atIteration === void 0 && record.atFraction === void 0) invalidConfiguration({
1215
+ path,
1216
+ rule: "object",
1217
+ message: "wrapUpHint must configure atIteration or atFraction.",
1218
+ expected: "WrapUpHintConfig with atIteration or atFraction",
1219
+ actual: value
1220
+ });
1221
+ }
1147
1222
  function validateOptionalSeed(value, path) {
1148
1223
  if (value === void 0) return;
1149
1224
  if (typeof value === "string") return;
@@ -2067,6 +2142,151 @@ function isRuntimeToolAdapterErrorCode(value) {
2067
2142
  return value === "invalid-input" || value === "permission-denied" || value === "timeout" || value === "aborted" || value === "unavailable" || value === "backend-error" || value === "unknown";
2068
2143
  }
2069
2144
  //#endregion
2145
+ //#region src/runtime/wrap-up.ts
2146
+ function createWrapUpHintController(options) {
2147
+ const hint = options.wrapUpHint;
2148
+ const effectiveBudget = effectiveWrapUpBudget(options.budget, options.terminate);
2149
+ let emitted = false;
2150
+ return {
2151
+ context(context) {
2152
+ return wrapUpEvaluationContext({
2153
+ ...context,
2154
+ tier: options.tier,
2155
+ ...effectiveBudget !== void 0 ? { budget: effectiveBudget } : {}
2156
+ });
2157
+ },
2158
+ inject(messages, context) {
2159
+ if (!hint || emitted) return messages;
2160
+ const evaluationContext = wrapUpEvaluationContext({
2161
+ ...context,
2162
+ tier: options.tier,
2163
+ ...effectiveBudget !== void 0 ? { budget: effectiveBudget } : {}
2164
+ });
2165
+ if (!shouldInjectWrapUpHint(hint, evaluationContext)) return messages;
2166
+ const content = (hint.inject ?? defaultWrapUpHint)(evaluationContext);
2167
+ emitted = true;
2168
+ return [
2169
+ messages[0] ?? {
2170
+ role: "system",
2171
+ content: ""
2172
+ },
2173
+ {
2174
+ role: "system",
2175
+ content
2176
+ },
2177
+ ...messages.slice(1)
2178
+ ];
2179
+ }
2180
+ };
2181
+ }
2182
+ function wrapUpEvaluationContext(options) {
2183
+ const iteration = options.iteration ?? options.transcript.length;
2184
+ const elapsedMs = options.elapsedMs;
2185
+ return {
2186
+ runId: options.runId,
2187
+ protocol: options.protocol,
2188
+ tier: options.tier,
2189
+ cost: options.cost,
2190
+ events: options.events,
2191
+ transcript: options.transcript,
2192
+ ...options.protocolConfig !== void 0 ? { protocolConfig: options.protocolConfig } : {},
2193
+ ...iteration !== void 0 ? { iteration } : {},
2194
+ ...options.protocolIteration !== void 0 ? { protocolIteration: options.protocolIteration } : {},
2195
+ ...elapsedMs !== void 0 ? { elapsedMs } : {},
2196
+ ...options.budget !== void 0 ? { budget: options.budget } : {},
2197
+ ...options.budget !== void 0 ? { remainingBudget: remainingBudget(options.budget, {
2198
+ cost: options.cost,
2199
+ iteration,
2200
+ elapsedMs
2201
+ }) } : {},
2202
+ ...options.metadata !== void 0 ? { metadata: options.metadata } : {}
2203
+ };
2204
+ }
2205
+ function shouldInjectWrapUpHint(hint, context) {
2206
+ const iteration = context.iteration ?? context.transcript.length;
2207
+ if (hint.atIteration !== void 0 && iteration >= hint.atIteration) return true;
2208
+ if (hint.atFraction === void 0 || context.budget === void 0) return false;
2209
+ const fraction = hint.atFraction;
2210
+ return capFractionReached(iteration, context.budget.maxIterations, fraction) || capFractionReached(context.elapsedMs, context.budget.timeoutMs, fraction);
2211
+ }
2212
+ function capFractionReached(current, limit, fraction) {
2213
+ if (current === void 0 || limit === void 0 || limit <= 0) return false;
2214
+ return current / limit >= fraction;
2215
+ }
2216
+ function remainingBudget(budget, current) {
2217
+ return {
2218
+ ...budget.maxIterations !== void 0 && current.iteration !== void 0 ? { iterations: Math.max(0, budget.maxIterations - current.iteration) } : {},
2219
+ ...budget.timeoutMs !== void 0 && current.elapsedMs !== void 0 ? { timeoutMs: Math.max(0, budget.timeoutMs - current.elapsedMs) } : {},
2220
+ ...budget.maxUsd !== void 0 ? { usd: Math.max(0, budget.maxUsd - current.cost.usd) } : {},
2221
+ ...budget.maxTokens !== void 0 ? { tokens: Math.max(0, budget.maxTokens - current.cost.totalTokens) } : {}
2222
+ };
2223
+ }
2224
+ function defaultWrapUpHint(context) {
2225
+ const parts = [];
2226
+ const remaining = context.remainingBudget;
2227
+ if (remaining?.iterations !== void 0) {
2228
+ const label = remaining.iterations === 1 ? "turn" : "turns";
2229
+ parts.push(`${remaining.iterations} ${label} remaining`);
2230
+ }
2231
+ if (remaining?.timeoutMs !== void 0) parts.push(`${formatRemainingTime(remaining.timeoutMs)} remaining`);
2232
+ return `[wrap-up] ${parts.length === 0 ? "You are approaching a configured hard limit." : `You are approaching a hard limit with ${parts.join(" and ")}.`} If you have enough context, package your work now and return a final-ready answer.`;
2233
+ }
2234
+ function formatRemainingTime(timeoutMs) {
2235
+ if (timeoutMs >= 1e3) return `${(timeoutMs / 1e3).toFixed(1)}s`;
2236
+ return `${timeoutMs}ms`;
2237
+ }
2238
+ function effectiveWrapUpBudget(budget, terminate) {
2239
+ const terminationBudget = budgetCapsFromTermination(terminate);
2240
+ if (!budget && !terminationBudget) return;
2241
+ const maxUsd = minCap(budget?.maxUsd, terminationBudget?.maxUsd);
2242
+ const maxTokens = minCap(budget?.maxTokens, terminationBudget?.maxTokens);
2243
+ const maxIterations = minCap(budget?.maxIterations, terminationBudget?.maxIterations);
2244
+ const timeoutMs = minCap(budget?.timeoutMs, terminationBudget?.timeoutMs);
2245
+ return {
2246
+ ...maxUsd !== void 0 ? { maxUsd } : {},
2247
+ ...maxTokens !== void 0 ? { maxTokens } : {},
2248
+ ...maxIterations !== void 0 ? { maxIterations } : {},
2249
+ ...timeoutMs !== void 0 ? { timeoutMs } : {}
2250
+ };
2251
+ }
2252
+ function budgetCapsFromTermination(condition) {
2253
+ if (!condition) return;
2254
+ switch (condition.kind) {
2255
+ case "budget": return {
2256
+ ...condition.maxUsd !== void 0 ? { maxUsd: condition.maxUsd } : {},
2257
+ ...condition.maxTokens !== void 0 ? { maxTokens: condition.maxTokens } : {},
2258
+ ...condition.maxIterations !== void 0 ? { maxIterations: condition.maxIterations } : {},
2259
+ ...condition.timeoutMs !== void 0 ? { timeoutMs: condition.timeoutMs } : {}
2260
+ };
2261
+ case "firstOf": {
2262
+ let merged;
2263
+ for (const child of condition.conditions) merged = mergeBudgetCaps(merged, budgetCapsFromTermination(child));
2264
+ return merged;
2265
+ }
2266
+ case "convergence":
2267
+ case "judge": return;
2268
+ }
2269
+ }
2270
+ function mergeBudgetCaps(left, right) {
2271
+ if (!left) return right;
2272
+ if (!right) return left;
2273
+ const maxUsd = minCap(left.maxUsd, right.maxUsd);
2274
+ const maxTokens = minCap(left.maxTokens, right.maxTokens);
2275
+ const maxIterations = minCap(left.maxIterations, right.maxIterations);
2276
+ const timeoutMs = minCap(left.timeoutMs, right.timeoutMs);
2277
+ return {
2278
+ ...maxUsd !== void 0 ? { maxUsd } : {},
2279
+ ...maxTokens !== void 0 ? { maxTokens } : {},
2280
+ ...maxIterations !== void 0 ? { maxIterations } : {},
2281
+ ...timeoutMs !== void 0 ? { timeoutMs } : {}
2282
+ };
2283
+ }
2284
+ function minCap(left, right) {
2285
+ if (left === void 0) return right;
2286
+ if (right === void 0) return left;
2287
+ return Math.min(left, right);
2288
+ }
2289
+ //#endregion
2070
2290
  //#region src/runtime/broadcast.ts
2071
2291
  async function runBroadcast(options) {
2072
2292
  const runId = createRunId$3();
@@ -2081,6 +2301,14 @@ async function runBroadcast(options) {
2081
2301
  const startedAtMs = nowMs$3();
2082
2302
  let stopped = false;
2083
2303
  let termination;
2304
+ const wrapUpHint = createWrapUpHintController({
2305
+ protocol: options.protocol,
2306
+ tier: options.tier,
2307
+ ...options.budget ? { budget: options.budget } : {},
2308
+ ...options.terminate ? { terminate: options.terminate } : {},
2309
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}
2310
+ });
2311
+ warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
2084
2312
  const emit = (event) => {
2085
2313
  events.push(event);
2086
2314
  options.emit?.(event);
@@ -2134,13 +2362,21 @@ async function runBroadcast(options) {
2134
2362
  round,
2135
2363
  ...toolAvailability
2136
2364
  },
2137
- messages: [{
2365
+ messages: wrapUpHint.inject([{
2138
2366
  role: "system",
2139
2367
  content: buildSystemPrompt$3(agent)
2140
2368
  }, {
2141
2369
  role: "user",
2142
2370
  content: input
2143
- }]
2371
+ }], {
2372
+ runId,
2373
+ protocol: "broadcast",
2374
+ cost: totalCost,
2375
+ events,
2376
+ transcript,
2377
+ iteration: transcript.length,
2378
+ elapsedMs: elapsedMs$3(startedAtMs)
2379
+ })
2144
2380
  };
2145
2381
  const response = await generateModelTurn({
2146
2382
  model: options.model,
@@ -2305,16 +2541,17 @@ async function runBroadcast(options) {
2305
2541
  function stopIfNeeded() {
2306
2542
  throwIfAborted(options.signal, options.model.id);
2307
2543
  if (stopped || !options.terminate) return stopped;
2308
- const stopRecord = evaluateTerminationStop(options.terminate, {
2544
+ const stopRecord = evaluateTerminationStop(options.terminate, wrapUpHint.context({
2309
2545
  runId,
2310
2546
  protocol: "broadcast",
2311
- tier: options.tier,
2547
+ protocolConfig: options.protocol,
2548
+ protocolIteration: broadcastRoundsCompleted(events),
2312
2549
  cost: totalCost,
2313
2550
  events,
2314
2551
  transcript,
2315
2552
  iteration: transcript.length,
2316
2553
  elapsedMs: elapsedMs$3(startedAtMs)
2317
- });
2554
+ }));
2318
2555
  if (!stopRecord) return false;
2319
2556
  stopped = true;
2320
2557
  termination = stopRecord;
@@ -2336,6 +2573,9 @@ async function runBroadcast(options) {
2336
2573
  recordProtocolDecision(event, { transcriptEntryCount: transcript.length });
2337
2574
  }
2338
2575
  }
2576
+ function broadcastRoundsCompleted(events) {
2577
+ return events.filter((event) => event.type === "broadcast").length;
2578
+ }
2339
2579
  function buildSystemPrompt$3(agent) {
2340
2580
  const instruction = agent.instructions ? `\nInstructions: ${agent.instructions}` : "";
2341
2581
  return `You are ${agent.id}, acting as ${agent.role} in a Broadcast multi-agent protocol.${instruction}`;
@@ -2383,6 +2623,14 @@ async function runCoordinator(options) {
2383
2623
  const startedAtMs = nowMs$2();
2384
2624
  let stopped = false;
2385
2625
  let termination;
2626
+ const wrapUpHint = createWrapUpHintController({
2627
+ protocol: options.protocol,
2628
+ tier: options.tier,
2629
+ ...options.budget ? { budget: options.budget } : {},
2630
+ ...options.terminate ? { terminate: options.terminate } : {},
2631
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}
2632
+ });
2633
+ warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
2386
2634
  const emit = (event) => {
2387
2635
  events.push(event);
2388
2636
  options.emit?.(event);
@@ -2432,6 +2680,9 @@ async function runCoordinator(options) {
2432
2680
  providerCalls,
2433
2681
  toolExecutor,
2434
2682
  toolAvailability,
2683
+ events,
2684
+ startedAtMs,
2685
+ wrapUpHint,
2435
2686
  emit,
2436
2687
  recordProtocolDecision
2437
2688
  });
@@ -2453,6 +2704,11 @@ async function runCoordinator(options) {
2453
2704
  providerCallSlots,
2454
2705
  toolExecutor,
2455
2706
  toolAvailability,
2707
+ totalCost,
2708
+ events,
2709
+ transcript: planTranscript,
2710
+ startedAtMs,
2711
+ wrapUpHint,
2456
2712
  emit
2457
2713
  })));
2458
2714
  providerCalls.push(...providerCallSlots.filter((call) => call !== void 0));
@@ -2499,6 +2755,9 @@ async function runCoordinator(options) {
2499
2755
  providerCalls,
2500
2756
  toolExecutor,
2501
2757
  toolAvailability,
2758
+ events,
2759
+ startedAtMs,
2760
+ wrapUpHint,
2502
2761
  emit,
2503
2762
  recordProtocolDecision
2504
2763
  });
@@ -2579,16 +2838,17 @@ async function runCoordinator(options) {
2579
2838
  function stopIfNeeded() {
2580
2839
  throwIfAborted(options.signal, options.model.id);
2581
2840
  if (stopped || !options.terminate) return stopped;
2582
- const stopRecord = evaluateTerminationStop(options.terminate, {
2841
+ const stopRecord = evaluateTerminationStop(options.terminate, wrapUpHint.context({
2583
2842
  runId,
2584
2843
  protocol: "coordinator",
2585
- tier: options.tier,
2844
+ protocolConfig: options.protocol,
2845
+ protocolIteration: transcript.length,
2586
2846
  cost: totalCost,
2587
2847
  events,
2588
2848
  transcript,
2589
2849
  iteration: transcript.length,
2590
2850
  elapsedMs: elapsedMs$2(startedAtMs)
2591
- });
2851
+ }));
2592
2852
  if (!stopRecord) return false;
2593
2853
  stopped = true;
2594
2854
  termination = stopRecord;
@@ -2625,13 +2885,21 @@ async function runCoordinatorTurn(turn) {
2625
2885
  phase: turn.phase,
2626
2886
  ...turn.toolAvailability
2627
2887
  },
2628
- messages: [{
2888
+ messages: turn.wrapUpHint.inject([{
2629
2889
  role: "system",
2630
2890
  content: buildSystemPrompt$2(turn.agent, turn.coordinator)
2631
2891
  }, {
2632
2892
  role: "user",
2633
2893
  content: turn.input
2634
- }]
2894
+ }], {
2895
+ runId: turn.runId,
2896
+ protocol: "coordinator",
2897
+ cost: turn.totalCost,
2898
+ events: turn.events,
2899
+ transcript: turn.transcript,
2900
+ iteration: turn.transcript.length,
2901
+ elapsedMs: elapsedMs$2(turn.startedAtMs)
2902
+ })
2635
2903
  };
2636
2904
  const response = await generateModelTurn({
2637
2905
  model: turn.options.model,
@@ -2698,13 +2966,21 @@ async function runCoordinatorWorkerTurn(turn) {
2698
2966
  phase: "worker",
2699
2967
  ...turn.toolAvailability
2700
2968
  },
2701
- messages: [{
2969
+ messages: turn.wrapUpHint.inject([{
2702
2970
  role: "system",
2703
2971
  content: buildSystemPrompt$2(turn.agent, turn.coordinator)
2704
2972
  }, {
2705
2973
  role: "user",
2706
2974
  content: turn.input
2707
- }]
2975
+ }], {
2976
+ runId: turn.runId,
2977
+ protocol: "coordinator",
2978
+ cost: turn.totalCost,
2979
+ events: turn.events,
2980
+ transcript: turn.transcript,
2981
+ iteration: turn.turn - 1,
2982
+ elapsedMs: elapsedMs$2(turn.startedAtMs)
2983
+ })
2708
2984
  };
2709
2985
  const response = await generateModelTurn({
2710
2986
  model: turn.options.model,
@@ -2787,6 +3063,14 @@ async function runSequential(options) {
2787
3063
  const startedAtMs = nowMs$1();
2788
3064
  let stopped = false;
2789
3065
  let termination;
3066
+ const wrapUpHint = createWrapUpHintController({
3067
+ protocol: options.protocol,
3068
+ tier: options.tier,
3069
+ ...options.budget ? { budget: options.budget } : {},
3070
+ ...options.terminate ? { terminate: options.terminate } : {},
3071
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}
3072
+ });
3073
+ warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
2790
3074
  const emit = (event) => {
2791
3075
  events.push(event);
2792
3076
  options.emit?.(event);
@@ -2838,13 +3122,21 @@ async function runSequential(options) {
2838
3122
  turn,
2839
3123
  ...toolAvailability
2840
3124
  },
2841
- messages: [{
3125
+ messages: wrapUpHint.inject([{
2842
3126
  role: "system",
2843
3127
  content: buildSystemPrompt$1(agent)
2844
3128
  }, {
2845
3129
  role: "user",
2846
3130
  content: input
2847
- }]
3131
+ }], {
3132
+ runId,
3133
+ protocol: "sequential",
3134
+ cost: totalCost,
3135
+ events,
3136
+ transcript,
3137
+ iteration: transcript.length,
3138
+ elapsedMs: elapsedMs$1(startedAtMs)
3139
+ })
2848
3140
  };
2849
3141
  const response = await generateModelTurn({
2850
3142
  model: options.model,
@@ -2969,16 +3261,17 @@ async function runSequential(options) {
2969
3261
  function stopIfNeeded() {
2970
3262
  throwIfAborted(options.signal, options.model.id);
2971
3263
  if (stopped || !options.terminate) return stopped;
2972
- const stopRecord = evaluateTerminationStop(options.terminate, {
3264
+ const stopRecord = evaluateTerminationStop(options.terminate, wrapUpHint.context({
2973
3265
  runId,
2974
3266
  protocol: "sequential",
2975
- tier: options.tier,
3267
+ protocolConfig: options.protocol,
3268
+ protocolIteration: transcript.length,
2976
3269
  cost: totalCost,
2977
3270
  events,
2978
3271
  transcript,
2979
3272
  iteration: transcript.length,
2980
3273
  elapsedMs: elapsedMs$1(startedAtMs)
2981
- });
3274
+ }));
2982
3275
  if (!stopRecord) return false;
2983
3276
  stopped = true;
2984
3277
  termination = stopRecord;
@@ -3040,6 +3333,14 @@ async function runShared(options) {
3040
3333
  const startedAtMs = nowMs();
3041
3334
  let stopped = false;
3042
3335
  let termination;
3336
+ const wrapUpHint = createWrapUpHintController({
3337
+ protocol: options.protocol,
3338
+ tier: options.tier,
3339
+ ...options.budget ? { budget: options.budget } : {},
3340
+ ...options.terminate ? { terminate: options.terminate } : {},
3341
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}
3342
+ });
3343
+ warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
3043
3344
  const emit = (event) => {
3044
3345
  events.push(event);
3045
3346
  options.emit?.(event);
@@ -3092,13 +3393,21 @@ async function runShared(options) {
3092
3393
  turn,
3093
3394
  ...toolAvailability
3094
3395
  },
3095
- messages: [{
3396
+ messages: wrapUpHint.inject([{
3096
3397
  role: "system",
3097
3398
  content: buildSystemPrompt(agent)
3098
3399
  }, {
3099
3400
  role: "user",
3100
3401
  content: input
3101
- }]
3402
+ }], {
3403
+ runId,
3404
+ protocol: "shared",
3405
+ cost: totalCost,
3406
+ events,
3407
+ transcript,
3408
+ iteration: transcript.length,
3409
+ elapsedMs: elapsedMs(startedAtMs)
3410
+ })
3102
3411
  };
3103
3412
  const response = await generateModelTurn({
3104
3413
  model: options.model,
@@ -3235,16 +3544,17 @@ async function runShared(options) {
3235
3544
  function stopIfNeeded() {
3236
3545
  throwIfAborted(options.signal, options.model.id);
3237
3546
  if (stopped || !options.terminate) return stopped;
3238
- const stopRecord = evaluateTerminationStop(options.terminate, {
3547
+ const stopRecord = evaluateTerminationStop(options.terminate, wrapUpHint.context({
3239
3548
  runId,
3240
3549
  protocol: "shared",
3241
- tier: options.tier,
3550
+ protocolConfig: options.protocol,
3551
+ protocolIteration: transcript.length,
3242
3552
  cost: totalCost,
3243
3553
  events,
3244
3554
  transcript,
3245
3555
  iteration: transcript.length,
3246
3556
  elapsedMs: elapsedMs(startedAtMs)
3247
- });
3557
+ }));
3248
3558
  if (!stopRecord) return false;
3249
3559
  stopped = true;
3250
3560
  termination = stopRecord;
@@ -3333,6 +3643,7 @@ function createEngine(options) {
3333
3643
  ...options.seed !== void 0 ? { seed: options.seed } : {},
3334
3644
  ...options.signal !== void 0 ? { signal: options.signal } : {},
3335
3645
  ...terminate ? { terminate } : {},
3646
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {},
3336
3647
  ...options.evaluate ? { evaluate: options.evaluate } : {}
3337
3648
  });
3338
3649
  },
@@ -3715,6 +4026,7 @@ function runProtocol(options) {
3715
4026
  ...options.seed !== void 0 ? { seed: options.seed } : {},
3716
4027
  ...options.signal !== void 0 ? { signal: options.signal } : {},
3717
4028
  ...options.terminate ? { terminate: options.terminate } : {},
4029
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {},
3718
4030
  ...options.emit ? { emit: options.emit } : {}
3719
4031
  });
3720
4032
  case "broadcast": return runBroadcast({
@@ -3729,6 +4041,7 @@ function runProtocol(options) {
3729
4041
  ...options.seed !== void 0 ? { seed: options.seed } : {},
3730
4042
  ...options.signal !== void 0 ? { signal: options.signal } : {},
3731
4043
  ...options.terminate ? { terminate: options.terminate } : {},
4044
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {},
3732
4045
  ...options.emit ? { emit: options.emit } : {}
3733
4046
  });
3734
4047
  case "coordinator": return runCoordinator({
@@ -3743,6 +4056,7 @@ function runProtocol(options) {
3743
4056
  ...options.seed !== void 0 ? { seed: options.seed } : {},
3744
4057
  ...options.signal !== void 0 ? { signal: options.signal } : {},
3745
4058
  ...options.terminate ? { terminate: options.terminate } : {},
4059
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {},
3746
4060
  ...options.emit ? { emit: options.emit } : {}
3747
4061
  });
3748
4062
  case "shared": return runShared({
@@ -3757,6 +4071,7 @@ function runProtocol(options) {
3757
4071
  ...options.seed !== void 0 ? { seed: options.seed } : {},
3758
4072
  ...options.signal !== void 0 ? { signal: options.signal } : {},
3759
4073
  ...options.terminate ? { terminate: options.terminate } : {},
4074
+ ...options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {},
3760
4075
  ...options.emit ? { emit: options.emit } : {}
3761
4076
  });
3762
4077
  }