@dogpile/sdk 0.2.2 → 0.3.1

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 (95) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/browser/index.js +1044 -507
  3. package/dist/browser/index.js.map +1 -1
  4. package/dist/index.d.ts +5 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/runtime/broadcast.d.ts +1 -0
  9. package/dist/runtime/broadcast.d.ts.map +1 -1
  10. package/dist/runtime/broadcast.js +28 -19
  11. package/dist/runtime/broadcast.js.map +1 -1
  12. package/dist/runtime/coordinator.d.ts +1 -0
  13. package/dist/runtime/coordinator.d.ts.map +1 -1
  14. package/dist/runtime/coordinator.js +46 -21
  15. package/dist/runtime/coordinator.js.map +1 -1
  16. package/dist/runtime/engine.d.ts.map +1 -1
  17. package/dist/runtime/engine.js +5 -0
  18. package/dist/runtime/engine.js.map +1 -1
  19. package/dist/runtime/ids.d.ts +19 -0
  20. package/dist/runtime/ids.d.ts.map +1 -0
  21. package/dist/runtime/ids.js +36 -0
  22. package/dist/runtime/ids.js.map +1 -0
  23. package/dist/runtime/logger.d.ts +61 -0
  24. package/dist/runtime/logger.d.ts.map +1 -0
  25. package/dist/runtime/logger.js +114 -0
  26. package/dist/runtime/logger.js.map +1 -0
  27. package/dist/runtime/retry.d.ts +99 -0
  28. package/dist/runtime/retry.d.ts.map +1 -0
  29. package/dist/runtime/retry.js +181 -0
  30. package/dist/runtime/retry.js.map +1 -0
  31. package/dist/runtime/sequential.d.ts +1 -0
  32. package/dist/runtime/sequential.d.ts.map +1 -1
  33. package/dist/runtime/sequential.js +25 -16
  34. package/dist/runtime/sequential.js.map +1 -1
  35. package/dist/runtime/shared.d.ts +1 -0
  36. package/dist/runtime/shared.d.ts.map +1 -1
  37. package/dist/runtime/shared.js +25 -19
  38. package/dist/runtime/shared.js.map +1 -1
  39. package/dist/runtime/termination.d.ts +6 -1
  40. package/dist/runtime/termination.d.ts.map +1 -1
  41. package/dist/runtime/termination.js +75 -0
  42. package/dist/runtime/termination.js.map +1 -1
  43. package/dist/runtime/tools/built-in.d.ts +99 -0
  44. package/dist/runtime/tools/built-in.d.ts.map +1 -0
  45. package/dist/runtime/tools/built-in.js +577 -0
  46. package/dist/runtime/tools/built-in.js.map +1 -0
  47. package/dist/runtime/tools/vercel-ai.d.ts +67 -0
  48. package/dist/runtime/tools/vercel-ai.d.ts.map +1 -0
  49. package/dist/runtime/tools/vercel-ai.js +148 -0
  50. package/dist/runtime/tools/vercel-ai.js.map +1 -0
  51. package/dist/runtime/tools.d.ts +5 -268
  52. package/dist/runtime/tools.d.ts.map +1 -1
  53. package/dist/runtime/tools.js +7 -770
  54. package/dist/runtime/tools.js.map +1 -1
  55. package/dist/runtime/validation.d.ts.map +1 -1
  56. package/dist/runtime/validation.js +22 -0
  57. package/dist/runtime/validation.js.map +1 -1
  58. package/dist/runtime/wrap-up.d.ts +26 -0
  59. package/dist/runtime/wrap-up.d.ts.map +1 -0
  60. package/dist/runtime/wrap-up.js +178 -0
  61. package/dist/runtime/wrap-up.js.map +1 -0
  62. package/dist/types/benchmark.d.ts +276 -0
  63. package/dist/types/benchmark.d.ts.map +1 -0
  64. package/dist/types/benchmark.js +2 -0
  65. package/dist/types/benchmark.js.map +1 -0
  66. package/dist/types/events.d.ts +495 -0
  67. package/dist/types/events.d.ts.map +1 -0
  68. package/dist/types/events.js +2 -0
  69. package/dist/types/events.js.map +1 -0
  70. package/dist/types/replay.d.ts +169 -0
  71. package/dist/types/replay.d.ts.map +1 -0
  72. package/dist/types/replay.js +2 -0
  73. package/dist/types/replay.js.map +1 -0
  74. package/dist/types.d.ts +74 -935
  75. package/dist/types.d.ts.map +1 -1
  76. package/package.json +28 -1
  77. package/src/index.ts +7 -1
  78. package/src/runtime/broadcast.ts +50 -35
  79. package/src/runtime/coordinator.ts +84 -43
  80. package/src/runtime/engine.ts +6 -0
  81. package/src/runtime/ids.ts +41 -0
  82. package/src/runtime/logger.ts +152 -0
  83. package/src/runtime/retry.ts +270 -0
  84. package/src/runtime/sequential.ts +46 -31
  85. package/src/runtime/shared.ts +46 -35
  86. package/src/runtime/termination.ts +100 -0
  87. package/src/runtime/tools/built-in.ts +875 -0
  88. package/src/runtime/tools/vercel-ai.ts +269 -0
  89. package/src/runtime/tools.ts +60 -1255
  90. package/src/runtime/validation.ts +25 -0
  91. package/src/runtime/wrap-up.ts +257 -0
  92. package/src/types/benchmark.ts +300 -0
  93. package/src/types/events.ts +544 -0
  94. package/src/types/replay.ts +201 -0
  95. package/src/types.ts +174 -994
@@ -18,6 +18,7 @@ import type {
18
18
  Tier,
19
19
  TranscriptEntry
20
20
  } from "../types.js";
21
+ import { createRunId, elapsedMs, nowMs, providerCallIdFor } from "./ids.js";
21
22
  import {
22
23
  addCost,
23
24
  createReplayTraceBudget,
@@ -36,8 +37,9 @@ import {
36
37
  import { throwIfAborted } from "./cancellation.js";
37
38
  import { parseAgentDecision } from "./decisions.js";
38
39
  import { generateModelTurn } from "./model.js";
39
- import { evaluateTerminationStop } from "./termination.js";
40
+ import { evaluateTerminationStop, warnOnProtocolTerminationMisconfiguration } from "./termination.js";
40
41
  import { createRuntimeToolExecutor, executeModelResponseToolRequests, runtimeToolAvailability } from "./tools.js";
42
+ import { createWrapUpHintController } from "./wrap-up.js";
41
43
 
42
44
  interface SharedRunOptions {
43
45
  readonly intent: string;
@@ -51,6 +53,7 @@ interface SharedRunOptions {
51
53
  readonly seed?: string | number;
52
54
  readonly signal?: AbortSignal;
53
55
  readonly terminate?: TerminationCondition;
56
+ readonly wrapUpHint?: DogpileOptions["wrapUpHint"];
54
57
  readonly emit?: (event: RunEvent) => void;
55
58
  }
56
59
 
@@ -67,6 +70,15 @@ export async function runShared(options: SharedRunOptions): Promise<RunResult> {
67
70
  const startedAtMs = nowMs();
68
71
  let stopped = false;
69
72
  let termination: TerminationStopRecord | undefined;
73
+ const wrapUpHint = createWrapUpHintController({
74
+ protocol: options.protocol,
75
+ tier: options.tier,
76
+ ...(options.budget ? { budget: options.budget } : {}),
77
+ ...(options.terminate ? { terminate: options.terminate } : {}),
78
+ ...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {})
79
+ });
80
+
81
+ warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
70
82
 
71
83
  const emit = (event: RunEvent): void => {
72
84
  events.push(event);
@@ -126,16 +138,27 @@ export async function runShared(options: SharedRunOptions): Promise<RunResult> {
126
138
  turn,
127
139
  ...toolAvailability
128
140
  },
129
- messages: [
141
+ messages: wrapUpHint.inject(
142
+ [
143
+ {
144
+ role: "system",
145
+ content: buildSystemPrompt(agent)
146
+ },
147
+ {
148
+ role: "user",
149
+ content: input
150
+ }
151
+ ],
130
152
  {
131
- role: "system",
132
- content: buildSystemPrompt(agent)
133
- },
134
- {
135
- role: "user",
136
- content: input
153
+ runId,
154
+ protocol: "shared",
155
+ cost: totalCost,
156
+ events,
157
+ transcript,
158
+ iteration: transcript.length,
159
+ elapsedMs: elapsedMs(startedAtMs)
137
160
  }
138
- ]
161
+ )
139
162
  };
140
163
  const response = await generateModelTurn({
141
164
  model: options.model,
@@ -285,16 +308,20 @@ export async function runShared(options: SharedRunOptions): Promise<RunResult> {
285
308
  return stopped;
286
309
  }
287
310
 
288
- const stopRecord = evaluateTerminationStop(options.terminate, {
289
- runId,
290
- protocol: "shared",
291
- tier: options.tier,
292
- cost: totalCost,
293
- events,
294
- transcript,
295
- iteration: transcript.length,
296
- elapsedMs: elapsedMs(startedAtMs)
297
- });
311
+ const stopRecord = evaluateTerminationStop(
312
+ options.terminate,
313
+ wrapUpHint.context({
314
+ runId,
315
+ protocol: "shared",
316
+ protocolConfig: options.protocol,
317
+ protocolIteration: transcript.length,
318
+ cost: totalCost,
319
+ events,
320
+ transcript,
321
+ iteration: transcript.length,
322
+ elapsedMs: elapsedMs(startedAtMs)
323
+ })
324
+ );
298
325
 
299
326
  if (!stopRecord) {
300
327
  return false;
@@ -349,19 +376,3 @@ function responseCost(response: ModelResponse): CostSummary {
349
376
  };
350
377
  }
351
378
 
352
- function createRunId(): string {
353
- const random = globalThis.crypto?.randomUUID?.();
354
- return random ?? `run-${Date.now().toString(36)}`;
355
- }
356
-
357
- function nowMs(): number {
358
- return globalThis.performance?.now() ?? Date.now();
359
- }
360
-
361
- function elapsedMs(startedAtMs: number): number {
362
- return Math.max(0, nowMs() - startedAtMs);
363
- }
364
-
365
- function providerCallIdFor(runId: string, oneBasedIndex: number): string {
366
- return `${runId}:provider-call:${oneBasedIndex}`;
367
- }
@@ -1,7 +1,9 @@
1
1
  import type {
2
+ BroadcastProtocolConfig,
2
3
  BudgetStopReason,
3
4
  BudgetTerminationCondition,
4
5
  ConvergenceTerminationCondition,
6
+ CoordinatorProtocolConfig,
5
7
  FirstOfTerminationCondition,
6
8
  FirstOfTerminationConditions,
7
9
  FirstOfTerminationOutput,
@@ -10,6 +12,9 @@ import type {
10
12
  JudgeTerminationCondition,
11
13
  JsonObject,
12
14
  NormalizedStopReason,
15
+ ProtocolConfig,
16
+ SequentialProtocolConfig,
17
+ SharedProtocolConfig,
13
18
  TerminationStopRecord,
14
19
  StopTerminationDecision,
15
20
  TerminationCondition,
@@ -85,6 +90,10 @@ export function evaluateTermination(
85
90
  condition: TerminationCondition,
86
91
  context: TerminationEvaluationContext
87
92
  ): TerminationDecision {
93
+ if (isTerminationFloorBlocked(condition, context)) {
94
+ return { type: "continue", condition };
95
+ }
96
+
88
97
  switch (condition.kind) {
89
98
  case "budget":
90
99
  return evaluateBudget(condition, context);
@@ -166,6 +175,30 @@ export function evaluateTerminationStop(
166
175
  return stopRecord(condition, decision);
167
176
  }
168
177
 
178
+ /**
179
+ * Warn when a protocol-level termination floor cannot be satisfied because a
180
+ * lower iteration cap will stop the run first.
181
+ */
182
+ export function warnOnProtocolTerminationMisconfiguration(
183
+ protocol: ProtocolConfig,
184
+ terminate: TerminationCondition | undefined,
185
+ warn: (message: string) => void = console.warn
186
+ ): void {
187
+ const minTurns = protocolMinTurns(protocol);
188
+ if (minTurns === undefined || !terminate) {
189
+ return;
190
+ }
191
+
192
+ const limitingIterationBudget = smallestIterationBudget(terminate);
193
+ if (limitingIterationBudget === undefined || limitingIterationBudget >= minTurns) {
194
+ return;
195
+ }
196
+
197
+ warn(
198
+ `[dogpile] protocol.minTurns (${minTurns}) exceeds terminate budget maxIterations (${limitingIterationBudget}); maxIterations will win.`
199
+ );
200
+ }
201
+
169
202
  /**
170
203
  * Combine independently evaluated termination decisions with SDK precedence.
171
204
  *
@@ -384,6 +417,73 @@ function stopPrecedence(reason: NormalizedStopReason): number {
384
417
  return 2;
385
418
  }
386
419
 
420
+ function isTerminationFloorBlocked(condition: TerminationCondition, context: TerminationEvaluationContext): boolean {
421
+ if (condition.kind !== "convergence" && condition.kind !== "judge") {
422
+ return false;
423
+ }
424
+
425
+ const floor = protocolTerminationFloor(context.protocolConfig);
426
+ if (floor === undefined || floor <= 0) {
427
+ return false;
428
+ }
429
+
430
+ const progress = protocolProgress(context);
431
+ return progress < floor;
432
+ }
433
+
434
+ function protocolTerminationFloor(protocol: ProtocolConfig | undefined): number | undefined {
435
+ if (!protocol) {
436
+ return undefined;
437
+ }
438
+
439
+ switch (protocol.kind) {
440
+ case "broadcast":
441
+ return protocol.minRounds;
442
+ case "coordinator":
443
+ case "sequential":
444
+ case "shared":
445
+ return protocol.minTurns;
446
+ }
447
+ }
448
+
449
+ function protocolProgress(context: TerminationEvaluationContext): number {
450
+ return context.protocolIteration ?? context.iteration ?? context.transcript.length;
451
+ }
452
+
453
+ function protocolMinTurns(
454
+ protocol: ProtocolConfig
455
+ ): SequentialProtocolConfig["minTurns"] | CoordinatorProtocolConfig["minTurns"] | SharedProtocolConfig["minTurns"] {
456
+ switch (protocol.kind) {
457
+ case "broadcast":
458
+ return undefined;
459
+ case "coordinator":
460
+ case "sequential":
461
+ case "shared":
462
+ return protocol.minTurns;
463
+ }
464
+ }
465
+
466
+ function smallestIterationBudget(condition: TerminationCondition): number | undefined {
467
+ switch (condition.kind) {
468
+ case "budget":
469
+ return condition.maxIterations;
470
+ case "convergence":
471
+ case "judge":
472
+ return undefined;
473
+ case "firstOf": {
474
+ let smallest: number | undefined;
475
+ for (const child of condition.conditions) {
476
+ const budget = smallestIterationBudget(child);
477
+ if (budget === undefined) {
478
+ continue;
479
+ }
480
+ smallest = smallest === undefined ? budget : Math.min(smallest, budget);
481
+ }
482
+ return smallest;
483
+ }
484
+ }
485
+ }
486
+
387
487
  function judgeStopDetail(decision: JudgeEvaluationDecision, minScore?: number): JsonObject {
388
488
  return {
389
489
  decision: decision.type,