@dogpile/sdk 0.1.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 (88) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +16 -0
  3. package/README.md +842 -0
  4. package/dist/browser/index.d.ts +8 -0
  5. package/dist/browser/index.d.ts.map +1 -0
  6. package/dist/browser/index.js +4493 -0
  7. package/dist/browser/index.js.map +1 -0
  8. package/dist/index.d.ts +17 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +14 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/providers/openai-compatible.d.ts +44 -0
  13. package/dist/providers/openai-compatible.d.ts.map +1 -0
  14. package/dist/providers/openai-compatible.js +305 -0
  15. package/dist/providers/openai-compatible.js.map +1 -0
  16. package/dist/runtime/broadcast.d.ts +18 -0
  17. package/dist/runtime/broadcast.d.ts.map +1 -0
  18. package/dist/runtime/broadcast.js +335 -0
  19. package/dist/runtime/broadcast.js.map +1 -0
  20. package/dist/runtime/cancellation.d.ts +6 -0
  21. package/dist/runtime/cancellation.d.ts.map +1 -0
  22. package/dist/runtime/cancellation.js +35 -0
  23. package/dist/runtime/cancellation.js.map +1 -0
  24. package/dist/runtime/coordinator.d.ts +18 -0
  25. package/dist/runtime/coordinator.d.ts.map +1 -0
  26. package/dist/runtime/coordinator.js +434 -0
  27. package/dist/runtime/coordinator.js.map +1 -0
  28. package/dist/runtime/decisions.d.ts +5 -0
  29. package/dist/runtime/decisions.d.ts.map +1 -0
  30. package/dist/runtime/decisions.js +31 -0
  31. package/dist/runtime/decisions.js.map +1 -0
  32. package/dist/runtime/defaults.d.ts +63 -0
  33. package/dist/runtime/defaults.d.ts.map +1 -0
  34. package/dist/runtime/defaults.js +426 -0
  35. package/dist/runtime/defaults.js.map +1 -0
  36. package/dist/runtime/engine.d.ts +79 -0
  37. package/dist/runtime/engine.d.ts.map +1 -0
  38. package/dist/runtime/engine.js +723 -0
  39. package/dist/runtime/engine.js.map +1 -0
  40. package/dist/runtime/model.d.ts +14 -0
  41. package/dist/runtime/model.d.ts.map +1 -0
  42. package/dist/runtime/model.js +82 -0
  43. package/dist/runtime/model.js.map +1 -0
  44. package/dist/runtime/sequential.d.ts +18 -0
  45. package/dist/runtime/sequential.d.ts.map +1 -0
  46. package/dist/runtime/sequential.js +277 -0
  47. package/dist/runtime/sequential.js.map +1 -0
  48. package/dist/runtime/shared.d.ts +18 -0
  49. package/dist/runtime/shared.d.ts.map +1 -0
  50. package/dist/runtime/shared.js +288 -0
  51. package/dist/runtime/shared.js.map +1 -0
  52. package/dist/runtime/termination.d.ts +77 -0
  53. package/dist/runtime/termination.d.ts.map +1 -0
  54. package/dist/runtime/termination.js +355 -0
  55. package/dist/runtime/termination.js.map +1 -0
  56. package/dist/runtime/tools.d.ts +314 -0
  57. package/dist/runtime/tools.d.ts.map +1 -0
  58. package/dist/runtime/tools.js +969 -0
  59. package/dist/runtime/tools.js.map +1 -0
  60. package/dist/runtime/validation.d.ts +23 -0
  61. package/dist/runtime/validation.d.ts.map +1 -0
  62. package/dist/runtime/validation.js +656 -0
  63. package/dist/runtime/validation.js.map +1 -0
  64. package/dist/types.d.ts +2434 -0
  65. package/dist/types.d.ts.map +1 -0
  66. package/dist/types.js +81 -0
  67. package/dist/types.js.map +1 -0
  68. package/package.json +157 -0
  69. package/src/browser/index.ts +7 -0
  70. package/src/index.ts +195 -0
  71. package/src/providers/openai-compatible.ts +406 -0
  72. package/src/runtime/broadcast.test.ts +355 -0
  73. package/src/runtime/broadcast.ts +428 -0
  74. package/src/runtime/cancellation.ts +40 -0
  75. package/src/runtime/coordinator.test.ts +468 -0
  76. package/src/runtime/coordinator.ts +581 -0
  77. package/src/runtime/decisions.ts +38 -0
  78. package/src/runtime/defaults.ts +547 -0
  79. package/src/runtime/engine.ts +880 -0
  80. package/src/runtime/model.ts +117 -0
  81. package/src/runtime/sequential.test.ts +262 -0
  82. package/src/runtime/sequential.ts +357 -0
  83. package/src/runtime/shared.test.ts +265 -0
  84. package/src/runtime/shared.ts +367 -0
  85. package/src/runtime/termination.ts +463 -0
  86. package/src/runtime/tools.ts +1518 -0
  87. package/src/runtime/validation.ts +771 -0
  88. package/src/types.ts +2729 -0
@@ -0,0 +1,4493 @@
1
+ const dogpileErrorCodes = [
2
+ "invalid-configuration",
3
+ "aborted",
4
+ "timeout",
5
+ "provider-authentication",
6
+ "provider-invalid-request",
7
+ "provider-invalid-response",
8
+ "provider-not-found",
9
+ "provider-rate-limited",
10
+ "provider-timeout",
11
+ "provider-unavailable",
12
+ "provider-unsupported",
13
+ "provider-error",
14
+ "unknown"
15
+ ];
16
+ class DogpileErrorImpl extends Error {
17
+ name = "DogpileError";
18
+ /** Stable machine-readable error code. */
19
+ code;
20
+ /** Whether caller retry policy may safely retry the same operation. */
21
+ retryable;
22
+ /** Configured provider id associated with the failure, when available. */
23
+ providerId;
24
+ /** Optional serializable diagnostic detail. */
25
+ detail;
26
+ /** Original thrown value, if Dogpile wrapped a lower-level failure. */
27
+ cause;
28
+ constructor(options) {
29
+ super(options.message);
30
+ this.code = options.code;
31
+ if (options.retryable !== void 0) {
32
+ this.retryable = options.retryable;
33
+ }
34
+ if (options.providerId !== void 0) {
35
+ this.providerId = options.providerId;
36
+ }
37
+ if (options.detail !== void 0) {
38
+ this.detail = options.detail;
39
+ }
40
+ if (options.cause !== void 0) {
41
+ this.cause = options.cause;
42
+ }
43
+ Object.setPrototypeOf(this, new.target.prototype);
44
+ }
45
+ /**
46
+ * Cross-realm guard for Dogpile public errors.
47
+ */
48
+ static isInstance(error) {
49
+ if (error instanceof DogpileErrorImpl) {
50
+ return true;
51
+ }
52
+ if (!isRecord$2(error)) {
53
+ return false;
54
+ }
55
+ return error.name === "DogpileError" && isDogpileErrorCode(error.code) && typeof error.message === "string";
56
+ }
57
+ /**
58
+ * JSON-safe representation for logs, traces, and observability tools.
59
+ */
60
+ toJSON() {
61
+ return {
62
+ name: this.name,
63
+ code: this.code,
64
+ message: this.message,
65
+ ...this.retryable !== void 0 ? { retryable: this.retryable } : {},
66
+ ...this.providerId !== void 0 ? { providerId: this.providerId } : {},
67
+ ...this.detail !== void 0 ? { detail: this.detail } : {}
68
+ };
69
+ }
70
+ }
71
+ const DogpileError = DogpileErrorImpl;
72
+ function isDogpileErrorCode(value) {
73
+ return typeof value === "string" && dogpileErrorCodes.includes(value);
74
+ }
75
+ function isRecord$2(value) {
76
+ return typeof value === "object" && value !== null && !Array.isArray(value);
77
+ }
78
+ function normalizeProtocol(protocol) {
79
+ if (typeof protocol !== "string") {
80
+ return protocol;
81
+ }
82
+ switch (protocol) {
83
+ case "sequential":
84
+ return { kind: "sequential", maxTurns: 3 };
85
+ case "coordinator":
86
+ return { kind: "coordinator", maxTurns: 3 };
87
+ case "broadcast":
88
+ return { kind: "broadcast", maxRounds: 2 };
89
+ case "shared":
90
+ return { kind: "shared", maxTurns: 3 };
91
+ }
92
+ }
93
+ function defaultAgents() {
94
+ return [
95
+ { id: "agent-1", role: "planner", instructions: "Frame the mission and identify the important constraints." },
96
+ { id: "agent-2", role: "critic", instructions: "Stress-test the previous contribution and improve weak spots." },
97
+ { id: "agent-3", role: "synthesizer", instructions: "Produce the final useful answer from the accumulated work." }
98
+ ];
99
+ }
100
+ function orderAgentsForTemperature(agents, temperature, seed) {
101
+ if (temperature !== 0) {
102
+ return agents;
103
+ }
104
+ if (seed !== void 0) {
105
+ return [...agents].sort((left, right) => compareAgentsBySeededSelection(left, right, seed));
106
+ }
107
+ return [...agents].sort(compareAgentsByStableIdentity);
108
+ }
109
+ function compareAgentsBySeededSelection(left, right, seed) {
110
+ const leftScore = deterministicSelectionScore(seed, left);
111
+ const rightScore = deterministicSelectionScore(seed, right);
112
+ if (leftScore !== rightScore) {
113
+ return leftScore - rightScore;
114
+ }
115
+ return compareAgentsByStableIdentity(left, right);
116
+ }
117
+ function deterministicSelectionScore(seed, agent) {
118
+ return stableHash(`${String(seed)}\0${agent.id}\0${agent.role}\0${agent.instructions ?? ""}`);
119
+ }
120
+ function stableHash(input) {
121
+ let hash = 2166136261;
122
+ for (let index = 0; index < input.length; index += 1) {
123
+ hash ^= input.charCodeAt(index);
124
+ hash = Math.imul(hash, 16777619);
125
+ }
126
+ return hash >>> 0;
127
+ }
128
+ function compareAgentsByStableIdentity(left, right) {
129
+ const idOrder = left.id.localeCompare(right.id);
130
+ if (idOrder !== 0) {
131
+ return idOrder;
132
+ }
133
+ const roleOrder = left.role.localeCompare(right.role);
134
+ if (roleOrder !== 0) {
135
+ return roleOrder;
136
+ }
137
+ return (left.instructions ?? "").localeCompare(right.instructions ?? "");
138
+ }
139
+ function tierTemperature(tier) {
140
+ switch (tier) {
141
+ case "fast":
142
+ return 0;
143
+ case "balanced":
144
+ return 0.2;
145
+ case "quality":
146
+ return 0.4;
147
+ }
148
+ }
149
+ function emptyCost() {
150
+ return { usd: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0 };
151
+ }
152
+ function addCost(left, right) {
153
+ return {
154
+ usd: left.usd + right.usd,
155
+ inputTokens: left.inputTokens + right.inputTokens,
156
+ outputTokens: left.outputTokens + right.outputTokens,
157
+ totalTokens: left.totalTokens + right.totalTokens
158
+ };
159
+ }
160
+ function createTranscriptLink(transcript) {
161
+ return {
162
+ kind: "trace-transcript",
163
+ entryCount: transcript.length,
164
+ lastEntryIndex: transcript.length === 0 ? null : transcript.length - 1
165
+ };
166
+ }
167
+ function createRunEventLog(runId, protocol, events) {
168
+ return {
169
+ kind: "run-event-log",
170
+ runId,
171
+ protocol,
172
+ eventTypes: events.map((event) => event.type),
173
+ eventCount: events.length,
174
+ events
175
+ };
176
+ }
177
+ function createRunUsage(cost) {
178
+ return {
179
+ usd: cost.usd,
180
+ inputTokens: cost.inputTokens,
181
+ outputTokens: cost.outputTokens,
182
+ totalTokens: cost.totalTokens
183
+ };
184
+ }
185
+ function createRunAccounting(options) {
186
+ const usage = createRunUsage(options.cost);
187
+ return {
188
+ kind: "run-accounting",
189
+ tier: options.tier,
190
+ ...options.budget ? { budget: options.budget } : {},
191
+ ...options.termination ? { termination: options.termination } : {},
192
+ usage,
193
+ cost: options.cost,
194
+ budgetStateChanges: createReplayTraceBudgetStateChanges(options.events),
195
+ ...options.budget?.maxUsd !== void 0 ? { usdCapUtilization: options.budget.maxUsd === 0 ? 0 : options.cost.usd / options.budget.maxUsd } : {},
196
+ ...options.budget?.maxTokens !== void 0 ? {
197
+ totalTokenCapUtilization: options.budget.maxTokens === 0 ? 0 : options.cost.totalTokens / options.budget.maxTokens
198
+ } : {}
199
+ };
200
+ }
201
+ function createRunMetadata(options) {
202
+ const firstEvent = options.events[0];
203
+ const lastEvent = options.events.at(-1);
204
+ return {
205
+ runId: options.runId,
206
+ protocol: options.protocol,
207
+ tier: options.tier,
208
+ modelProviderId: options.modelProviderId,
209
+ agentsUsed: options.agentsUsed,
210
+ startedAt: firstEvent?.at ?? "",
211
+ completedAt: lastEvent?.at ?? ""
212
+ };
213
+ }
214
+ function createReplayTraceRunInputs(options) {
215
+ return {
216
+ kind: "replay-trace-run-inputs",
217
+ intent: options.intent,
218
+ protocol: options.protocol,
219
+ tier: options.tier,
220
+ modelProviderId: options.modelProviderId,
221
+ agents: options.agents,
222
+ temperature: options.temperature
223
+ };
224
+ }
225
+ function createReplayTraceBudget(options) {
226
+ return {
227
+ kind: "replay-trace-budget",
228
+ tier: options.tier,
229
+ ...options.caps ? { caps: options.caps } : {},
230
+ ...options.termination ? { termination: options.termination } : {}
231
+ };
232
+ }
233
+ function createReplayTraceBudgetStateChanges(events) {
234
+ return events.flatMap((event, eventIndex) => {
235
+ switch (event.type) {
236
+ case "agent-turn":
237
+ case "broadcast":
238
+ case "final":
239
+ return [
240
+ {
241
+ kind: "replay-trace-budget-state-change",
242
+ eventIndex,
243
+ eventType: event.type,
244
+ at: event.at,
245
+ cost: event.cost
246
+ }
247
+ ];
248
+ case "budget-stop":
249
+ return [
250
+ {
251
+ kind: "replay-trace-budget-state-change",
252
+ eventIndex,
253
+ eventType: event.type,
254
+ at: event.at,
255
+ cost: event.cost,
256
+ iteration: event.iteration,
257
+ elapsedMs: event.elapsedMs,
258
+ budgetReason: event.reason
259
+ }
260
+ ];
261
+ case "role-assignment":
262
+ case "model-request":
263
+ case "model-response":
264
+ case "model-output-chunk":
265
+ case "tool-call":
266
+ case "tool-result":
267
+ return [];
268
+ }
269
+ });
270
+ }
271
+ function createReplayTraceSeed(seed) {
272
+ if (seed === void 0) {
273
+ return {
274
+ kind: "replay-trace-seed",
275
+ source: "none",
276
+ value: null
277
+ };
278
+ }
279
+ return {
280
+ kind: "replay-trace-seed",
281
+ source: "caller",
282
+ value: seed
283
+ };
284
+ }
285
+ function createReplayTraceProtocolDecision(protocol, event, eventIndex, options = {}) {
286
+ const base = {
287
+ kind: "replay-trace-protocol-decision",
288
+ eventIndex,
289
+ eventType: event.type,
290
+ protocol,
291
+ decision: options.decision ?? defaultProtocolDecision(event),
292
+ at: event.at,
293
+ ...options.turn !== void 0 ? { turn: options.turn } : {},
294
+ ...options.phase !== void 0 ? { phase: options.phase } : {},
295
+ ...options.round !== void 0 ? { round: options.round } : {},
296
+ ...options.transcriptEntryCount !== void 0 ? { transcriptEntryCount: options.transcriptEntryCount } : {},
297
+ ...options.contributionCount !== void 0 ? { contributionCount: options.contributionCount } : {}
298
+ };
299
+ switch (event.type) {
300
+ case "role-assignment":
301
+ return {
302
+ ...base,
303
+ agentId: event.agentId,
304
+ role: event.role
305
+ };
306
+ case "model-request":
307
+ return {
308
+ ...base,
309
+ agentId: event.agentId,
310
+ role: event.role,
311
+ callId: event.callId,
312
+ providerId: event.providerId,
313
+ input: event.request.messages.map((message) => message.content).join("\n")
314
+ };
315
+ case "model-response":
316
+ return {
317
+ ...base,
318
+ agentId: event.agentId,
319
+ role: event.role,
320
+ callId: event.callId,
321
+ providerId: event.providerId,
322
+ output: event.response.text
323
+ };
324
+ case "model-output-chunk":
325
+ return {
326
+ ...base,
327
+ agentId: event.agentId,
328
+ role: event.role,
329
+ input: event.input,
330
+ output: event.output
331
+ };
332
+ case "tool-call":
333
+ return {
334
+ ...base,
335
+ toolCallId: event.toolCallId,
336
+ tool: event.tool,
337
+ input: stableJsonStringify(event.input),
338
+ ...eventAgentScope(event)
339
+ };
340
+ case "tool-result":
341
+ return {
342
+ ...base,
343
+ toolCallId: event.toolCallId,
344
+ tool: event.tool,
345
+ output: stableJsonStringify(event.result),
346
+ ...eventAgentScope(event)
347
+ };
348
+ case "agent-turn":
349
+ return {
350
+ ...base,
351
+ agentId: event.agentId,
352
+ role: event.role,
353
+ input: event.input,
354
+ output: event.output,
355
+ cost: event.cost
356
+ };
357
+ case "broadcast":
358
+ return {
359
+ ...base,
360
+ round: event.round,
361
+ contributionCount: options.contributionCount ?? event.contributions.length,
362
+ cost: event.cost
363
+ };
364
+ case "budget-stop":
365
+ return {
366
+ ...base,
367
+ cost: event.cost,
368
+ budgetReason: event.reason
369
+ };
370
+ case "final":
371
+ return {
372
+ ...base,
373
+ output: event.output,
374
+ cost: event.cost
375
+ };
376
+ }
377
+ }
378
+ function defaultProtocolDecision(event) {
379
+ switch (event.type) {
380
+ case "role-assignment":
381
+ return "assign-role";
382
+ case "model-request":
383
+ return "start-model-call";
384
+ case "model-response":
385
+ return "complete-model-call";
386
+ case "model-output-chunk":
387
+ return "observe-model-output";
388
+ case "tool-call":
389
+ return "start-tool-call";
390
+ case "tool-result":
391
+ return "complete-tool-call";
392
+ case "agent-turn":
393
+ return "select-agent-turn";
394
+ case "broadcast":
395
+ return "collect-broadcast-round";
396
+ case "budget-stop":
397
+ return "stop-for-budget";
398
+ case "final":
399
+ return "finalize-output";
400
+ }
401
+ }
402
+ function eventAgentScope(event) {
403
+ return {
404
+ ...event.agentId !== void 0 ? { agentId: event.agentId } : {},
405
+ ...event.role !== void 0 ? { role: event.role } : {}
406
+ };
407
+ }
408
+ function createReplayTraceFinalOutput(output, event) {
409
+ if (event.type === "final") {
410
+ return {
411
+ kind: "replay-trace-final-output",
412
+ output,
413
+ cost: event.cost,
414
+ completedAt: event.at,
415
+ transcript: event.transcript
416
+ };
417
+ }
418
+ return {
419
+ kind: "replay-trace-final-output",
420
+ output,
421
+ cost: emptyCost(),
422
+ completedAt: event.at,
423
+ transcript: {
424
+ kind: "trace-transcript",
425
+ entryCount: 0,
426
+ lastEntryIndex: null
427
+ }
428
+ };
429
+ }
430
+ function nextProviderCallId(runId, providerCalls) {
431
+ return `${runId}:provider-call:${providerCalls.length + 1}`;
432
+ }
433
+ function canonicalizeRunResult(result) {
434
+ const trace = canonicalizeSerializable(result.trace);
435
+ const eventLog = {
436
+ eventCount: trace.events.length,
437
+ eventTypes: trace.events.map((event) => event.type),
438
+ events: trace.events,
439
+ kind: "run-event-log",
440
+ protocol: trace.protocol,
441
+ runId: trace.runId
442
+ };
443
+ const canonicalResult = {
444
+ accounting: canonicalizeSerializable(result.accounting),
445
+ cost: canonicalizeSerializable(result.cost),
446
+ ...result.evaluation !== void 0 ? { evaluation: canonicalizeSerializable(result.evaluation) } : {},
447
+ eventLog,
448
+ metadata: canonicalizeSerializable(result.metadata),
449
+ output: result.output,
450
+ ...result.quality !== void 0 ? { quality: canonicalizeSerializable(result.quality) } : {},
451
+ trace,
452
+ transcript: trace.transcript,
453
+ usage: canonicalizeSerializable(result.usage)
454
+ };
455
+ return canonicalResult;
456
+ }
457
+ function stableJsonStringify(value) {
458
+ return JSON.stringify(canonicalizeSerializable(value));
459
+ }
460
+ function canonicalizeSerializable(value) {
461
+ if (Array.isArray(value)) {
462
+ return value.map((item) => canonicalizeSerializable(item));
463
+ }
464
+ if (typeof value === "number") {
465
+ if (Object.is(value, -0)) {
466
+ return 0;
467
+ }
468
+ if (!Number.isFinite(value)) {
469
+ return null;
470
+ }
471
+ return value;
472
+ }
473
+ if (value === null || typeof value !== "object") {
474
+ return value;
475
+ }
476
+ const input = value;
477
+ const output = {};
478
+ for (const key of Object.keys(input).sort()) {
479
+ const child = input[key];
480
+ if (child !== void 0) {
481
+ output[key] = canonicalizeSerializable(child);
482
+ }
483
+ }
484
+ return output;
485
+ }
486
+ function throwIfAborted(signal, providerId) {
487
+ if (!signal?.aborted) {
488
+ return;
489
+ }
490
+ throw createAbortErrorFromSignal(signal, providerId);
491
+ }
492
+ function createAbortError(providerId, detail, cause) {
493
+ return new DogpileError({
494
+ code: "aborted",
495
+ message: "The operation was aborted.",
496
+ retryable: false,
497
+ providerId,
498
+ ...{},
499
+ ...cause !== void 0 ? { cause } : {}
500
+ });
501
+ }
502
+ function createAbortErrorFromSignal(signal, providerId) {
503
+ if (DogpileError.isInstance(signal.reason)) {
504
+ return signal.reason;
505
+ }
506
+ return createAbortError(providerId, void 0, signal.reason);
507
+ }
508
+ function createTimeoutError(providerId, timeoutMs) {
509
+ return new DogpileError({
510
+ code: "timeout",
511
+ message: `The operation timed out after ${timeoutMs}ms.`,
512
+ retryable: true,
513
+ providerId,
514
+ detail: {
515
+ timeoutMs
516
+ }
517
+ });
518
+ }
519
+ function parseAgentDecision(output) {
520
+ const selectedRole = matchLine(output, /^role_selected:\s*(.+)$/imu);
521
+ const participation = matchLine(output, /^participation:\s*(contribute|abstain)$/imu);
522
+ const rationale = matchLine(output, /^rationale:\s*(.+)$/imu);
523
+ const contribution = matchContribution(output);
524
+ if (!selectedRole || !participation || !isAgentParticipation(participation) || !rationale || !contribution) {
525
+ return void 0;
526
+ }
527
+ return {
528
+ selectedRole,
529
+ participation,
530
+ rationale,
531
+ contribution
532
+ };
533
+ }
534
+ function isParticipatingDecision(decision) {
535
+ return decision?.participation !== "abstain";
536
+ }
537
+ function matchLine(output, pattern) {
538
+ const match = output.match(pattern);
539
+ return match?.[1]?.trim();
540
+ }
541
+ function matchContribution(output) {
542
+ const match = output.match(/^contribution:\s*\n([\s\S]*)$/imu);
543
+ const contribution = match?.[1]?.trim();
544
+ return contribution && contribution.length > 0 ? contribution : void 0;
545
+ }
546
+ function isAgentParticipation(value) {
547
+ return value === "contribute" || value === "abstain";
548
+ }
549
+ async function generateModelTurn(options) {
550
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
551
+ let response;
552
+ throwIfAborted(options.request.signal, options.model.id);
553
+ if (!options.model.stream) {
554
+ response = await options.model.generate(options.request);
555
+ throwIfAborted(options.request.signal, options.model.id);
556
+ recordProviderCall(response, startedAt, options);
557
+ return response;
558
+ }
559
+ let text = "";
560
+ let chunkIndex = 0;
561
+ let usage;
562
+ let costUsd;
563
+ let finishReason;
564
+ let toolRequests;
565
+ let metadata;
566
+ for await (const chunk of options.model.stream(options.request)) {
567
+ throwIfAborted(options.request.signal, options.model.id);
568
+ text += chunk.text;
569
+ options.emit({
570
+ type: "model-output-chunk",
571
+ runId: options.runId,
572
+ at: (/* @__PURE__ */ new Date()).toISOString(),
573
+ agentId: options.agent.id,
574
+ role: options.agent.role,
575
+ input: options.input,
576
+ chunkIndex,
577
+ text: chunk.text,
578
+ output: text
579
+ });
580
+ chunkIndex += 1;
581
+ if (chunk.usage) {
582
+ usage = chunk.usage;
583
+ }
584
+ if (chunk.costUsd !== void 0) {
585
+ costUsd = chunk.costUsd;
586
+ }
587
+ if (chunk.finishReason !== void 0) {
588
+ finishReason = chunk.finishReason;
589
+ }
590
+ if (chunk.toolRequests !== void 0) {
591
+ toolRequests = chunk.toolRequests;
592
+ }
593
+ if (chunk.metadata !== void 0) {
594
+ metadata = chunk.metadata;
595
+ }
596
+ }
597
+ response = {
598
+ text,
599
+ ...finishReason !== void 0 ? { finishReason } : {},
600
+ ...toolRequests && toolRequests.length > 0 ? { toolRequests } : {},
601
+ ...usage ? { usage } : {},
602
+ ...costUsd !== void 0 ? { costUsd } : {},
603
+ ...metadata !== void 0 ? { metadata } : {}
604
+ };
605
+ throwIfAborted(options.request.signal, options.model.id);
606
+ recordProviderCall(response, startedAt, options);
607
+ return response;
608
+ }
609
+ function recordProviderCall(response, startedAt, options) {
610
+ options.onProviderCall?.({
611
+ kind: "replay-trace-provider-call",
612
+ callId: options.callId,
613
+ providerId: options.model.id,
614
+ startedAt,
615
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
616
+ agentId: options.agent.id,
617
+ role: options.agent.role,
618
+ request: requestForTrace(options.request),
619
+ response
620
+ });
621
+ }
622
+ function requestForTrace(request) {
623
+ return {
624
+ messages: request.messages,
625
+ temperature: request.temperature,
626
+ metadata: request.metadata
627
+ };
628
+ }
629
+ function budget(options) {
630
+ return {
631
+ kind: "budget",
632
+ ...options
633
+ };
634
+ }
635
+ function convergence(options) {
636
+ return {
637
+ kind: "convergence",
638
+ ...options
639
+ };
640
+ }
641
+ function judge(options) {
642
+ return {
643
+ kind: "judge",
644
+ ...options
645
+ };
646
+ }
647
+ function firstOf(...conditions) {
648
+ if (conditions.length === 0) {
649
+ throw new RangeError("firstOf requires at least one termination condition.");
650
+ }
651
+ return {
652
+ kind: "firstOf",
653
+ conditions
654
+ };
655
+ }
656
+ function evaluateTermination(condition, context) {
657
+ switch (condition.kind) {
658
+ case "budget":
659
+ return evaluateBudget(condition, context);
660
+ case "firstOf":
661
+ return evaluateFirstOf(condition, context).decision;
662
+ case "convergence":
663
+ return evaluateConvergence(condition, context);
664
+ case "judge":
665
+ return evaluateJudge(condition, context);
666
+ }
667
+ }
668
+ function evaluateFirstOf(condition, context) {
669
+ const evaluated = [];
670
+ for (const [index, child] of condition.conditions.entries()) {
671
+ const decision = evaluateTermination(child, context);
672
+ evaluated.push(decision);
673
+ if (decision.type === "stop") {
674
+ return {
675
+ kind: "firstOf-output",
676
+ decision,
677
+ winningConditionIndex: index,
678
+ evaluated
679
+ };
680
+ }
681
+ }
682
+ return {
683
+ kind: "firstOf-output",
684
+ decision: { type: "continue", condition },
685
+ winningConditionIndex: null,
686
+ evaluated
687
+ };
688
+ }
689
+ function evaluateTerminationStop(condition, context) {
690
+ if (condition.kind === "firstOf") {
691
+ const output = evaluateFirstOf(condition, context);
692
+ if (output.decision.type !== "stop" || output.winningConditionIndex === null) {
693
+ return null;
694
+ }
695
+ const winningCondition = condition.conditions[output.winningConditionIndex];
696
+ if (!winningCondition) {
697
+ throw new RangeError("firstOf stop referenced a missing winning condition.");
698
+ }
699
+ return stopRecord(condition, output.decision, {
700
+ kind: "firstOf-stop",
701
+ winningConditionIndex: output.winningConditionIndex,
702
+ winningCondition,
703
+ firedCondition: output.decision.condition,
704
+ evaluated: output.evaluated
705
+ });
706
+ }
707
+ const decision = evaluateTermination(condition, context);
708
+ if (decision.type !== "stop") {
709
+ return null;
710
+ }
711
+ return stopRecord(condition, decision);
712
+ }
713
+ function combineTerminationDecisions(decisions) {
714
+ const stopDecisions = decisions.filter((decision) => decision.type === "stop");
715
+ if (stopDecisions.length === 0) {
716
+ const firstDecision = decisions[0];
717
+ if (!firstDecision) {
718
+ throw new RangeError("combineTerminationDecisions requires at least one decision.");
719
+ }
720
+ return firstDecision;
721
+ }
722
+ return stopDecisions.reduce(
723
+ (winner, candidate) => stopPrecedence(candidate.normalizedReason) < stopPrecedence(winner.normalizedReason) ? candidate : winner
724
+ );
725
+ }
726
+ function evaluateBudget(condition, context) {
727
+ const iteration = context.iteration ?? context.transcript.length;
728
+ const elapsedMs2 = context.elapsedMs ?? 0;
729
+ const costStop = stopIfReached(condition, "maxUsd", "cost", context.cost.usd);
730
+ if (costStop) {
731
+ return costStop;
732
+ }
733
+ const tokenStop = stopIfReached(condition, "maxTokens", "tokens", context.cost.totalTokens);
734
+ if (tokenStop) {
735
+ return tokenStop;
736
+ }
737
+ const iterationStop = stopIfReached(condition, "maxIterations", "iterations", iteration);
738
+ if (iterationStop) {
739
+ return iterationStop;
740
+ }
741
+ const timeoutStop = stopIfReached(condition, "timeoutMs", "timeout", elapsedMs2);
742
+ if (timeoutStop) {
743
+ return timeoutStop;
744
+ }
745
+ return { type: "continue", condition };
746
+ }
747
+ function evaluateConvergence(condition, context) {
748
+ const stableTurns = Math.max(1, Math.ceil(condition.stableTurns));
749
+ if (context.transcript.length < stableTurns) {
750
+ return { type: "continue", condition };
751
+ }
752
+ const recentEntries = context.transcript.slice(-stableTurns);
753
+ const recentOutputs = recentEntries.map((entry) => entry.output);
754
+ const similarities = consecutiveSimilarities(recentEntries);
755
+ const observedSimilarity = similarities.length === 0 ? 1 : Math.min(...similarities);
756
+ if (observedSimilarity < condition.minSimilarity) {
757
+ return { type: "continue", condition };
758
+ }
759
+ return {
760
+ type: "stop",
761
+ condition,
762
+ reason: "convergence",
763
+ normalizedReason: "convergence",
764
+ detail: {
765
+ protocol: context.protocol,
766
+ stableTurns,
767
+ minSimilarity: condition.minSimilarity,
768
+ observedSimilarity,
769
+ outputs: recentOutputs
770
+ }
771
+ };
772
+ }
773
+ function evaluateJudge(condition, context) {
774
+ const decision = context.judgeDecision ?? scoreDecisionFromQuality(context.quality);
775
+ if (!decision) {
776
+ return { type: "continue", condition };
777
+ }
778
+ switch (decision.type) {
779
+ case "accept":
780
+ return judgeStop(condition, "accepted", decision);
781
+ case "reject":
782
+ return judgeStop(condition, "rejected", decision);
783
+ case "score": {
784
+ const minScore = condition.minScore;
785
+ if (minScore !== void 0 && decision.score < minScore) {
786
+ return { type: "continue", condition };
787
+ }
788
+ return judgeStop(condition, "score-threshold", decision, minScore);
789
+ }
790
+ }
791
+ }
792
+ function stopIfReached(condition, cap, reason, observed) {
793
+ const limit = condition[cap];
794
+ if (limit === void 0 || observed < limit) {
795
+ return null;
796
+ }
797
+ return {
798
+ type: "stop",
799
+ condition,
800
+ reason: "budget",
801
+ normalizedReason: normalizeBudgetStopReason(reason),
802
+ budgetReason: reason,
803
+ detail: {
804
+ cap,
805
+ limit,
806
+ observed
807
+ }
808
+ };
809
+ }
810
+ function scoreDecisionFromQuality(quality) {
811
+ if (quality === void 0) {
812
+ return null;
813
+ }
814
+ return {
815
+ type: "score",
816
+ score: quality
817
+ };
818
+ }
819
+ function judgeStop(condition, judgeReason, decision, minScore) {
820
+ return {
821
+ type: "stop",
822
+ condition,
823
+ reason: "judge",
824
+ normalizedReason: normalizeJudgeStopReason(judgeReason),
825
+ judgeReason,
826
+ detail: judgeStopDetail(decision, minScore)
827
+ };
828
+ }
829
+ function normalizeBudgetStopReason(reason) {
830
+ switch (reason) {
831
+ case "cost":
832
+ return "budget:cost";
833
+ case "tokens":
834
+ return "budget:tokens";
835
+ case "iterations":
836
+ return "budget:iterations";
837
+ case "timeout":
838
+ return "budget:timeout";
839
+ }
840
+ }
841
+ function normalizeJudgeStopReason(reason) {
842
+ switch (reason) {
843
+ case "accepted":
844
+ return "judge:accepted";
845
+ case "rejected":
846
+ return "judge:rejected";
847
+ case "score-threshold":
848
+ return "judge:score-threshold";
849
+ }
850
+ }
851
+ function stopPrecedence(reason) {
852
+ if (reason.startsWith("budget:")) {
853
+ return 0;
854
+ }
855
+ if (reason.startsWith("judge:")) {
856
+ return 1;
857
+ }
858
+ return 2;
859
+ }
860
+ function judgeStopDetail(decision, minScore) {
861
+ return {
862
+ decision: decision.type,
863
+ ...decision.score !== void 0 ? { score: decision.score } : {},
864
+ ...minScore !== void 0 ? { minScore } : {},
865
+ ...decision.rationale !== void 0 ? { rationale: decision.rationale } : {},
866
+ ...decision.metadata !== void 0 ? { metadata: decision.metadata } : {}
867
+ };
868
+ }
869
+ function stopRecord(rootCondition, decision, firstOfRecord) {
870
+ return {
871
+ kind: "termination-stop",
872
+ rootCondition,
873
+ firedCondition: decision.condition,
874
+ reason: decision.reason,
875
+ normalizedReason: decision.normalizedReason,
876
+ ...decision.budgetReason !== void 0 ? { budgetReason: decision.budgetReason } : {},
877
+ ...decision.judgeReason !== void 0 ? { judgeReason: decision.judgeReason } : {},
878
+ ...decision.detail !== void 0 ? { detail: decision.detail } : {},
879
+ ...firstOfRecord !== void 0 ? { firstOf: firstOfRecord } : {}
880
+ };
881
+ }
882
+ function consecutiveSimilarities(entries) {
883
+ const similarities = [];
884
+ for (let index = 1; index < entries.length; index += 1) {
885
+ const previous = entries[index - 1];
886
+ const current = entries[index];
887
+ if (previous && current) {
888
+ similarities.push(outputSimilarity(previous.output, current.output));
889
+ }
890
+ }
891
+ return similarities;
892
+ }
893
+ function outputSimilarity(left, right) {
894
+ const normalizedLeft = normalizeOutput(left);
895
+ const normalizedRight = normalizeOutput(right);
896
+ if (normalizedLeft === normalizedRight) {
897
+ return 1;
898
+ }
899
+ const leftTokens = tokenize(normalizedLeft);
900
+ const rightTokens = tokenize(normalizedRight);
901
+ if (leftTokens.length === 0 || rightTokens.length === 0) {
902
+ return 0;
903
+ }
904
+ const leftSet = new Set(leftTokens);
905
+ const rightSet = new Set(rightTokens);
906
+ let intersection = 0;
907
+ for (const token of leftSet) {
908
+ if (rightSet.has(token)) {
909
+ intersection += 1;
910
+ }
911
+ }
912
+ const union = (/* @__PURE__ */ new Set([...leftSet, ...rightSet])).size;
913
+ return union === 0 ? 0 : intersection / union;
914
+ }
915
+ function normalizeOutput(output) {
916
+ return output.trim().toLowerCase();
917
+ }
918
+ function tokenize(output) {
919
+ return output.split(/[^a-z0-9]+/u).filter((token) => token.length > 0);
920
+ }
921
+ const protocolNames = ["coordinator", "sequential", "broadcast", "shared"];
922
+ const budgetTiers = ["fast", "balanced", "quality"];
923
+ function validateDogpileOptions(options) {
924
+ requireRecord(options, "options");
925
+ validateMissionIntent(options.intent);
926
+ if (options.protocol !== void 0) {
927
+ validateProtocolSelection(options.protocol, "protocol");
928
+ }
929
+ if (options.tier !== void 0) {
930
+ validateBudgetTier(options.tier, "tier");
931
+ }
932
+ validateModelProviderRegistration(options.model, "model");
933
+ validateOptionalAgents(options.agents, "agents");
934
+ validateOptionalRuntimeTools(options.tools, "tools");
935
+ validateOptionalTemperature(options.temperature, "temperature");
936
+ validateOptionalBudgetCaps(options.budget, "budget");
937
+ validateOptionalTerminationCondition(options.terminate, "terminate");
938
+ validateOptionalFunction(options.evaluate, "evaluate");
939
+ validateOptionalSeed(options.seed, "seed");
940
+ validateOptionalAbortSignal(options.signal, "signal");
941
+ }
942
+ function validateMissionIntent(intent, path = "intent") {
943
+ validateNonEmptyString(intent, path, "intent is required.");
944
+ }
945
+ function validateEngineOptions(options) {
946
+ requireRecord(options, "options");
947
+ validateProtocolSelection(options.protocol, "protocol");
948
+ validateBudgetTier(options.tier, "tier");
949
+ validateModelProviderRegistration(options.model, "model");
950
+ validateOptionalAgents(options.agents, "agents");
951
+ validateOptionalRuntimeTools(options.tools, "tools");
952
+ validateOptionalTemperature(options.temperature, "temperature");
953
+ validateOptionalBudgetCaps(options.budget, "budget");
954
+ validateOptionalTerminationCondition(options.terminate, "terminate");
955
+ validateOptionalFunction(options.evaluate, "evaluate");
956
+ validateOptionalSeed(options.seed, "seed");
957
+ validateOptionalAbortSignal(options.signal, "signal");
958
+ }
959
+ function validateProtocolSelection(value, path) {
960
+ if (typeof value === "string") {
961
+ if (!isProtocolName(value)) {
962
+ invalidConfiguration({
963
+ path,
964
+ rule: "enum",
965
+ message: "protocol must be one of coordinator, sequential, broadcast, or shared.",
966
+ expected: protocolNames.join(" | "),
967
+ actual: value
968
+ });
969
+ }
970
+ return;
971
+ }
972
+ validateProtocolConfig(value, path);
973
+ }
974
+ function validateProtocolConfig(value, path) {
975
+ const record = requireRecord(value, path);
976
+ const kind = record.kind;
977
+ if (!isProtocolName(kind)) {
978
+ invalidConfiguration({
979
+ path: `${path}.kind`,
980
+ rule: "enum",
981
+ message: "protocol config kind must be one of coordinator, sequential, broadcast, or shared.",
982
+ expected: protocolNames.join(" | "),
983
+ actual: kind
984
+ });
985
+ }
986
+ switch (kind) {
987
+ case "coordinator":
988
+ case "sequential":
989
+ case "shared":
990
+ validateOptionalPositiveInteger(record.maxTurns, `${path}.maxTurns`);
991
+ if (kind === "shared") {
992
+ validateOptionalString(record.organizationalMemory, `${path}.organizationalMemory`);
993
+ }
994
+ return;
995
+ case "broadcast":
996
+ validateOptionalPositiveInteger(record.maxRounds, `${path}.maxRounds`);
997
+ return;
998
+ }
999
+ }
1000
+ function validateBudgetTier(value, path) {
1001
+ if (!isBudgetTier(value)) {
1002
+ invalidConfiguration({
1003
+ path,
1004
+ rule: "enum",
1005
+ message: "tier must be one of fast, balanced, or quality.",
1006
+ expected: budgetTiers.join(" | "),
1007
+ actual: value
1008
+ });
1009
+ }
1010
+ }
1011
+ function validateModelProviderRegistration(value, path = "model") {
1012
+ const record = requireRecord(value, path);
1013
+ validateNonEmptyString(record.id, `${path}.id`, "model.id is required.");
1014
+ validateFunction(record.generate, `${path}.generate`);
1015
+ validateOptionalFunction(record.stream, `${path}.stream`);
1016
+ }
1017
+ function validateOptionalAgents(value, path) {
1018
+ if (value === void 0) {
1019
+ return;
1020
+ }
1021
+ if (!Array.isArray(value)) {
1022
+ invalidConfiguration({
1023
+ path,
1024
+ rule: "array",
1025
+ message: "agents must be an array when provided.",
1026
+ expected: "readonly AgentSpec[]",
1027
+ actual: value
1028
+ });
1029
+ }
1030
+ if (value.length === 0) {
1031
+ invalidConfiguration({
1032
+ path,
1033
+ rule: "array",
1034
+ message: "agents must contain at least one participant when provided.",
1035
+ expected: "non-empty readonly AgentSpec[]",
1036
+ actual: value
1037
+ });
1038
+ }
1039
+ value.forEach((agent, index) => {
1040
+ const agentPath = `${path}[${index}]`;
1041
+ const record = requireRecord(agent, agentPath);
1042
+ validateNonEmptyString(record.id, `${agentPath}.id`, "agent.id is required.");
1043
+ validateNonEmptyString(record.role, `${agentPath}.role`, "agent.role is required.");
1044
+ validateOptionalString(record.instructions, `${agentPath}.instructions`);
1045
+ });
1046
+ }
1047
+ function validateOptionalRuntimeTools(value, path) {
1048
+ if (value === void 0) {
1049
+ return;
1050
+ }
1051
+ validateRuntimeToolRegistrations(value, path);
1052
+ }
1053
+ function validateRuntimeToolRegistrations(value, path = "tools") {
1054
+ if (!Array.isArray(value)) {
1055
+ invalidConfiguration({
1056
+ path,
1057
+ rule: "array",
1058
+ message: "tools must be an array when provided.",
1059
+ expected: "readonly RuntimeTool[]",
1060
+ actual: value
1061
+ });
1062
+ }
1063
+ value.forEach((tool, index) => validateRuntimeTool(tool, `${path}[${index}]`));
1064
+ }
1065
+ function validateRuntimeTool(value, path) {
1066
+ const record = requireRecord(value, path);
1067
+ const identity = requireRecord(record.identity, `${path}.identity`);
1068
+ validateNonEmptyString(identity.id, `${path}.identity.id`, "tool identity id is required.");
1069
+ validateNonEmptyString(identity.name, `${path}.identity.name`, "tool identity name is required.");
1070
+ validateOptionalString(identity.namespace, `${path}.identity.namespace`);
1071
+ validateOptionalString(identity.version, `${path}.identity.version`);
1072
+ validateOptionalString(identity.description, `${path}.identity.description`);
1073
+ const inputSchema = requireRecord(record.inputSchema, `${path}.inputSchema`);
1074
+ if (inputSchema.kind !== "json-schema") {
1075
+ invalidConfiguration({
1076
+ path: `${path}.inputSchema.kind`,
1077
+ rule: "runtime-tool",
1078
+ message: "tool inputSchema.kind must be json-schema.",
1079
+ expected: "json-schema",
1080
+ actual: inputSchema.kind
1081
+ });
1082
+ }
1083
+ validateJsonObject(inputSchema.schema, `${path}.inputSchema.schema`);
1084
+ validateOptionalString(inputSchema.description, `${path}.inputSchema.description`);
1085
+ validateOptionalArray(record.permissions, `${path}.permissions`);
1086
+ validateOptionalFunction(record.validateInput, `${path}.validateInput`);
1087
+ validateFunction(record.execute, `${path}.execute`);
1088
+ }
1089
+ function validateOptionalBudgetCaps(value, path) {
1090
+ if (value === void 0) {
1091
+ return;
1092
+ }
1093
+ validateBudgetCaps(value, path);
1094
+ }
1095
+ function validateBudgetCaps(value, path) {
1096
+ const record = requireRecord(value, path);
1097
+ validateOptionalNonNegativeNumber(record.maxUsd, `${path}.maxUsd`);
1098
+ validateOptionalNonNegativeInteger(record.maxTokens, `${path}.maxTokens`);
1099
+ validateOptionalNonNegativeInteger(record.maxIterations, `${path}.maxIterations`);
1100
+ validateOptionalNonNegativeInteger(record.timeoutMs, `${path}.timeoutMs`);
1101
+ validateOptionalNumberInRange(record.qualityWeight, `${path}.qualityWeight`, 0, 1);
1102
+ }
1103
+ function validateOptionalTerminationCondition(value, path) {
1104
+ if (value === void 0) {
1105
+ return;
1106
+ }
1107
+ validateTerminationCondition(value, path, /* @__PURE__ */ new Set());
1108
+ }
1109
+ function validateTerminationCondition(value, path, stack) {
1110
+ const record = requireRecord(value, path);
1111
+ if (stack.has(record)) {
1112
+ invalidConfiguration({
1113
+ path,
1114
+ rule: "termination-condition",
1115
+ message: "termination conditions must not contain cycles.",
1116
+ expected: "acyclic termination condition",
1117
+ actual: value
1118
+ });
1119
+ }
1120
+ stack.add(record);
1121
+ try {
1122
+ switch (record.kind) {
1123
+ case "budget":
1124
+ validateBudgetCaps(record, path);
1125
+ return;
1126
+ case "convergence":
1127
+ validatePositiveInteger(record.stableTurns, `${path}.stableTurns`);
1128
+ validateNumberInRange(record.minSimilarity, `${path}.minSimilarity`, 0, 1);
1129
+ return;
1130
+ case "judge":
1131
+ validateJudgeRubric(record.rubric, `${path}.rubric`);
1132
+ validateOptionalNumberInRange(record.minScore, `${path}.minScore`, 0, 1);
1133
+ return;
1134
+ case "firstOf":
1135
+ validateFirstOfConditions(record.conditions, `${path}.conditions`, stack);
1136
+ return;
1137
+ default:
1138
+ invalidConfiguration({
1139
+ path: `${path}.kind`,
1140
+ rule: "termination-condition",
1141
+ message: "termination condition kind must be budget, convergence, judge, or firstOf.",
1142
+ expected: "budget | convergence | judge | firstOf",
1143
+ actual: record.kind
1144
+ });
1145
+ }
1146
+ } finally {
1147
+ stack.delete(record);
1148
+ }
1149
+ }
1150
+ function validateFirstOfConditions(value, path, stack) {
1151
+ if (!Array.isArray(value)) {
1152
+ invalidConfiguration({
1153
+ path,
1154
+ rule: "array",
1155
+ message: "firstOf conditions must be a non-empty array.",
1156
+ expected: "non-empty termination condition array",
1157
+ actual: value
1158
+ });
1159
+ }
1160
+ if (value.length === 0) {
1161
+ invalidConfiguration({
1162
+ path,
1163
+ rule: "array",
1164
+ message: "firstOf conditions must contain at least one condition.",
1165
+ expected: "non-empty termination condition array",
1166
+ actual: value
1167
+ });
1168
+ }
1169
+ value.forEach((condition, index) => {
1170
+ validateTerminationCondition(condition, `${path}[${index}]`, stack);
1171
+ });
1172
+ }
1173
+ function validateJudgeRubric(value, path) {
1174
+ if (typeof value === "string") {
1175
+ validateNonEmptyString(value, path, "judge rubric must not be empty.");
1176
+ return;
1177
+ }
1178
+ validateJsonObject(value, path);
1179
+ }
1180
+ function validateOptionalTemperature(value, path) {
1181
+ validateOptionalNumberInRange(value, path, 0, 2);
1182
+ }
1183
+ function validateOptionalSeed(value, path) {
1184
+ if (value === void 0) {
1185
+ return;
1186
+ }
1187
+ if (typeof value === "string") {
1188
+ return;
1189
+ }
1190
+ if (typeof value === "number" && Number.isFinite(value)) {
1191
+ return;
1192
+ }
1193
+ invalidConfiguration({
1194
+ path,
1195
+ rule: "finite-number",
1196
+ message: "seed must be a string or finite number when provided.",
1197
+ expected: "string or finite number",
1198
+ actual: value
1199
+ });
1200
+ }
1201
+ function validateJsonObject(value, path) {
1202
+ if (!isJsonValue$1(value, /* @__PURE__ */ new Set()) || !isRecord$1(value)) {
1203
+ invalidConfiguration({
1204
+ path,
1205
+ rule: "json-object",
1206
+ message: "value must be a JSON-compatible object.",
1207
+ expected: "JSON-compatible object",
1208
+ actual: value
1209
+ });
1210
+ }
1211
+ }
1212
+ function isJsonValue$1(value, stack) {
1213
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
1214
+ return true;
1215
+ }
1216
+ if (typeof value === "number") {
1217
+ return Number.isFinite(value);
1218
+ }
1219
+ if (Array.isArray(value)) {
1220
+ if (stack.has(value)) {
1221
+ return false;
1222
+ }
1223
+ stack.add(value);
1224
+ const valid = value.every((child) => isJsonValue$1(child, stack));
1225
+ stack.delete(value);
1226
+ return valid;
1227
+ }
1228
+ if (isRecord$1(value)) {
1229
+ if (stack.has(value)) {
1230
+ return false;
1231
+ }
1232
+ stack.add(value);
1233
+ const valid = Object.values(value).every((child) => isJsonValue$1(child, stack));
1234
+ stack.delete(value);
1235
+ return valid;
1236
+ }
1237
+ return false;
1238
+ }
1239
+ function validateOptionalString(value, path) {
1240
+ if (value === void 0) {
1241
+ return;
1242
+ }
1243
+ if (typeof value !== "string") {
1244
+ invalidConfiguration({
1245
+ path,
1246
+ rule: "non-empty-string",
1247
+ message: "value must be a string when provided.",
1248
+ expected: "string",
1249
+ actual: value
1250
+ });
1251
+ }
1252
+ }
1253
+ function validateNonEmptyString(value, path, message) {
1254
+ if (typeof value !== "string" || value.trim().length === 0) {
1255
+ invalidConfiguration({
1256
+ path,
1257
+ rule: "non-empty-string",
1258
+ message,
1259
+ expected: "non-empty string",
1260
+ actual: value
1261
+ });
1262
+ }
1263
+ }
1264
+ function validateOptionalFunction(value, path) {
1265
+ if (value === void 0) {
1266
+ return;
1267
+ }
1268
+ validateFunction(value, path);
1269
+ }
1270
+ function validateFunction(value, path) {
1271
+ if (typeof value !== "function") {
1272
+ invalidConfiguration({
1273
+ path,
1274
+ rule: "function",
1275
+ message: "value must be a function.",
1276
+ expected: "function",
1277
+ actual: value
1278
+ });
1279
+ }
1280
+ }
1281
+ function validateOptionalArray(value, path) {
1282
+ if (value === void 0) {
1283
+ return;
1284
+ }
1285
+ if (!Array.isArray(value)) {
1286
+ invalidConfiguration({
1287
+ path,
1288
+ rule: "array",
1289
+ message: "value must be an array when provided.",
1290
+ expected: "array",
1291
+ actual: value
1292
+ });
1293
+ }
1294
+ }
1295
+ function validateOptionalAbortSignal(value, path) {
1296
+ if (value === void 0) {
1297
+ return;
1298
+ }
1299
+ if (!isAbortSignalLike(value)) {
1300
+ invalidConfiguration({
1301
+ path,
1302
+ rule: "abort-signal",
1303
+ message: "value must be an AbortSignal when provided.",
1304
+ expected: "AbortSignal",
1305
+ actual: value
1306
+ });
1307
+ }
1308
+ }
1309
+ function isAbortSignalLike(value) {
1310
+ if (!isRecord$1(value)) {
1311
+ return false;
1312
+ }
1313
+ return typeof value.aborted === "boolean" && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function";
1314
+ }
1315
+ function validateOptionalPositiveInteger(value, path) {
1316
+ if (value === void 0) {
1317
+ return;
1318
+ }
1319
+ validatePositiveInteger(value, path);
1320
+ }
1321
+ function validatePositiveInteger(value, path) {
1322
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
1323
+ invalidConfiguration({
1324
+ path,
1325
+ rule: "positive-integer",
1326
+ message: "value must be a positive integer.",
1327
+ expected: "integer >= 1",
1328
+ actual: value
1329
+ });
1330
+ }
1331
+ }
1332
+ function validateOptionalNonNegativeInteger(value, path) {
1333
+ if (value === void 0) {
1334
+ return;
1335
+ }
1336
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
1337
+ invalidConfiguration({
1338
+ path,
1339
+ rule: "non-negative-integer",
1340
+ message: "value must be a non-negative integer.",
1341
+ expected: "integer >= 0",
1342
+ actual: value
1343
+ });
1344
+ }
1345
+ }
1346
+ function validateOptionalNonNegativeNumber(value, path) {
1347
+ if (value === void 0) {
1348
+ return;
1349
+ }
1350
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
1351
+ invalidConfiguration({
1352
+ path,
1353
+ rule: "non-negative-number",
1354
+ message: "value must be a non-negative finite number.",
1355
+ expected: "finite number >= 0",
1356
+ actual: value
1357
+ });
1358
+ }
1359
+ }
1360
+ function validateOptionalNumberInRange(value, path, min, max) {
1361
+ if (value === void 0) {
1362
+ return;
1363
+ }
1364
+ validateNumberInRange(value, path, min, max);
1365
+ }
1366
+ function validateNumberInRange(value, path, min, max) {
1367
+ if (typeof value !== "number" || !Number.isFinite(value) || value < min || value > max) {
1368
+ invalidConfiguration({
1369
+ path,
1370
+ rule: "range",
1371
+ message: `value must be a finite number in the inclusive range ${min}..${max}.`,
1372
+ expected: `finite number in ${min}..${max}`,
1373
+ actual: value
1374
+ });
1375
+ }
1376
+ }
1377
+ function requireRecord(value, path) {
1378
+ if (!isRecord$1(value)) {
1379
+ invalidConfiguration({
1380
+ path,
1381
+ rule: "object",
1382
+ message: "value must be an object.",
1383
+ expected: "object",
1384
+ actual: value
1385
+ });
1386
+ }
1387
+ return value;
1388
+ }
1389
+ function invalidConfiguration(options) {
1390
+ throw new DogpileError({
1391
+ code: "invalid-configuration",
1392
+ message: `Invalid Dogpile configuration at ${options.path}: ${options.message}`,
1393
+ retryable: false,
1394
+ detail: {
1395
+ kind: "configuration-validation",
1396
+ path: options.path,
1397
+ rule: options.rule,
1398
+ expected: options.expected,
1399
+ received: describeValue(options.actual)
1400
+ }
1401
+ });
1402
+ }
1403
+ function isProtocolName(value) {
1404
+ return typeof value === "string" && protocolNames.includes(value);
1405
+ }
1406
+ function isBudgetTier(value) {
1407
+ return typeof value === "string" && budgetTiers.includes(value);
1408
+ }
1409
+ function isRecord$1(value) {
1410
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1411
+ }
1412
+ function describeValue(value) {
1413
+ if (value === null) {
1414
+ return "null";
1415
+ }
1416
+ if (value === void 0) {
1417
+ return "undefined";
1418
+ }
1419
+ if (Array.isArray(value)) {
1420
+ return "array";
1421
+ }
1422
+ if (typeof value === "number" && !Number.isFinite(value)) {
1423
+ return String(value);
1424
+ }
1425
+ return typeof value;
1426
+ }
1427
+ const webSearchIdentity = {
1428
+ id: "dogpile.tools.webSearch",
1429
+ namespace: "dogpile",
1430
+ name: "webSearch",
1431
+ version: "1.0.0",
1432
+ description: "Search the web through a caller-provided fetch-compatible search adapter."
1433
+ };
1434
+ const codeExecIdentity = {
1435
+ id: "dogpile.tools.codeExec",
1436
+ namespace: "dogpile",
1437
+ name: "codeExec",
1438
+ version: "1.0.0",
1439
+ description: "Execute code through a caller-provided sandbox adapter."
1440
+ };
1441
+ const webSearchInputSchema = {
1442
+ kind: "json-schema",
1443
+ description: "Web search query and optional result cap.",
1444
+ schema: {
1445
+ type: "object",
1446
+ properties: {
1447
+ query: { type: "string" },
1448
+ maxResults: { type: "number", minimum: 1 }
1449
+ },
1450
+ required: ["query"],
1451
+ additionalProperties: false
1452
+ }
1453
+ };
1454
+ const codeExecInputSchema = {
1455
+ kind: "json-schema",
1456
+ description: "Code snippet plus language and optional timeout.",
1457
+ schema: {
1458
+ type: "object",
1459
+ properties: {
1460
+ language: {
1461
+ type: "string",
1462
+ enum: ["javascript", "typescript", "python", "bash", "shell"]
1463
+ },
1464
+ code: { type: "string" },
1465
+ timeoutMs: { type: "number", minimum: 1 }
1466
+ },
1467
+ required: ["language", "code"],
1468
+ additionalProperties: false
1469
+ }
1470
+ };
1471
+ const webSearchPermissions = [
1472
+ {
1473
+ kind: "network",
1474
+ allowPrivateNetwork: false
1475
+ }
1476
+ ];
1477
+ const codeExecPermissions = [
1478
+ {
1479
+ kind: "code-execution",
1480
+ sandbox: "caller-provided",
1481
+ languages: ["javascript", "typescript", "python", "bash", "shell"],
1482
+ allowNetwork: false
1483
+ }
1484
+ ];
1485
+ const codeExecLanguages = ["javascript", "typescript", "python", "bash", "shell"];
1486
+ function builtInDogpileToolIdentity(name) {
1487
+ return name === "webSearch" ? webSearchIdentity : codeExecIdentity;
1488
+ }
1489
+ function builtInDogpileToolInputSchema(name) {
1490
+ return name === "webSearch" ? webSearchInputSchema : codeExecInputSchema;
1491
+ }
1492
+ function builtInDogpileToolPermissions(name) {
1493
+ return name === "webSearch" ? webSearchPermissions : codeExecPermissions;
1494
+ }
1495
+ function validateBuiltInDogpileToolInput(name, input) {
1496
+ const issues = name === "webSearch" ? validateWebSearchInput(input) : validateCodeExecInput(input);
1497
+ return issues.length === 0 ? { type: "valid" } : { type: "invalid", issues };
1498
+ }
1499
+ function createRuntimeToolExecutor(options) {
1500
+ validateRuntimeToolRegistrations(options.tools);
1501
+ const tools = Array.from(options.tools);
1502
+ let callCount = 0;
1503
+ return {
1504
+ tools,
1505
+ async execute(request) {
1506
+ const tool = tools.find((candidate) => candidate.identity.id === request.toolId);
1507
+ const identity = tool?.identity ?? {
1508
+ id: request.toolId,
1509
+ name: request.toolId
1510
+ };
1511
+ const callIndex = callCount;
1512
+ callCount += 1;
1513
+ const toolCallId = request.toolCallId ?? options.makeToolCallId?.(identity, callIndex) ?? defaultToolCallId(options.runId, callIndex);
1514
+ const context = createExecutionContext(options, request, toolCallId);
1515
+ options.emit?.({
1516
+ type: "tool-call",
1517
+ runId: options.runId,
1518
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1519
+ toolCallId,
1520
+ tool: identity,
1521
+ input: request.input,
1522
+ ...request.agentId ? { agentId: request.agentId } : {},
1523
+ ...request.role ? { role: request.role } : {}
1524
+ });
1525
+ const result = await executeRuntimeTool(tool, identity, request.input, context);
1526
+ options.emit?.({
1527
+ type: "tool-result",
1528
+ runId: options.runId,
1529
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1530
+ toolCallId,
1531
+ tool: identity,
1532
+ result,
1533
+ ...request.agentId ? { agentId: request.agentId } : {},
1534
+ ...request.role ? { role: request.role } : {}
1535
+ });
1536
+ return result;
1537
+ }
1538
+ };
1539
+ }
1540
+ function runtimeToolManifest(tools) {
1541
+ return tools.map((tool) => {
1542
+ const inputSchema = {
1543
+ kind: tool.inputSchema.kind,
1544
+ schema: tool.inputSchema.schema,
1545
+ ...tool.inputSchema.description ? { description: tool.inputSchema.description } : {}
1546
+ };
1547
+ return {
1548
+ identity: runtimeToolIdentityManifest(tool.identity),
1549
+ inputSchema,
1550
+ permissions: Array.from(tool.permissions ?? []).map(runtimeToolPermissionManifest)
1551
+ };
1552
+ });
1553
+ }
1554
+ function runtimeToolAvailability(tools) {
1555
+ const manifest = runtimeToolManifest(tools);
1556
+ return manifest.length > 0 ? { tools: manifest } : {};
1557
+ }
1558
+ async function executeModelResponseToolRequests(options) {
1559
+ const toolCalls = [];
1560
+ for (const request of options.response.toolRequests ?? []) {
1561
+ const result = await options.executor.execute({
1562
+ ...request,
1563
+ agentId: request.agentId ?? options.agentId,
1564
+ role: request.role ?? options.role,
1565
+ turn: request.turn ?? options.turn,
1566
+ metadata: mergeToolMetadata(options.metadata, request.metadata)
1567
+ });
1568
+ toolCalls.push({
1569
+ toolCallId: result.toolCallId,
1570
+ tool: result.tool,
1571
+ input: request.input,
1572
+ result
1573
+ });
1574
+ }
1575
+ return toolCalls;
1576
+ }
1577
+ function runtimeToolIdentityManifest(identity) {
1578
+ return {
1579
+ id: identity.id,
1580
+ name: identity.name,
1581
+ ...identity.namespace ? { namespace: identity.namespace } : {},
1582
+ ...identity.version ? { version: identity.version } : {},
1583
+ ...identity.description ? { description: identity.description } : {}
1584
+ };
1585
+ }
1586
+ function runtimeToolPermissionManifest(permission) {
1587
+ if (permission.kind === "network") {
1588
+ return {
1589
+ kind: permission.kind,
1590
+ ...permission.allowHosts ? { allowHosts: Array.from(permission.allowHosts) } : {},
1591
+ ...permission.allowPrivateNetwork === void 0 ? {} : { allowPrivateNetwork: permission.allowPrivateNetwork }
1592
+ };
1593
+ }
1594
+ if (permission.kind === "code-execution") {
1595
+ return {
1596
+ kind: permission.kind,
1597
+ sandbox: permission.sandbox,
1598
+ ...permission.languages ? { languages: Array.from(permission.languages) } : {},
1599
+ ...permission.allowNetwork === void 0 ? {} : { allowNetwork: permission.allowNetwork }
1600
+ };
1601
+ }
1602
+ return {
1603
+ kind: permission.kind,
1604
+ name: permission.name,
1605
+ ...permission.description ? { description: permission.description } : {},
1606
+ ...permission.metadata ? { metadata: permission.metadata } : {}
1607
+ };
1608
+ }
1609
+ function validateCodeExecAdapterInput(input, options) {
1610
+ const issues = [...validateCodeExecInput(input)];
1611
+ const languages = options.languages ?? codeExecLanguages;
1612
+ if (typeof input.language === "string" && isCodeExecLanguage(input.language) && !languages.includes(input.language)) {
1613
+ issues.push({
1614
+ code: "invalid-value",
1615
+ path: "language",
1616
+ message: "codeExec.language is not enabled for this adapter.",
1617
+ detail: {
1618
+ allowed: Array.from(languages)
1619
+ }
1620
+ });
1621
+ }
1622
+ const effectiveTimeoutMs = input.timeoutMs ?? options.defaultTimeoutMs;
1623
+ if (effectiveTimeoutMs !== void 0 && options.maxTimeoutMs !== void 0 && Number.isFinite(effectiveTimeoutMs) && Number.isFinite(options.maxTimeoutMs) && effectiveTimeoutMs > options.maxTimeoutMs) {
1624
+ issues.push({
1625
+ code: "out-of-range",
1626
+ path: input.timeoutMs === void 0 ? "defaultTimeoutMs" : "timeoutMs",
1627
+ message: `codeExec.timeoutMs must be less than or equal to ${options.maxTimeoutMs}.`,
1628
+ detail: {
1629
+ maximum: options.maxTimeoutMs
1630
+ }
1631
+ });
1632
+ }
1633
+ return issues.length === 0 ? { type: "valid" } : { type: "invalid", issues };
1634
+ }
1635
+ function createExecutionContext(options, request, toolCallId) {
1636
+ return {
1637
+ runId: options.runId,
1638
+ toolCallId,
1639
+ protocol: options.protocol,
1640
+ tier: options.tier,
1641
+ ...request.agentId ? { agentId: request.agentId } : {},
1642
+ ...request.role ? { role: request.role } : {},
1643
+ ...request.turn !== void 0 ? { turn: request.turn } : {},
1644
+ ...options.getTrace ? { trace: options.getTrace() } : {},
1645
+ ...request.abortSignal ?? options.abortSignal ? { abortSignal: request.abortSignal ?? options.abortSignal } : {},
1646
+ ...options.metadata || request.metadata ? { metadata: mergeToolMetadata(options.metadata, request.metadata) } : {}
1647
+ };
1648
+ }
1649
+ async function executeRuntimeTool(tool, identity, input, context) {
1650
+ if (!tool) {
1651
+ return {
1652
+ type: "error",
1653
+ toolCallId: context.toolCallId,
1654
+ tool: identity,
1655
+ error: {
1656
+ code: "unavailable",
1657
+ message: `Runtime tool "${identity.id}" is not registered.`,
1658
+ retryable: false
1659
+ }
1660
+ };
1661
+ }
1662
+ const validation = validateRuntimeToolInput(tool, input);
1663
+ if (validation.type === "invalid") {
1664
+ return {
1665
+ type: "error",
1666
+ toolCallId: context.toolCallId,
1667
+ tool: identity,
1668
+ error: {
1669
+ code: "invalid-input",
1670
+ message: "Runtime tool input failed validation.",
1671
+ retryable: false,
1672
+ detail: {
1673
+ issues: validation.issues.map((issue) => ({
1674
+ code: issue.code,
1675
+ path: issue.path,
1676
+ message: issue.message,
1677
+ ...issue.detail ? { detail: issue.detail } : {}
1678
+ }))
1679
+ }
1680
+ }
1681
+ };
1682
+ }
1683
+ try {
1684
+ return await tool.execute(input, context);
1685
+ } catch (error) {
1686
+ return {
1687
+ type: "error",
1688
+ toolCallId: context.toolCallId,
1689
+ tool: identity,
1690
+ error: normalizeRuntimeToolAdapterError(error)
1691
+ };
1692
+ }
1693
+ }
1694
+ function validateRuntimeToolInput(tool, input) {
1695
+ if (typeof tool.validateInput !== "function") {
1696
+ return { type: "valid" };
1697
+ }
1698
+ return tool.validateInput(input);
1699
+ }
1700
+ function mergeToolMetadata(base, request) {
1701
+ return {
1702
+ ...base ?? {},
1703
+ ...request ?? {}
1704
+ };
1705
+ }
1706
+ function defaultToolCallId(runId, callIndex) {
1707
+ return `${runId}:tool-${callIndex + 1}`;
1708
+ }
1709
+ function normalizeRuntimeToolAdapterError(error) {
1710
+ if (isRuntimeToolAdapterError(error)) {
1711
+ return error;
1712
+ }
1713
+ if (error instanceof DOMException && error.name === "AbortError") {
1714
+ return {
1715
+ code: "aborted",
1716
+ message: error.message || "Tool execution was aborted.",
1717
+ retryable: true,
1718
+ detail: {
1719
+ name: error.name
1720
+ }
1721
+ };
1722
+ }
1723
+ if (error instanceof Error) {
1724
+ return {
1725
+ code: "backend-error",
1726
+ message: error.message,
1727
+ retryable: false,
1728
+ detail: {
1729
+ name: error.name
1730
+ }
1731
+ };
1732
+ }
1733
+ return {
1734
+ code: "unknown",
1735
+ message: "Tool execution failed with a non-Error value.",
1736
+ retryable: false,
1737
+ detail: {
1738
+ valueType: typeof error
1739
+ }
1740
+ };
1741
+ }
1742
+ function createWebSearchToolAdapter(options) {
1743
+ const identity = mergeIdentity(webSearchIdentity, options.identity);
1744
+ return normalizeBuiltInDogpileTool({
1745
+ name: "webSearch",
1746
+ ...options.identity ? { identity: options.identity } : {},
1747
+ ...options.permissions ? { permissions: options.permissions } : {},
1748
+ async execute(input, context) {
1749
+ const fetchImplementation = options.fetch ?? globalThis.fetch;
1750
+ if (!fetchImplementation) {
1751
+ return {
1752
+ type: "error",
1753
+ toolCallId: context.toolCallId,
1754
+ tool: identity,
1755
+ error: {
1756
+ code: "unavailable",
1757
+ message: "No fetch implementation is available for webSearch.",
1758
+ retryable: false
1759
+ }
1760
+ };
1761
+ }
1762
+ const request = options.buildRequest ? options.buildRequest(input, context) : defaultWebSearchRequest(options, input);
1763
+ const response = await fetchImplementation(request.url, {
1764
+ ...request.init,
1765
+ ...context.abortSignal ? { signal: context.abortSignal } : {}
1766
+ });
1767
+ if (!response.ok) {
1768
+ throw {
1769
+ code: response.status >= 500 ? "unavailable" : "backend-error",
1770
+ message: `Web search backend returned HTTP ${response.status}.`,
1771
+ retryable: response.status === 408 || response.status === 429 || response.status >= 500,
1772
+ detail: {
1773
+ status: response.status,
1774
+ statusText: response.statusText
1775
+ }
1776
+ };
1777
+ }
1778
+ const output = options.parseResponse ? await options.parseResponse(response, input, context) : await defaultWebSearchResponseParser(response);
1779
+ return {
1780
+ type: "success",
1781
+ toolCallId: context.toolCallId,
1782
+ tool: identity,
1783
+ output
1784
+ };
1785
+ }
1786
+ });
1787
+ }
1788
+ function createCodeExecToolAdapter(options) {
1789
+ const identity = mergeIdentity(codeExecIdentity, options.identity);
1790
+ const permissions = options.permissions ?? codeExecPermissionsFor(options.languages ?? codeExecLanguages, options.allowNetwork ?? false);
1791
+ const inputSchema = codeExecInputSchemaFor(options.languages ?? codeExecLanguages);
1792
+ return {
1793
+ identity,
1794
+ inputSchema,
1795
+ permissions,
1796
+ validateInput: (input) => validateCodeExecAdapterInput(input, options),
1797
+ async execute(input, context) {
1798
+ const validation = validateCodeExecAdapterInput(input, options);
1799
+ if (validation.type === "invalid") {
1800
+ return {
1801
+ type: "error",
1802
+ toolCallId: context.toolCallId,
1803
+ tool: identity,
1804
+ error: {
1805
+ code: "invalid-input",
1806
+ message: "Invalid codeExec tool input.",
1807
+ retryable: false,
1808
+ detail: {
1809
+ issues: validation.issues
1810
+ }
1811
+ }
1812
+ };
1813
+ }
1814
+ const timeoutMs = input.timeoutMs ?? options.defaultTimeoutMs;
1815
+ const executionInput = timeoutMs === void 0 ? input : {
1816
+ ...input,
1817
+ timeoutMs
1818
+ };
1819
+ try {
1820
+ const output = await executeSandboxWithPolicy(options.execute, executionInput, context, timeoutMs);
1821
+ return {
1822
+ type: "success",
1823
+ toolCallId: context.toolCallId,
1824
+ tool: identity,
1825
+ output
1826
+ };
1827
+ } catch (error) {
1828
+ return {
1829
+ type: "error",
1830
+ toolCallId: context.toolCallId,
1831
+ tool: identity,
1832
+ error: normalizeRuntimeToolAdapterError(error)
1833
+ };
1834
+ }
1835
+ }
1836
+ };
1837
+ }
1838
+ function normalizeBuiltInDogpileTool(definition) {
1839
+ switch (definition.name) {
1840
+ case "webSearch": {
1841
+ const identity = mergeIdentity(webSearchIdentity, definition.identity);
1842
+ const permissions = definition.permissions ?? webSearchPermissions;
1843
+ const tool = {
1844
+ identity,
1845
+ inputSchema: definition.inputSchema ?? webSearchInputSchema,
1846
+ permissions,
1847
+ validateInput: (input) => validateBuiltInDogpileToolInput("webSearch", input),
1848
+ execute: (input, context) => executeBuiltInTool(identity, definition.execute, input, context, "webSearch")
1849
+ };
1850
+ return tool;
1851
+ }
1852
+ case "codeExec": {
1853
+ const identity = mergeIdentity(codeExecIdentity, definition.identity);
1854
+ const permissions = definition.permissions ?? codeExecPermissions;
1855
+ const tool = {
1856
+ identity,
1857
+ inputSchema: definition.inputSchema ?? codeExecInputSchema,
1858
+ permissions,
1859
+ validateInput: (input) => validateBuiltInDogpileToolInput("codeExec", input),
1860
+ execute: (input, context) => executeBuiltInTool(identity, definition.execute, input, context, "codeExec")
1861
+ };
1862
+ return tool;
1863
+ }
1864
+ }
1865
+ }
1866
+ function normalizeBuiltInDogpileTools(tools) {
1867
+ const normalized = [];
1868
+ if (tools.webSearch) {
1869
+ normalized.push(normalizeBuiltInDogpileTool(asWebSearchDefinition(tools.webSearch)));
1870
+ }
1871
+ if (tools.codeExec) {
1872
+ normalized.push(normalizeBuiltInDogpileTool(asCodeExecDefinition(tools.codeExec)));
1873
+ }
1874
+ return normalized;
1875
+ }
1876
+ async function executeBuiltInTool(identity, execute, input, context, name) {
1877
+ const validation = validateBuiltInDogpileToolInput(
1878
+ name,
1879
+ input
1880
+ );
1881
+ if (validation.type === "invalid") {
1882
+ return {
1883
+ type: "error",
1884
+ toolCallId: context.toolCallId,
1885
+ tool: identity,
1886
+ error: {
1887
+ code: "invalid-input",
1888
+ message: `Invalid ${name} tool input.`,
1889
+ retryable: false,
1890
+ detail: {
1891
+ issues: validation.issues
1892
+ }
1893
+ }
1894
+ };
1895
+ }
1896
+ try {
1897
+ return await execute(input, context);
1898
+ } catch (error) {
1899
+ return {
1900
+ type: "error",
1901
+ toolCallId: context.toolCallId,
1902
+ tool: identity,
1903
+ error: normalizeRuntimeToolAdapterError(error)
1904
+ };
1905
+ }
1906
+ }
1907
+ function asWebSearchDefinition(tool) {
1908
+ return typeof tool === "function" ? { name: "webSearch", execute: tool } : tool;
1909
+ }
1910
+ function asCodeExecDefinition(tool) {
1911
+ return typeof tool === "function" ? { name: "codeExec", execute: tool } : tool;
1912
+ }
1913
+ function mergeIdentity(defaultIdentity, options) {
1914
+ if (!options) {
1915
+ return defaultIdentity;
1916
+ }
1917
+ return {
1918
+ ...defaultIdentity,
1919
+ ...options.namespace !== void 0 ? { namespace: options.namespace } : {},
1920
+ ...options.version !== void 0 ? { version: options.version } : {},
1921
+ ...options.description !== void 0 ? { description: options.description } : {}
1922
+ };
1923
+ }
1924
+ function defaultWebSearchRequest(options, input, _context) {
1925
+ const url = new URL(String(options.endpoint));
1926
+ url.searchParams.set("q", input.query);
1927
+ url.searchParams.set("limit", String(input.maxResults ?? options.defaultMaxResults ?? 10));
1928
+ return {
1929
+ url,
1930
+ init: {
1931
+ method: "GET",
1932
+ ...options.headers ? { headers: options.headers } : {}
1933
+ }
1934
+ };
1935
+ }
1936
+ async function defaultWebSearchResponseParser(response) {
1937
+ const payload = await response.json();
1938
+ const resultValues = Array.isArray(payload) ? payload : isJsonObject(payload) && Array.isArray(payload.results) ? payload.results : void 0;
1939
+ if (!resultValues) {
1940
+ throw {
1941
+ code: "backend-error",
1942
+ message: "Web search backend response must contain a results array.",
1943
+ retryable: false
1944
+ };
1945
+ }
1946
+ return {
1947
+ results: resultValues.map(normalizeWebSearchResult)
1948
+ };
1949
+ }
1950
+ function codeExecPermissionsFor(languages, allowNetwork) {
1951
+ return [
1952
+ {
1953
+ kind: "code-execution",
1954
+ sandbox: "caller-provided",
1955
+ languages,
1956
+ allowNetwork
1957
+ }
1958
+ ];
1959
+ }
1960
+ function codeExecInputSchemaFor(languages) {
1961
+ return {
1962
+ kind: "json-schema",
1963
+ ...codeExecInputSchema.description ? { description: codeExecInputSchema.description } : {},
1964
+ schema: {
1965
+ type: "object",
1966
+ properties: {
1967
+ language: {
1968
+ type: "string",
1969
+ enum: Array.from(languages)
1970
+ },
1971
+ code: { type: "string" },
1972
+ timeoutMs: { type: "number", minimum: 1 }
1973
+ },
1974
+ required: ["language", "code"],
1975
+ additionalProperties: false
1976
+ }
1977
+ };
1978
+ }
1979
+ async function executeSandboxWithPolicy(execute, input, context, timeoutMs) {
1980
+ if (context.abortSignal?.aborted) {
1981
+ throw {
1982
+ code: "aborted",
1983
+ message: "Code execution was aborted before the sandbox started.",
1984
+ retryable: true
1985
+ };
1986
+ }
1987
+ const execution = Promise.resolve().then(() => execute(input, context));
1988
+ if (timeoutMs === void 0 && context.abortSignal === void 0) {
1989
+ return await execution;
1990
+ }
1991
+ return await new Promise((resolve, reject) => {
1992
+ let timeoutId;
1993
+ const cleanup = () => {
1994
+ if (timeoutId !== void 0) {
1995
+ clearTimeout(timeoutId);
1996
+ }
1997
+ context.abortSignal?.removeEventListener("abort", abortHandler);
1998
+ };
1999
+ const abortHandler = () => {
2000
+ cleanup();
2001
+ reject({
2002
+ code: "aborted",
2003
+ message: "Code execution was aborted.",
2004
+ retryable: true
2005
+ });
2006
+ };
2007
+ if (context.abortSignal) {
2008
+ context.abortSignal.addEventListener("abort", abortHandler, { once: true });
2009
+ }
2010
+ if (timeoutMs !== void 0) {
2011
+ timeoutId = setTimeout(() => {
2012
+ cleanup();
2013
+ reject({
2014
+ code: "timeout",
2015
+ message: `Code execution exceeded timeout of ${timeoutMs}ms.`,
2016
+ retryable: true,
2017
+ detail: {
2018
+ timeoutMs
2019
+ }
2020
+ });
2021
+ }, timeoutMs);
2022
+ }
2023
+ execution.then(
2024
+ (output) => {
2025
+ cleanup();
2026
+ resolve(output);
2027
+ },
2028
+ (error) => {
2029
+ cleanup();
2030
+ reject(error);
2031
+ }
2032
+ );
2033
+ });
2034
+ }
2035
+ function normalizeWebSearchResult(value) {
2036
+ if (!isJsonObject(value)) {
2037
+ throw {
2038
+ code: "backend-error",
2039
+ message: "Web search result must be a JSON object.",
2040
+ retryable: false
2041
+ };
2042
+ }
2043
+ const title = jsonString(value.title, "title");
2044
+ const url = jsonString(value.url, "url");
2045
+ const snippet = optionalJsonString(value.snippet, "snippet");
2046
+ const metadata = optionalJsonObject(value.metadata, "metadata");
2047
+ return {
2048
+ title,
2049
+ url,
2050
+ ...snippet !== void 0 ? { snippet } : {},
2051
+ ...metadata !== void 0 ? { metadata } : {}
2052
+ };
2053
+ }
2054
+ function jsonString(value, fieldName) {
2055
+ if (typeof value !== "string" || value.trim().length === 0) {
2056
+ throw {
2057
+ code: "backend-error",
2058
+ message: `Web search result ${fieldName} must be a non-empty string.`,
2059
+ retryable: false
2060
+ };
2061
+ }
2062
+ return value;
2063
+ }
2064
+ function optionalJsonString(value, fieldName) {
2065
+ if (value === void 0) {
2066
+ return void 0;
2067
+ }
2068
+ if (typeof value !== "string") {
2069
+ throw {
2070
+ code: "backend-error",
2071
+ message: `Web search result ${fieldName} must be a string when present.`,
2072
+ retryable: false
2073
+ };
2074
+ }
2075
+ return value;
2076
+ }
2077
+ function optionalJsonObject(value, fieldName) {
2078
+ if (value === void 0) {
2079
+ return void 0;
2080
+ }
2081
+ if (!isJsonObject(value)) {
2082
+ throw {
2083
+ code: "backend-error",
2084
+ message: `Web search result ${fieldName} must be a JSON object when present.`,
2085
+ retryable: false
2086
+ };
2087
+ }
2088
+ return value;
2089
+ }
2090
+ function isJsonObject(value) {
2091
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2092
+ }
2093
+ function validateWebSearchInput(input) {
2094
+ const issues = [];
2095
+ if (typeof input.query !== "string") {
2096
+ issues.push({
2097
+ code: input.query === void 0 ? "missing-field" : "invalid-type",
2098
+ path: "query",
2099
+ message: "webSearch.query must be a string."
2100
+ });
2101
+ } else if (input.query.trim().length === 0) {
2102
+ issues.push({
2103
+ code: "invalid-value",
2104
+ path: "query",
2105
+ message: "webSearch.query must not be empty."
2106
+ });
2107
+ }
2108
+ if (input.maxResults !== void 0) {
2109
+ if (typeof input.maxResults !== "number" || !Number.isFinite(input.maxResults)) {
2110
+ issues.push({
2111
+ code: "invalid-type",
2112
+ path: "maxResults",
2113
+ message: "webSearch.maxResults must be a finite number."
2114
+ });
2115
+ } else if (input.maxResults < 1) {
2116
+ issues.push({
2117
+ code: "out-of-range",
2118
+ path: "maxResults",
2119
+ message: "webSearch.maxResults must be greater than or equal to 1.",
2120
+ detail: {
2121
+ minimum: 1
2122
+ }
2123
+ });
2124
+ }
2125
+ }
2126
+ return issues;
2127
+ }
2128
+ function validateCodeExecInput(input) {
2129
+ const issues = [];
2130
+ if (typeof input.language !== "string") {
2131
+ issues.push({
2132
+ code: input.language === void 0 ? "missing-field" : "invalid-type",
2133
+ path: "language",
2134
+ message: "codeExec.language must be a string."
2135
+ });
2136
+ } else if (!isCodeExecLanguage(input.language)) {
2137
+ issues.push({
2138
+ code: "invalid-value",
2139
+ path: "language",
2140
+ message: "codeExec.language must be one of javascript, typescript, python, bash, or shell.",
2141
+ detail: {
2142
+ allowed: ["javascript", "typescript", "python", "bash", "shell"]
2143
+ }
2144
+ });
2145
+ }
2146
+ if (typeof input.code !== "string") {
2147
+ issues.push({
2148
+ code: input.code === void 0 ? "missing-field" : "invalid-type",
2149
+ path: "code",
2150
+ message: "codeExec.code must be a string."
2151
+ });
2152
+ }
2153
+ if (input.timeoutMs !== void 0) {
2154
+ if (typeof input.timeoutMs !== "number" || !Number.isFinite(input.timeoutMs)) {
2155
+ issues.push({
2156
+ code: "invalid-type",
2157
+ path: "timeoutMs",
2158
+ message: "codeExec.timeoutMs must be a finite number."
2159
+ });
2160
+ } else if (input.timeoutMs < 1) {
2161
+ issues.push({
2162
+ code: "out-of-range",
2163
+ path: "timeoutMs",
2164
+ message: "codeExec.timeoutMs must be greater than or equal to 1.",
2165
+ detail: {
2166
+ minimum: 1
2167
+ }
2168
+ });
2169
+ }
2170
+ }
2171
+ return issues;
2172
+ }
2173
+ function isCodeExecLanguage(value) {
2174
+ return value === "javascript" || value === "typescript" || value === "python" || value === "bash" || value === "shell";
2175
+ }
2176
+ function isRuntimeToolAdapterError(error) {
2177
+ if (typeof error !== "object" || error === null || !("code" in error) || !("message" in error)) {
2178
+ return false;
2179
+ }
2180
+ const candidate = error;
2181
+ return isRuntimeToolAdapterErrorCode(candidate.code) && typeof candidate.message === "string";
2182
+ }
2183
+ function isRuntimeToolAdapterErrorCode(value) {
2184
+ return value === "invalid-input" || value === "permission-denied" || value === "timeout" || value === "aborted" || value === "unavailable" || value === "backend-error" || value === "unknown";
2185
+ }
2186
+ async function runBroadcast(options) {
2187
+ const runId = createRunId$3();
2188
+ const events = [];
2189
+ const transcript = [];
2190
+ const protocolDecisions = [];
2191
+ const providerCalls = [];
2192
+ let totalCost = emptyCost();
2193
+ const maxRounds = options.protocol.maxRounds ?? 2;
2194
+ let firstRoundContributions = [];
2195
+ let lastContributions = [];
2196
+ const startedAtMs = nowMs$3();
2197
+ let stopped = false;
2198
+ let termination;
2199
+ const emit = (event) => {
2200
+ events.push(event);
2201
+ options.emit?.(event);
2202
+ };
2203
+ const recordProtocolDecision = (event, decisionOptions) => {
2204
+ protocolDecisions.push(
2205
+ createReplayTraceProtocolDecision("broadcast", event, events.length - 1, decisionOptions)
2206
+ );
2207
+ };
2208
+ const toolExecutor = createRuntimeToolExecutor({
2209
+ runId,
2210
+ protocol: "broadcast",
2211
+ tier: options.tier,
2212
+ tools: options.tools,
2213
+ emit(event) {
2214
+ emit(event);
2215
+ recordProtocolDecision(event);
2216
+ },
2217
+ getTrace: () => ({ events, transcript }),
2218
+ ...options.signal !== void 0 ? { abortSignal: options.signal } : {}
2219
+ });
2220
+ const toolAvailability = runtimeToolAvailability(toolExecutor.tools);
2221
+ throwIfAborted(options.signal, options.model.id);
2222
+ for (const agent of options.agents) {
2223
+ const event = {
2224
+ type: "role-assignment",
2225
+ runId,
2226
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2227
+ agentId: agent.id,
2228
+ role: agent.role
2229
+ };
2230
+ emit(event);
2231
+ recordProtocolDecision(event);
2232
+ }
2233
+ for (let round = 1; round <= maxRounds; round += 1) {
2234
+ if (stopIfNeeded()) {
2235
+ break;
2236
+ }
2237
+ const providerCallSlots = [];
2238
+ const turnResults = await Promise.all(
2239
+ options.agents.map(async (agent, agentIndex) => {
2240
+ const turn = transcript.length + agentIndex + 1;
2241
+ const input = buildBroadcastInput(options.intent, round, maxRounds, firstRoundContributions);
2242
+ const request = {
2243
+ temperature: options.temperature,
2244
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
2245
+ metadata: {
2246
+ runId,
2247
+ protocol: "broadcast",
2248
+ agentId: agent.id,
2249
+ role: agent.role,
2250
+ tier: options.tier,
2251
+ round,
2252
+ ...toolAvailability
2253
+ },
2254
+ messages: [
2255
+ {
2256
+ role: "system",
2257
+ content: buildSystemPrompt$3(agent)
2258
+ },
2259
+ {
2260
+ role: "user",
2261
+ content: input
2262
+ }
2263
+ ]
2264
+ };
2265
+ const response = await generateModelTurn({
2266
+ model: options.model,
2267
+ request,
2268
+ runId,
2269
+ agent,
2270
+ input,
2271
+ emit,
2272
+ callId: providerCallIdFor$2(runId, providerCalls.length + agentIndex + 1),
2273
+ onProviderCall(call) {
2274
+ providerCallSlots[agentIndex] = call;
2275
+ }
2276
+ });
2277
+ const decision = parseAgentDecision(response.text);
2278
+ const toolCalls = await executeModelResponseToolRequests({
2279
+ response,
2280
+ executor: toolExecutor,
2281
+ agentId: agent.id,
2282
+ role: agent.role,
2283
+ turn,
2284
+ metadata: {
2285
+ round
2286
+ }
2287
+ });
2288
+ throwIfAborted(options.signal, options.model.id);
2289
+ return {
2290
+ agent,
2291
+ agentIndex,
2292
+ turn,
2293
+ input,
2294
+ response,
2295
+ decision,
2296
+ toolCalls,
2297
+ turnCost: responseCost$3(response)
2298
+ };
2299
+ })
2300
+ );
2301
+ providerCalls.push(...providerCallSlots.filter((call) => call !== void 0));
2302
+ const contributions = [];
2303
+ for (const result of turnResults) {
2304
+ totalCost = addCost(totalCost, result.turnCost);
2305
+ transcript.push({
2306
+ agentId: result.agent.id,
2307
+ role: result.agent.role,
2308
+ input: result.input,
2309
+ output: result.response.text,
2310
+ ...result.decision !== void 0 ? { decision: result.decision } : {},
2311
+ ...result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {}
2312
+ });
2313
+ contributions.push({
2314
+ agentId: result.agent.id,
2315
+ role: result.agent.role,
2316
+ output: result.response.text,
2317
+ ...result.decision !== void 0 ? { decision: result.decision } : {}
2318
+ });
2319
+ const event = {
2320
+ type: "agent-turn",
2321
+ runId,
2322
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2323
+ agentId: result.agent.id,
2324
+ role: result.agent.role,
2325
+ input: result.input,
2326
+ output: result.response.text,
2327
+ ...result.decision !== void 0 ? { decision: result.decision } : {},
2328
+ cost: totalCost
2329
+ };
2330
+ emit(event);
2331
+ recordProtocolDecision(event, {
2332
+ round,
2333
+ turn: result.turn,
2334
+ transcriptEntryCount: transcript.length,
2335
+ contributionCount: result.agentIndex + 1
2336
+ });
2337
+ }
2338
+ if (contributions.length === 0) {
2339
+ break;
2340
+ }
2341
+ if (round === 1) {
2342
+ firstRoundContributions = contributions;
2343
+ }
2344
+ lastContributions = contributions;
2345
+ const broadcast = {
2346
+ type: "broadcast",
2347
+ runId,
2348
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2349
+ round,
2350
+ contributions,
2351
+ cost: totalCost
2352
+ };
2353
+ emit(broadcast);
2354
+ recordProtocolDecision(broadcast, {
2355
+ round,
2356
+ transcriptEntryCount: transcript.length,
2357
+ contributionCount: contributions.length
2358
+ });
2359
+ if (stopIfNeeded()) {
2360
+ break;
2361
+ }
2362
+ }
2363
+ const output = synthesizeBroadcastOutput(lastContributions);
2364
+ throwIfAborted(options.signal, options.model.id);
2365
+ const final = {
2366
+ type: "final",
2367
+ runId,
2368
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2369
+ output,
2370
+ cost: totalCost,
2371
+ transcript: createTranscriptLink(transcript),
2372
+ ...termination !== void 0 ? { termination } : {}
2373
+ };
2374
+ emit(final);
2375
+ recordProtocolDecision(final, {
2376
+ transcriptEntryCount: transcript.length
2377
+ });
2378
+ const finalEvent = events.at(-1);
2379
+ return {
2380
+ output,
2381
+ eventLog: createRunEventLog(runId, "broadcast", events),
2382
+ trace: {
2383
+ schemaVersion: "1.0",
2384
+ runId,
2385
+ protocol: "broadcast",
2386
+ tier: options.tier,
2387
+ modelProviderId: options.model.id,
2388
+ agentsUsed: options.agents,
2389
+ inputs: createReplayTraceRunInputs({
2390
+ intent: options.intent,
2391
+ protocol: options.protocol,
2392
+ tier: options.tier,
2393
+ modelProviderId: options.model.id,
2394
+ agents: options.agents,
2395
+ temperature: options.temperature
2396
+ }),
2397
+ budget: createReplayTraceBudget({
2398
+ tier: options.tier,
2399
+ ...options.budget ? { caps: options.budget } : {},
2400
+ ...options.terminate ? { termination: options.terminate } : {}
2401
+ }),
2402
+ budgetStateChanges: createReplayTraceBudgetStateChanges(events),
2403
+ seed: createReplayTraceSeed(options.seed),
2404
+ protocolDecisions,
2405
+ providerCalls,
2406
+ finalOutput: createReplayTraceFinalOutput(output, finalEvent ?? {
2407
+ type: "final",
2408
+ at: "",
2409
+ cost: totalCost,
2410
+ transcript: createTranscriptLink(transcript)
2411
+ }),
2412
+ events,
2413
+ transcript
2414
+ },
2415
+ transcript,
2416
+ usage: createRunUsage(totalCost),
2417
+ metadata: createRunMetadata({
2418
+ runId,
2419
+ protocol: "broadcast",
2420
+ tier: options.tier,
2421
+ modelProviderId: options.model.id,
2422
+ agentsUsed: options.agents,
2423
+ events
2424
+ }),
2425
+ accounting: createRunAccounting({
2426
+ tier: options.tier,
2427
+ ...options.budget ? { budget: options.budget } : {},
2428
+ ...options.terminate ? { termination: options.terminate } : {},
2429
+ cost: totalCost,
2430
+ events
2431
+ }),
2432
+ cost: totalCost
2433
+ };
2434
+ function stopIfNeeded() {
2435
+ throwIfAborted(options.signal, options.model.id);
2436
+ if (stopped || !options.terminate) {
2437
+ return stopped;
2438
+ }
2439
+ const stopRecord2 = evaluateTerminationStop(options.terminate, {
2440
+ protocol: "broadcast",
2441
+ tier: options.tier,
2442
+ cost: totalCost,
2443
+ transcript,
2444
+ iteration: transcript.length,
2445
+ elapsedMs: elapsedMs$3(startedAtMs)
2446
+ });
2447
+ if (!stopRecord2) {
2448
+ return false;
2449
+ }
2450
+ stopped = true;
2451
+ termination = stopRecord2;
2452
+ if (stopRecord2.reason === "budget") {
2453
+ emitBudgetStop(stopRecord2);
2454
+ }
2455
+ return true;
2456
+ }
2457
+ function emitBudgetStop(record) {
2458
+ const event = {
2459
+ type: "budget-stop",
2460
+ runId,
2461
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2462
+ reason: record.budgetReason ?? "cost",
2463
+ cost: totalCost,
2464
+ iteration: transcript.length,
2465
+ elapsedMs: elapsedMs$3(startedAtMs),
2466
+ detail: record.detail ?? {}
2467
+ };
2468
+ emit(event);
2469
+ recordProtocolDecision(event, {
2470
+ transcriptEntryCount: transcript.length
2471
+ });
2472
+ }
2473
+ }
2474
+ function buildSystemPrompt$3(agent) {
2475
+ const instruction = agent.instructions ? `
2476
+ Instructions: ${agent.instructions}` : "";
2477
+ return `You are ${agent.id}, acting as ${agent.role} in a Broadcast multi-agent protocol.${instruction}`;
2478
+ }
2479
+ function buildBroadcastInput(intent, round, maxRounds, firstRoundContributions) {
2480
+ if (maxRounds === 1) {
2481
+ return `Mission: ${intent}
2482
+ Broadcast round ${round}: contribute independently before synthesis.`;
2483
+ }
2484
+ if (round === 1) {
2485
+ return `Mission: ${intent}
2486
+ Broadcast round 1: broadcast your intended role and participation decision. Do not produce the final plan yet.`;
2487
+ }
2488
+ const intentions = firstRoundContributions.map((contribution) => `${contribution.role}:${contribution.agentId} => ${contribution.output}`).join("\n");
2489
+ return `Mission: ${intent}
2490
+
2491
+ Round 1 intentions:
2492
+ ${intentions || "(none)"}
2493
+
2494
+ Broadcast round ${round}: make your final contribution or abstention decision informed by all round 1 intentions.`;
2495
+ }
2496
+ function synthesizeBroadcastOutput(contributions) {
2497
+ return contributions.map((entry) => `${entry.role}:${entry.agentId} => ${entry.output}`).join("\n");
2498
+ }
2499
+ function responseCost$3(response) {
2500
+ return {
2501
+ usd: response.costUsd ?? 0,
2502
+ inputTokens: response.usage?.inputTokens ?? 0,
2503
+ outputTokens: response.usage?.outputTokens ?? 0,
2504
+ totalTokens: response.usage?.totalTokens ?? 0
2505
+ };
2506
+ }
2507
+ function createRunId$3() {
2508
+ const random = globalThis.crypto?.randomUUID?.();
2509
+ return random ?? `run-${Date.now().toString(36)}`;
2510
+ }
2511
+ function nowMs$3() {
2512
+ return globalThis.performance?.now() ?? Date.now();
2513
+ }
2514
+ function elapsedMs$3(startedAtMs) {
2515
+ return Math.max(0, nowMs$3() - startedAtMs);
2516
+ }
2517
+ function providerCallIdFor$2(runId, oneBasedIndex) {
2518
+ return `${runId}:provider-call:${oneBasedIndex}`;
2519
+ }
2520
+ async function runCoordinator(options) {
2521
+ const runId = createRunId$2();
2522
+ const events = [];
2523
+ const transcript = [];
2524
+ const protocolDecisions = [];
2525
+ const providerCalls = [];
2526
+ let totalCost = emptyCost();
2527
+ const maxTurns = options.protocol.maxTurns ?? options.agents.length;
2528
+ const activeAgents = options.agents.slice(0, maxTurns);
2529
+ const coordinator = activeAgents[0];
2530
+ const startedAtMs = nowMs$2();
2531
+ let stopped = false;
2532
+ let termination;
2533
+ const emit = (event) => {
2534
+ events.push(event);
2535
+ options.emit?.(event);
2536
+ };
2537
+ const recordProtocolDecision = (event, decisionOptions) => {
2538
+ protocolDecisions.push(
2539
+ createReplayTraceProtocolDecision("coordinator", event, events.length - 1, decisionOptions)
2540
+ );
2541
+ };
2542
+ const toolExecutor = createRuntimeToolExecutor({
2543
+ runId,
2544
+ protocol: "coordinator",
2545
+ tier: options.tier,
2546
+ tools: options.tools,
2547
+ emit(event) {
2548
+ emit(event);
2549
+ recordProtocolDecision(event);
2550
+ },
2551
+ getTrace: () => ({ events, transcript }),
2552
+ ...options.signal !== void 0 ? { abortSignal: options.signal } : {}
2553
+ });
2554
+ const toolAvailability = runtimeToolAvailability(toolExecutor.tools);
2555
+ throwIfAborted(options.signal, options.model.id);
2556
+ for (const agent of activeAgents) {
2557
+ const event = {
2558
+ type: "role-assignment",
2559
+ runId,
2560
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2561
+ agentId: agent.id,
2562
+ role: agent.role
2563
+ };
2564
+ emit(event);
2565
+ recordProtocolDecision(event);
2566
+ }
2567
+ if (coordinator) {
2568
+ if (!stopIfNeeded()) {
2569
+ totalCost = await runCoordinatorTurn({
2570
+ agent: coordinator,
2571
+ coordinator,
2572
+ input: buildCoordinatorPlanInput(options.intent, coordinator),
2573
+ phase: "plan",
2574
+ options,
2575
+ runId,
2576
+ transcript,
2577
+ totalCost,
2578
+ providerCalls,
2579
+ toolExecutor,
2580
+ toolAvailability,
2581
+ emit,
2582
+ recordProtocolDecision
2583
+ });
2584
+ stopIfNeeded();
2585
+ }
2586
+ if (!stopIfNeeded()) {
2587
+ const workers = activeAgents.slice(1);
2588
+ const providerCallSlots = [];
2589
+ const planTranscript = [...transcript];
2590
+ const workerResults = await Promise.all(
2591
+ workers.map(
2592
+ (agent, index) => runCoordinatorWorkerTurn({
2593
+ agent,
2594
+ coordinator,
2595
+ input: buildWorkerInput(options.intent, planTranscript, coordinator),
2596
+ options,
2597
+ runId,
2598
+ turn: transcript.length + index + 1,
2599
+ providerCallId: providerCallIdFor$1(runId, providerCalls.length + index + 1),
2600
+ providerCallIndex: index,
2601
+ providerCallSlots,
2602
+ toolExecutor,
2603
+ toolAvailability,
2604
+ emit
2605
+ })
2606
+ )
2607
+ );
2608
+ providerCalls.push(...providerCallSlots.filter((call) => call !== void 0));
2609
+ for (const result of workerResults) {
2610
+ totalCost = addCost(totalCost, result.turnCost);
2611
+ transcript.push({
2612
+ agentId: result.agent.id,
2613
+ role: result.agent.role,
2614
+ input: result.input,
2615
+ output: result.response.text,
2616
+ ...result.decision !== void 0 ? { decision: result.decision } : {},
2617
+ ...result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {}
2618
+ });
2619
+ const event = {
2620
+ type: "agent-turn",
2621
+ runId,
2622
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2623
+ agentId: result.agent.id,
2624
+ role: result.agent.role,
2625
+ input: result.input,
2626
+ output: result.response.text,
2627
+ ...result.decision !== void 0 ? { decision: result.decision } : {},
2628
+ cost: totalCost
2629
+ };
2630
+ emit(event);
2631
+ recordProtocolDecision(event, {
2632
+ turn: transcript.length,
2633
+ phase: "worker",
2634
+ transcriptEntryCount: transcript.length
2635
+ });
2636
+ }
2637
+ stopIfNeeded();
2638
+ }
2639
+ if (!stopIfNeeded()) {
2640
+ totalCost = await runCoordinatorTurn({
2641
+ agent: coordinator,
2642
+ coordinator,
2643
+ input: buildFinalSynthesisInput(options.intent, transcript, coordinator),
2644
+ phase: "final-synthesis",
2645
+ options,
2646
+ runId,
2647
+ transcript,
2648
+ totalCost,
2649
+ providerCalls,
2650
+ toolExecutor,
2651
+ toolAvailability,
2652
+ emit,
2653
+ recordProtocolDecision
2654
+ });
2655
+ stopIfNeeded();
2656
+ }
2657
+ }
2658
+ const output = transcript.at(-1)?.output ?? "";
2659
+ throwIfAborted(options.signal, options.model.id);
2660
+ const final = {
2661
+ type: "final",
2662
+ runId,
2663
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2664
+ output,
2665
+ cost: totalCost,
2666
+ transcript: createTranscriptLink(transcript),
2667
+ ...termination !== void 0 ? { termination } : {}
2668
+ };
2669
+ emit(final);
2670
+ recordProtocolDecision(final, {
2671
+ transcriptEntryCount: transcript.length
2672
+ });
2673
+ const finalEvent = events.at(-1);
2674
+ return {
2675
+ output,
2676
+ eventLog: createRunEventLog(runId, "coordinator", events),
2677
+ trace: {
2678
+ schemaVersion: "1.0",
2679
+ runId,
2680
+ protocol: "coordinator",
2681
+ tier: options.tier,
2682
+ modelProviderId: options.model.id,
2683
+ agentsUsed: activeAgents,
2684
+ inputs: createReplayTraceRunInputs({
2685
+ intent: options.intent,
2686
+ protocol: options.protocol,
2687
+ tier: options.tier,
2688
+ modelProviderId: options.model.id,
2689
+ agents: activeAgents,
2690
+ temperature: options.temperature
2691
+ }),
2692
+ budget: createReplayTraceBudget({
2693
+ tier: options.tier,
2694
+ ...options.budget ? { caps: options.budget } : {},
2695
+ ...options.terminate ? { termination: options.terminate } : {}
2696
+ }),
2697
+ budgetStateChanges: createReplayTraceBudgetStateChanges(events),
2698
+ seed: createReplayTraceSeed(options.seed),
2699
+ protocolDecisions,
2700
+ providerCalls,
2701
+ finalOutput: createReplayTraceFinalOutput(output, finalEvent ?? {
2702
+ type: "final",
2703
+ at: "",
2704
+ cost: totalCost,
2705
+ transcript: createTranscriptLink(transcript)
2706
+ }),
2707
+ events,
2708
+ transcript
2709
+ },
2710
+ transcript,
2711
+ usage: createRunUsage(totalCost),
2712
+ metadata: createRunMetadata({
2713
+ runId,
2714
+ protocol: "coordinator",
2715
+ tier: options.tier,
2716
+ modelProviderId: options.model.id,
2717
+ agentsUsed: activeAgents,
2718
+ events
2719
+ }),
2720
+ accounting: createRunAccounting({
2721
+ tier: options.tier,
2722
+ ...options.budget ? { budget: options.budget } : {},
2723
+ ...options.terminate ? { termination: options.terminate } : {},
2724
+ cost: totalCost,
2725
+ events
2726
+ }),
2727
+ cost: totalCost
2728
+ };
2729
+ function stopIfNeeded() {
2730
+ throwIfAborted(options.signal, options.model.id);
2731
+ if (stopped || !options.terminate) {
2732
+ return stopped;
2733
+ }
2734
+ const stopRecord2 = evaluateTerminationStop(options.terminate, {
2735
+ protocol: "coordinator",
2736
+ tier: options.tier,
2737
+ cost: totalCost,
2738
+ transcript,
2739
+ iteration: transcript.length,
2740
+ elapsedMs: elapsedMs$2(startedAtMs)
2741
+ });
2742
+ if (!stopRecord2) {
2743
+ return false;
2744
+ }
2745
+ stopped = true;
2746
+ termination = stopRecord2;
2747
+ if (stopRecord2.reason === "budget") {
2748
+ emitBudgetStop(stopRecord2);
2749
+ }
2750
+ return true;
2751
+ }
2752
+ function emitBudgetStop(record) {
2753
+ const event = {
2754
+ type: "budget-stop",
2755
+ runId,
2756
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2757
+ reason: record.budgetReason ?? "cost",
2758
+ cost: totalCost,
2759
+ iteration: transcript.length,
2760
+ elapsedMs: elapsedMs$2(startedAtMs),
2761
+ detail: record.detail ?? {}
2762
+ };
2763
+ emit(event);
2764
+ recordProtocolDecision(event, {
2765
+ transcriptEntryCount: transcript.length
2766
+ });
2767
+ }
2768
+ }
2769
+ async function runCoordinatorTurn(turn) {
2770
+ throwIfAborted(turn.options.signal, turn.options.model.id);
2771
+ const request = {
2772
+ temperature: turn.options.temperature,
2773
+ ...turn.options.signal !== void 0 ? { signal: turn.options.signal } : {},
2774
+ metadata: {
2775
+ runId: turn.runId,
2776
+ protocol: "coordinator",
2777
+ agentId: turn.agent.id,
2778
+ role: turn.agent.role,
2779
+ coordinatorAgentId: turn.coordinator.id,
2780
+ tier: turn.options.tier,
2781
+ phase: turn.phase,
2782
+ ...turn.toolAvailability
2783
+ },
2784
+ messages: [
2785
+ {
2786
+ role: "system",
2787
+ content: buildSystemPrompt$2(turn.agent, turn.coordinator)
2788
+ },
2789
+ {
2790
+ role: "user",
2791
+ content: turn.input
2792
+ }
2793
+ ]
2794
+ };
2795
+ const response = await generateModelTurn({
2796
+ model: turn.options.model,
2797
+ request,
2798
+ runId: turn.runId,
2799
+ agent: turn.agent,
2800
+ input: turn.input,
2801
+ emit: turn.emit,
2802
+ callId: nextProviderCallId(turn.runId, turn.providerCalls),
2803
+ onProviderCall(call) {
2804
+ turn.providerCalls.push(call);
2805
+ }
2806
+ });
2807
+ const decision = parseAgentDecision(response.text);
2808
+ const totalCost = addCost(turn.totalCost, responseCost$2(response));
2809
+ const toolCalls = await executeModelResponseToolRequests({
2810
+ response,
2811
+ executor: turn.toolExecutor,
2812
+ agentId: turn.agent.id,
2813
+ role: turn.agent.role,
2814
+ turn: turn.transcript.length + 1,
2815
+ metadata: {
2816
+ phase: turn.phase
2817
+ }
2818
+ });
2819
+ throwIfAborted(turn.options.signal, turn.options.model.id);
2820
+ turn.transcript.push({
2821
+ agentId: turn.agent.id,
2822
+ role: turn.agent.role,
2823
+ input: turn.input,
2824
+ output: response.text,
2825
+ ...decision !== void 0 ? { decision } : {},
2826
+ ...toolCalls.length > 0 ? { toolCalls } : {}
2827
+ });
2828
+ const event = {
2829
+ type: "agent-turn",
2830
+ runId: turn.runId,
2831
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2832
+ agentId: turn.agent.id,
2833
+ role: turn.agent.role,
2834
+ input: turn.input,
2835
+ output: response.text,
2836
+ ...decision !== void 0 ? { decision } : {},
2837
+ cost: totalCost
2838
+ };
2839
+ turn.emit(event);
2840
+ turn.recordProtocolDecision(event, {
2841
+ turn: turn.transcript.length,
2842
+ phase: turn.phase,
2843
+ transcriptEntryCount: turn.transcript.length
2844
+ });
2845
+ return totalCost;
2846
+ }
2847
+ async function runCoordinatorWorkerTurn(turn) {
2848
+ throwIfAborted(turn.options.signal, turn.options.model.id);
2849
+ const request = {
2850
+ temperature: turn.options.temperature,
2851
+ ...turn.options.signal !== void 0 ? { signal: turn.options.signal } : {},
2852
+ metadata: {
2853
+ runId: turn.runId,
2854
+ protocol: "coordinator",
2855
+ agentId: turn.agent.id,
2856
+ role: turn.agent.role,
2857
+ coordinatorAgentId: turn.coordinator.id,
2858
+ tier: turn.options.tier,
2859
+ phase: "worker",
2860
+ ...turn.toolAvailability
2861
+ },
2862
+ messages: [
2863
+ {
2864
+ role: "system",
2865
+ content: buildSystemPrompt$2(turn.agent, turn.coordinator)
2866
+ },
2867
+ {
2868
+ role: "user",
2869
+ content: turn.input
2870
+ }
2871
+ ]
2872
+ };
2873
+ const response = await generateModelTurn({
2874
+ model: turn.options.model,
2875
+ request,
2876
+ runId: turn.runId,
2877
+ agent: turn.agent,
2878
+ input: turn.input,
2879
+ emit: turn.emit,
2880
+ callId: turn.providerCallId,
2881
+ onProviderCall(call) {
2882
+ turn.providerCallSlots[turn.providerCallIndex] = call;
2883
+ }
2884
+ });
2885
+ const decision = parseAgentDecision(response.text);
2886
+ const toolCalls = await executeModelResponseToolRequests({
2887
+ response,
2888
+ executor: turn.toolExecutor,
2889
+ agentId: turn.agent.id,
2890
+ role: turn.agent.role,
2891
+ turn: turn.turn,
2892
+ metadata: {
2893
+ phase: "worker"
2894
+ }
2895
+ });
2896
+ throwIfAborted(turn.options.signal, turn.options.model.id);
2897
+ return {
2898
+ agent: turn.agent,
2899
+ input: turn.input,
2900
+ response,
2901
+ decision,
2902
+ toolCalls,
2903
+ turnCost: responseCost$2(response)
2904
+ };
2905
+ }
2906
+ function buildSystemPrompt$2(agent, coordinator) {
2907
+ const instruction = agent.instructions ? `
2908
+ Instructions: ${agent.instructions}` : "";
2909
+ const coordinatorText = coordinator && agent.id === coordinator.id ? "You are the coordinator: assign work, integrate worker contributions, and produce the final answer." : `You are a worker managed by coordinator ${coordinator?.id ?? "unknown"}.`;
2910
+ return `You are ${agent.id}, acting as ${agent.role} in a Coordinator multi-agent protocol. ${coordinatorText}${instruction}`;
2911
+ }
2912
+ function buildCoordinatorPlanInput(intent, coordinator) {
2913
+ return `Mission: ${intent}
2914
+ Coordinator ${coordinator.id}: assign the work, name the plan, and provide the first contribution.`;
2915
+ }
2916
+ function buildWorkerInput(intent, transcript, coordinator) {
2917
+ const prior = transcript.map((entry) => `${entry.role} (${entry.agentId}): ${entry.output}`).join("\n\n");
2918
+ return `Mission: ${intent}
2919
+
2920
+ Coordinator: ${coordinator.id}
2921
+ Prior contributions:
2922
+ ${prior}
2923
+
2924
+ Follow the coordinator-managed plan and provide your assigned contribution.`;
2925
+ }
2926
+ function buildFinalSynthesisInput(intent, transcript, coordinator) {
2927
+ const prior = transcript.map((entry) => `${entry.role} (${entry.agentId}): ${entry.output}`).join("\n\n");
2928
+ return `Mission: ${intent}
2929
+
2930
+ Coordinator: ${coordinator.id}
2931
+ Prior contributions:
2932
+ ${prior}
2933
+
2934
+ Synthesize the final answer as the coordinator.`;
2935
+ }
2936
+ function responseCost$2(response) {
2937
+ return {
2938
+ usd: response.costUsd ?? 0,
2939
+ inputTokens: response.usage?.inputTokens ?? 0,
2940
+ outputTokens: response.usage?.outputTokens ?? 0,
2941
+ totalTokens: response.usage?.totalTokens ?? 0
2942
+ };
2943
+ }
2944
+ function createRunId$2() {
2945
+ const random = globalThis.crypto?.randomUUID?.();
2946
+ return random ?? `run-${Date.now().toString(36)}`;
2947
+ }
2948
+ function nowMs$2() {
2949
+ return globalThis.performance?.now() ?? Date.now();
2950
+ }
2951
+ function elapsedMs$2(startedAtMs) {
2952
+ return Math.max(0, nowMs$2() - startedAtMs);
2953
+ }
2954
+ function providerCallIdFor$1(runId, oneBasedIndex) {
2955
+ return `${runId}:provider-call:${oneBasedIndex}`;
2956
+ }
2957
+ async function runSequential(options) {
2958
+ const runId = createRunId$1();
2959
+ const events = [];
2960
+ const transcript = [];
2961
+ const protocolDecisions = [];
2962
+ const providerCalls = [];
2963
+ let totalCost = emptyCost();
2964
+ const maxTurns = options.protocol.maxTurns ?? options.agents.length;
2965
+ const activeAgents = options.agents.slice(0, maxTurns);
2966
+ const startedAtMs = nowMs$1();
2967
+ let stopped = false;
2968
+ let termination;
2969
+ const emit = (event) => {
2970
+ events.push(event);
2971
+ options.emit?.(event);
2972
+ };
2973
+ const recordProtocolDecision = (event, decisionOptions) => {
2974
+ protocolDecisions.push(
2975
+ createReplayTraceProtocolDecision("sequential", event, events.length - 1, decisionOptions)
2976
+ );
2977
+ };
2978
+ const toolExecutor = createRuntimeToolExecutor({
2979
+ runId,
2980
+ protocol: "sequential",
2981
+ tier: options.tier,
2982
+ tools: options.tools,
2983
+ emit(event) {
2984
+ emit(event);
2985
+ recordProtocolDecision(event);
2986
+ },
2987
+ getTrace: () => ({ events, transcript }),
2988
+ ...options.signal !== void 0 ? { abortSignal: options.signal } : {}
2989
+ });
2990
+ const toolAvailability = runtimeToolAvailability(toolExecutor.tools);
2991
+ throwIfAborted(options.signal, options.model.id);
2992
+ for (const agent of activeAgents) {
2993
+ const event = {
2994
+ type: "role-assignment",
2995
+ runId,
2996
+ at: (/* @__PURE__ */ new Date()).toISOString(),
2997
+ agentId: agent.id,
2998
+ role: agent.role
2999
+ };
3000
+ emit(event);
3001
+ recordProtocolDecision(event);
3002
+ }
3003
+ for (const [index, agent] of activeAgents.entries()) {
3004
+ if (stopIfNeeded()) {
3005
+ break;
3006
+ }
3007
+ const turn = index + 1;
3008
+ const input = buildSequentialInput(options.intent, transcript);
3009
+ const request = {
3010
+ temperature: options.temperature,
3011
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
3012
+ metadata: {
3013
+ runId,
3014
+ protocol: "sequential",
3015
+ agentId: agent.id,
3016
+ role: agent.role,
3017
+ tier: options.tier,
3018
+ turn,
3019
+ ...toolAvailability
3020
+ },
3021
+ messages: [
3022
+ {
3023
+ role: "system",
3024
+ content: buildSystemPrompt$1(agent)
3025
+ },
3026
+ {
3027
+ role: "user",
3028
+ content: input
3029
+ }
3030
+ ]
3031
+ };
3032
+ const response = await generateModelTurn({
3033
+ model: options.model,
3034
+ request,
3035
+ runId,
3036
+ agent,
3037
+ input,
3038
+ emit,
3039
+ callId: nextProviderCallId(runId, providerCalls),
3040
+ onProviderCall(call) {
3041
+ providerCalls.push(call);
3042
+ }
3043
+ });
3044
+ const turnCost = responseCost$1(response);
3045
+ totalCost = addCost(totalCost, turnCost);
3046
+ const decision = parseAgentDecision(response.text);
3047
+ const toolCalls = await executeModelResponseToolRequests({
3048
+ response,
3049
+ executor: toolExecutor,
3050
+ agentId: agent.id,
3051
+ role: agent.role,
3052
+ turn
3053
+ });
3054
+ throwIfAborted(options.signal, options.model.id);
3055
+ transcript.push({
3056
+ agentId: agent.id,
3057
+ role: agent.role,
3058
+ input,
3059
+ output: response.text,
3060
+ ...decision !== void 0 ? { decision } : {},
3061
+ ...toolCalls.length > 0 ? { toolCalls } : {}
3062
+ });
3063
+ const event = {
3064
+ type: "agent-turn",
3065
+ runId,
3066
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3067
+ agentId: agent.id,
3068
+ role: agent.role,
3069
+ input,
3070
+ output: response.text,
3071
+ ...decision !== void 0 ? { decision } : {},
3072
+ cost: totalCost
3073
+ };
3074
+ emit(event);
3075
+ recordProtocolDecision(event, {
3076
+ turn,
3077
+ transcriptEntryCount: transcript.length
3078
+ });
3079
+ if (stopIfNeeded()) {
3080
+ break;
3081
+ }
3082
+ }
3083
+ const output = [...transcript].reverse().find((entry) => isParticipatingDecision(entry.decision))?.output ?? "";
3084
+ throwIfAborted(options.signal, options.model.id);
3085
+ const final = {
3086
+ type: "final",
3087
+ runId,
3088
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3089
+ output,
3090
+ cost: totalCost,
3091
+ transcript: createTranscriptLink(transcript),
3092
+ ...termination !== void 0 ? { termination } : {}
3093
+ };
3094
+ emit(final);
3095
+ recordProtocolDecision(final, {
3096
+ transcriptEntryCount: transcript.length
3097
+ });
3098
+ const finalEvent = events.at(-1);
3099
+ return {
3100
+ output,
3101
+ eventLog: createRunEventLog(runId, "sequential", events),
3102
+ trace: {
3103
+ schemaVersion: "1.0",
3104
+ runId,
3105
+ protocol: "sequential",
3106
+ tier: options.tier,
3107
+ modelProviderId: options.model.id,
3108
+ agentsUsed: activeAgents,
3109
+ inputs: createReplayTraceRunInputs({
3110
+ intent: options.intent,
3111
+ protocol: options.protocol,
3112
+ tier: options.tier,
3113
+ modelProviderId: options.model.id,
3114
+ agents: activeAgents,
3115
+ temperature: options.temperature
3116
+ }),
3117
+ budget: createReplayTraceBudget({
3118
+ tier: options.tier,
3119
+ ...options.budget ? { caps: options.budget } : {},
3120
+ ...options.terminate ? { termination: options.terminate } : {}
3121
+ }),
3122
+ budgetStateChanges: createReplayTraceBudgetStateChanges(events),
3123
+ seed: createReplayTraceSeed(options.seed),
3124
+ protocolDecisions,
3125
+ providerCalls,
3126
+ finalOutput: createReplayTraceFinalOutput(output, finalEvent ?? events[0] ?? {
3127
+ type: "final",
3128
+ at: "",
3129
+ cost: totalCost,
3130
+ transcript: createTranscriptLink(transcript)
3131
+ }),
3132
+ events,
3133
+ transcript
3134
+ },
3135
+ transcript,
3136
+ usage: createRunUsage(totalCost),
3137
+ metadata: createRunMetadata({
3138
+ runId,
3139
+ protocol: "sequential",
3140
+ tier: options.tier,
3141
+ modelProviderId: options.model.id,
3142
+ agentsUsed: activeAgents,
3143
+ events
3144
+ }),
3145
+ accounting: createRunAccounting({
3146
+ tier: options.tier,
3147
+ ...options.budget ? { budget: options.budget } : {},
3148
+ ...options.terminate ? { termination: options.terminate } : {},
3149
+ cost: totalCost,
3150
+ events
3151
+ }),
3152
+ cost: totalCost
3153
+ };
3154
+ function stopIfNeeded() {
3155
+ throwIfAborted(options.signal, options.model.id);
3156
+ if (stopped || !options.terminate) {
3157
+ return stopped;
3158
+ }
3159
+ const stopRecord2 = evaluateTerminationStop(options.terminate, {
3160
+ protocol: "sequential",
3161
+ tier: options.tier,
3162
+ cost: totalCost,
3163
+ transcript,
3164
+ iteration: transcript.length,
3165
+ elapsedMs: elapsedMs$1(startedAtMs)
3166
+ });
3167
+ if (!stopRecord2) {
3168
+ return false;
3169
+ }
3170
+ stopped = true;
3171
+ termination = stopRecord2;
3172
+ if (stopRecord2.reason === "budget") {
3173
+ emitBudgetStop(stopRecord2);
3174
+ }
3175
+ return true;
3176
+ }
3177
+ function emitBudgetStop(record) {
3178
+ const event = {
3179
+ type: "budget-stop",
3180
+ runId,
3181
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3182
+ reason: record.budgetReason ?? "cost",
3183
+ cost: totalCost,
3184
+ iteration: transcript.length,
3185
+ elapsedMs: elapsedMs$1(startedAtMs),
3186
+ detail: record.detail ?? {}
3187
+ };
3188
+ emit(event);
3189
+ recordProtocolDecision(event, {
3190
+ transcriptEntryCount: transcript.length
3191
+ });
3192
+ }
3193
+ }
3194
+ function buildSystemPrompt$1(agent) {
3195
+ const instruction = agent.instructions ? `
3196
+ Instructions: ${agent.instructions}` : "";
3197
+ return `You are ${agent.id}, acting as ${agent.role} in a Sequential multi-agent protocol.${instruction}`;
3198
+ }
3199
+ function buildSequentialInput(intent, transcript) {
3200
+ if (transcript.length === 0) {
3201
+ return `Mission: ${intent}
3202
+ Provide your contribution.`;
3203
+ }
3204
+ const prior = transcript.map((entry) => `${entry.role} (${entry.agentId}): ${entry.output}`).join("\n\n");
3205
+ return `Mission: ${intent}
3206
+
3207
+ Prior contributions:
3208
+ ${prior}
3209
+
3210
+ Continue the sequence with a useful next contribution.`;
3211
+ }
3212
+ function responseCost$1(response) {
3213
+ return {
3214
+ usd: response.costUsd ?? 0,
3215
+ inputTokens: response.usage?.inputTokens ?? 0,
3216
+ outputTokens: response.usage?.outputTokens ?? 0,
3217
+ totalTokens: response.usage?.totalTokens ?? 0
3218
+ };
3219
+ }
3220
+ function createRunId$1() {
3221
+ const random = globalThis.crypto?.randomUUID?.();
3222
+ return random ?? `run-${Date.now().toString(36)}`;
3223
+ }
3224
+ function nowMs$1() {
3225
+ return globalThis.performance?.now() ?? Date.now();
3226
+ }
3227
+ function elapsedMs$1(startedAtMs) {
3228
+ return Math.max(0, nowMs$1() - startedAtMs);
3229
+ }
3230
+ async function runShared(options) {
3231
+ const runId = createRunId();
3232
+ const events = [];
3233
+ const transcript = [];
3234
+ const protocolDecisions = [];
3235
+ const providerCalls = [];
3236
+ let totalCost = emptyCost();
3237
+ const sharedState = options.protocol.organizationalMemory ?? "";
3238
+ const maxTurns = options.protocol.maxTurns ?? options.agents.length;
3239
+ const activeAgents = options.agents.slice(0, maxTurns);
3240
+ const startedAtMs = nowMs();
3241
+ let stopped = false;
3242
+ let termination;
3243
+ const emit = (event) => {
3244
+ events.push(event);
3245
+ options.emit?.(event);
3246
+ };
3247
+ const recordProtocolDecision = (event, decisionOptions) => {
3248
+ protocolDecisions.push(createReplayTraceProtocolDecision("shared", event, events.length - 1, decisionOptions));
3249
+ };
3250
+ const toolExecutor = createRuntimeToolExecutor({
3251
+ runId,
3252
+ protocol: "shared",
3253
+ tier: options.tier,
3254
+ tools: options.tools,
3255
+ emit(event) {
3256
+ emit(event);
3257
+ recordProtocolDecision(event);
3258
+ },
3259
+ getTrace: () => ({ events, transcript }),
3260
+ ...options.signal !== void 0 ? { abortSignal: options.signal } : {}
3261
+ });
3262
+ const toolAvailability = runtimeToolAvailability(toolExecutor.tools);
3263
+ throwIfAborted(options.signal, options.model.id);
3264
+ for (const agent of activeAgents) {
3265
+ const event = {
3266
+ type: "role-assignment",
3267
+ runId,
3268
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3269
+ agentId: agent.id,
3270
+ role: agent.role
3271
+ };
3272
+ emit(event);
3273
+ recordProtocolDecision(event);
3274
+ }
3275
+ if (!stopIfNeeded()) {
3276
+ const providerCallSlots = [];
3277
+ const turnResults = await Promise.all(
3278
+ activeAgents.map(async (agent, index) => {
3279
+ const turn = index + 1;
3280
+ const input = buildSharedInput(options.intent, sharedState, turn);
3281
+ const request = {
3282
+ temperature: options.temperature,
3283
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
3284
+ metadata: {
3285
+ runId,
3286
+ protocol: "shared",
3287
+ agentId: agent.id,
3288
+ role: agent.role,
3289
+ tier: options.tier,
3290
+ turn,
3291
+ ...toolAvailability
3292
+ },
3293
+ messages: [
3294
+ {
3295
+ role: "system",
3296
+ content: buildSystemPrompt(agent)
3297
+ },
3298
+ {
3299
+ role: "user",
3300
+ content: input
3301
+ }
3302
+ ]
3303
+ };
3304
+ const response = await generateModelTurn({
3305
+ model: options.model,
3306
+ request,
3307
+ runId,
3308
+ agent,
3309
+ input,
3310
+ emit,
3311
+ callId: providerCallIdFor(runId, providerCalls.length + index + 1),
3312
+ onProviderCall(call) {
3313
+ providerCallSlots[index] = call;
3314
+ }
3315
+ });
3316
+ const decision = parseAgentDecision(response.text);
3317
+ const toolCalls = await executeModelResponseToolRequests({
3318
+ response,
3319
+ executor: toolExecutor,
3320
+ agentId: agent.id,
3321
+ role: agent.role,
3322
+ turn
3323
+ });
3324
+ throwIfAborted(options.signal, options.model.id);
3325
+ return {
3326
+ agent,
3327
+ turn,
3328
+ input,
3329
+ response,
3330
+ decision,
3331
+ toolCalls,
3332
+ turnCost: responseCost(response)
3333
+ };
3334
+ })
3335
+ );
3336
+ providerCalls.push(...providerCallSlots.filter((call) => call !== void 0));
3337
+ for (const result of turnResults) {
3338
+ totalCost = addCost(totalCost, result.turnCost);
3339
+ transcript.push({
3340
+ agentId: result.agent.id,
3341
+ role: result.agent.role,
3342
+ input: result.input,
3343
+ output: result.response.text,
3344
+ ...result.decision !== void 0 ? { decision: result.decision } : {},
3345
+ ...result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {}
3346
+ });
3347
+ const event = {
3348
+ type: "agent-turn",
3349
+ runId,
3350
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3351
+ agentId: result.agent.id,
3352
+ role: result.agent.role,
3353
+ input: result.input,
3354
+ output: result.response.text,
3355
+ ...result.decision !== void 0 ? { decision: result.decision } : {},
3356
+ cost: totalCost
3357
+ };
3358
+ emit(event);
3359
+ recordProtocolDecision(event, {
3360
+ turn: result.turn,
3361
+ transcriptEntryCount: transcript.length
3362
+ });
3363
+ }
3364
+ stopIfNeeded();
3365
+ }
3366
+ const output = synthesizeSharedOutput(transcript);
3367
+ throwIfAborted(options.signal, options.model.id);
3368
+ const final = {
3369
+ type: "final",
3370
+ runId,
3371
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3372
+ output,
3373
+ cost: totalCost,
3374
+ transcript: createTranscriptLink(transcript),
3375
+ ...termination !== void 0 ? { termination } : {}
3376
+ };
3377
+ emit(final);
3378
+ recordProtocolDecision(final, {
3379
+ transcriptEntryCount: transcript.length
3380
+ });
3381
+ const finalEvent = events.at(-1);
3382
+ return {
3383
+ output,
3384
+ eventLog: createRunEventLog(runId, "shared", events),
3385
+ trace: {
3386
+ schemaVersion: "1.0",
3387
+ runId,
3388
+ protocol: "shared",
3389
+ tier: options.tier,
3390
+ modelProviderId: options.model.id,
3391
+ agentsUsed: activeAgents,
3392
+ inputs: createReplayTraceRunInputs({
3393
+ intent: options.intent,
3394
+ protocol: options.protocol,
3395
+ tier: options.tier,
3396
+ modelProviderId: options.model.id,
3397
+ agents: activeAgents,
3398
+ temperature: options.temperature
3399
+ }),
3400
+ budget: createReplayTraceBudget({
3401
+ tier: options.tier,
3402
+ ...options.budget ? { caps: options.budget } : {},
3403
+ ...options.terminate ? { termination: options.terminate } : {}
3404
+ }),
3405
+ budgetStateChanges: createReplayTraceBudgetStateChanges(events),
3406
+ seed: createReplayTraceSeed(options.seed),
3407
+ protocolDecisions,
3408
+ providerCalls,
3409
+ finalOutput: createReplayTraceFinalOutput(output, finalEvent ?? {
3410
+ type: "final",
3411
+ at: "",
3412
+ cost: totalCost,
3413
+ transcript: createTranscriptLink(transcript)
3414
+ }),
3415
+ events,
3416
+ transcript
3417
+ },
3418
+ transcript,
3419
+ usage: createRunUsage(totalCost),
3420
+ metadata: createRunMetadata({
3421
+ runId,
3422
+ protocol: "shared",
3423
+ tier: options.tier,
3424
+ modelProviderId: options.model.id,
3425
+ agentsUsed: activeAgents,
3426
+ events
3427
+ }),
3428
+ accounting: createRunAccounting({
3429
+ tier: options.tier,
3430
+ ...options.budget ? { budget: options.budget } : {},
3431
+ ...options.terminate ? { termination: options.terminate } : {},
3432
+ cost: totalCost,
3433
+ events
3434
+ }),
3435
+ cost: totalCost
3436
+ };
3437
+ function stopIfNeeded() {
3438
+ throwIfAborted(options.signal, options.model.id);
3439
+ if (stopped || !options.terminate) {
3440
+ return stopped;
3441
+ }
3442
+ const stopRecord2 = evaluateTerminationStop(options.terminate, {
3443
+ protocol: "shared",
3444
+ tier: options.tier,
3445
+ cost: totalCost,
3446
+ transcript,
3447
+ iteration: transcript.length,
3448
+ elapsedMs: elapsedMs(startedAtMs)
3449
+ });
3450
+ if (!stopRecord2) {
3451
+ return false;
3452
+ }
3453
+ stopped = true;
3454
+ termination = stopRecord2;
3455
+ if (stopRecord2.reason === "budget") {
3456
+ emitBudgetStop(stopRecord2);
3457
+ }
3458
+ return true;
3459
+ }
3460
+ function emitBudgetStop(record) {
3461
+ const event = {
3462
+ type: "budget-stop",
3463
+ runId,
3464
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3465
+ reason: record.budgetReason ?? "cost",
3466
+ cost: totalCost,
3467
+ iteration: transcript.length,
3468
+ elapsedMs: elapsedMs(startedAtMs),
3469
+ detail: record.detail ?? {}
3470
+ };
3471
+ emit(event);
3472
+ recordProtocolDecision(event, {
3473
+ transcriptEntryCount: transcript.length
3474
+ });
3475
+ }
3476
+ }
3477
+ function buildSystemPrompt(agent) {
3478
+ const instruction = agent.instructions ? `
3479
+ Instructions: ${agent.instructions}` : "";
3480
+ return `You are ${agent.id}, acting as ${agent.role} in a Shared multi-agent protocol. Read the shared state, update it with your best contribution, and preserve useful prior work.${instruction}`;
3481
+ }
3482
+ function buildSharedInput(intent, sharedState, turn) {
3483
+ const state = sharedState ? sharedState : "(empty)";
3484
+ return `Mission: ${intent}
3485
+ Shared turn ${turn}: read the shared state and return an improved shared-state update.
3486
+
3487
+ Shared state:
3488
+ ${state}`;
3489
+ }
3490
+ function synthesizeSharedOutput(transcript) {
3491
+ return transcript.map((entry) => `${entry.role}:${entry.agentId} => ${entry.output}`).join("\n");
3492
+ }
3493
+ function responseCost(response) {
3494
+ return {
3495
+ usd: response.costUsd ?? 0,
3496
+ inputTokens: response.usage?.inputTokens ?? 0,
3497
+ outputTokens: response.usage?.outputTokens ?? 0,
3498
+ totalTokens: response.usage?.totalTokens ?? 0
3499
+ };
3500
+ }
3501
+ function createRunId() {
3502
+ const random = globalThis.crypto?.randomUUID?.();
3503
+ return random ?? `run-${Date.now().toString(36)}`;
3504
+ }
3505
+ function nowMs() {
3506
+ return globalThis.performance?.now() ?? Date.now();
3507
+ }
3508
+ function elapsedMs(startedAtMs) {
3509
+ return Math.max(0, nowMs() - startedAtMs);
3510
+ }
3511
+ function providerCallIdFor(runId, oneBasedIndex) {
3512
+ return `${runId}:provider-call:${oneBasedIndex}`;
3513
+ }
3514
+ const defaultHighLevelProtocol = "sequential";
3515
+ const defaultHighLevelTier = "balanced";
3516
+ function createEngine(options) {
3517
+ validateEngineOptions(options);
3518
+ const protocol = normalizeProtocol(options.protocol);
3519
+ const tools = options.tools ?? [];
3520
+ const temperature = options.temperature ?? tierTemperature(options.tier);
3521
+ const agents = orderAgentsForTemperature(options.agents ?? defaultAgents(), temperature, options.seed);
3522
+ const terminate = options.terminate ?? (options.budget ? conditionFromBudget(options.budget) : void 0);
3523
+ return {
3524
+ run(intent) {
3525
+ validateMissionIntent(intent);
3526
+ return runNonStreamingProtocol({
3527
+ intent,
3528
+ protocol,
3529
+ tier: options.tier,
3530
+ model: options.model,
3531
+ agents,
3532
+ tools,
3533
+ temperature,
3534
+ ...options.budget ? { budget: options.budget } : {},
3535
+ ...options.seed !== void 0 ? { seed: options.seed } : {},
3536
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
3537
+ ...terminate ? { terminate } : {},
3538
+ ...options.evaluate ? { evaluate: options.evaluate } : {}
3539
+ });
3540
+ },
3541
+ stream(intent) {
3542
+ validateMissionIntent(intent);
3543
+ const pendingEvents = [];
3544
+ const pendingResolvers = [];
3545
+ const emittedEvents = [];
3546
+ const subscribers = /* @__PURE__ */ new Set();
3547
+ const abortController = new AbortController();
3548
+ const timeoutLifecycle = createTimeoutAbortLifecycle({
3549
+ abortController,
3550
+ timeoutMs: runtimeTimeoutMs({ budget: options.budget, terminate }),
3551
+ providerId: options.model.id
3552
+ });
3553
+ const abortRace = createAbortRace(abortController.signal, options.model.id);
3554
+ let complete = false;
3555
+ let lastRunId = "";
3556
+ let pendingFinalEvent;
3557
+ let status = "running";
3558
+ let resolveResult;
3559
+ let rejectResult;
3560
+ let removeCallerAbortListener = () => {
3561
+ };
3562
+ const result = new Promise((resolve, reject) => {
3563
+ resolveResult = resolve;
3564
+ rejectResult = reject;
3565
+ });
3566
+ removeCallerAbortListener = wireCallerAbortSignal(options.signal, abortController, cancelRun);
3567
+ void execute();
3568
+ return {
3569
+ get status() {
3570
+ return status;
3571
+ },
3572
+ result,
3573
+ cancel() {
3574
+ cancelRun();
3575
+ },
3576
+ subscribe(subscriber) {
3577
+ subscribers.add(subscriber);
3578
+ for (const event of emittedEvents) {
3579
+ subscriber(event);
3580
+ }
3581
+ return {
3582
+ unsubscribe() {
3583
+ subscribers.delete(subscriber);
3584
+ }
3585
+ };
3586
+ },
3587
+ [Symbol.asyncIterator]() {
3588
+ return {
3589
+ next() {
3590
+ const event = pendingEvents.shift();
3591
+ if (event) {
3592
+ return Promise.resolve({ done: false, value: event });
3593
+ }
3594
+ if (complete) {
3595
+ return Promise.resolve({ done: true, value: void 0 });
3596
+ }
3597
+ return new Promise((resolve) => {
3598
+ pendingResolvers.push(resolve);
3599
+ });
3600
+ }
3601
+ };
3602
+ }
3603
+ };
3604
+ async function execute() {
3605
+ if (status !== "running") {
3606
+ return;
3607
+ }
3608
+ try {
3609
+ const baseResult = await abortRace.run(runProtocol({
3610
+ intent,
3611
+ protocol,
3612
+ tier: options.tier,
3613
+ model: options.model,
3614
+ agents,
3615
+ tools,
3616
+ temperature,
3617
+ ...options.budget ? { budget: options.budget } : {},
3618
+ ...options.seed !== void 0 ? { seed: options.seed } : {},
3619
+ signal: abortController.signal,
3620
+ ...terminate ? { terminate } : {},
3621
+ emit(event) {
3622
+ if (status !== "running") {
3623
+ return;
3624
+ }
3625
+ lastRunId = event.runId;
3626
+ if (event.type === "final") {
3627
+ pendingFinalEvent = event;
3628
+ return;
3629
+ }
3630
+ publish(event);
3631
+ }
3632
+ }));
3633
+ if (status !== "running") {
3634
+ return;
3635
+ }
3636
+ const finalizedResult = await abortRace.run(applyRunEvaluation(baseResult, options.evaluate));
3637
+ if (status !== "running") {
3638
+ return;
3639
+ }
3640
+ const finalEvent = finalizedResult.trace.events.at(-1);
3641
+ if (finalEvent?.type === "final") {
3642
+ publish(finalEvent);
3643
+ } else if (pendingFinalEvent) {
3644
+ publish(pendingFinalEvent);
3645
+ }
3646
+ status = "completed";
3647
+ closeStream();
3648
+ resolveResult(finalizedResult);
3649
+ } catch (error) {
3650
+ if (isStreamHandleStatus(status, "cancelled")) {
3651
+ return;
3652
+ }
3653
+ const runtimeError = timeoutLifecycle.translateError(error);
3654
+ status = isCancellationError(runtimeError) ? "cancelled" : "failed";
3655
+ publish(createStreamErrorEvent(runtimeError, lastRunId));
3656
+ closeStream();
3657
+ rejectResult(runtimeError);
3658
+ }
3659
+ }
3660
+ function cancelRun(cause) {
3661
+ if (status !== "running") {
3662
+ return;
3663
+ }
3664
+ const error = createStreamCancellationError(options.model.id, cause);
3665
+ status = "cancelled";
3666
+ abortController.abort(error);
3667
+ publish(createStreamErrorEvent(error, lastRunId));
3668
+ closeStream();
3669
+ rejectResult(error);
3670
+ }
3671
+ function closeStream() {
3672
+ if (complete) {
3673
+ return;
3674
+ }
3675
+ complete = true;
3676
+ removeCallerAbortListener();
3677
+ timeoutLifecycle.cleanup();
3678
+ abortRace.cleanup();
3679
+ subscribers.clear();
3680
+ for (const resolver of pendingResolvers.splice(0)) {
3681
+ resolver({ done: true, value: void 0 });
3682
+ }
3683
+ }
3684
+ function publish(event) {
3685
+ if (complete) {
3686
+ return;
3687
+ }
3688
+ const canonicalEvent = canonicalizeSerializable(event);
3689
+ emittedEvents.push(canonicalEvent);
3690
+ for (const subscriber of subscribers) {
3691
+ try {
3692
+ subscriber(canonicalEvent);
3693
+ } catch {
3694
+ }
3695
+ }
3696
+ const resolver = pendingResolvers.shift();
3697
+ if (resolver) {
3698
+ resolver({ done: false, value: canonicalEvent });
3699
+ return;
3700
+ }
3701
+ pendingEvents.push(canonicalEvent);
3702
+ }
3703
+ }
3704
+ };
3705
+ }
3706
+ function isStreamHandleStatus(status, expected) {
3707
+ return status === expected;
3708
+ }
3709
+ function conditionFromBudget(budget$1) {
3710
+ return budget({
3711
+ ...budget$1.maxUsd !== void 0 ? { maxUsd: budget$1.maxUsd } : {},
3712
+ ...budget$1.maxTokens !== void 0 ? { maxTokens: budget$1.maxTokens } : {},
3713
+ ...budget$1.maxIterations !== void 0 ? { maxIterations: budget$1.maxIterations } : {},
3714
+ ...budget$1.timeoutMs !== void 0 ? { timeoutMs: budget$1.timeoutMs } : {}
3715
+ });
3716
+ }
3717
+ function createNonStreamingAbortLifecycle(options) {
3718
+ if (options.timeoutMs === void 0) {
3719
+ return {
3720
+ signal: options.callerSignal,
3721
+ async run(operation) {
3722
+ return await operation;
3723
+ },
3724
+ translateError(error) {
3725
+ return error;
3726
+ },
3727
+ cleanup() {
3728
+ }
3729
+ };
3730
+ }
3731
+ const abortController = new AbortController();
3732
+ const timeoutLifecycle = createTimeoutAbortLifecycle({
3733
+ abortController,
3734
+ timeoutMs: options.timeoutMs,
3735
+ providerId: options.providerId
3736
+ });
3737
+ const abortRace = createAbortRace(abortController.signal, options.providerId);
3738
+ const removeCallerAbortListener = wireCallerAbortSignal(options.callerSignal, abortController, () => {
3739
+ abortController.abort(readAbortSignalReason(options.callerSignal));
3740
+ });
3741
+ return {
3742
+ signal: abortController.signal,
3743
+ async run(operation) {
3744
+ return await abortRace.run(operation);
3745
+ },
3746
+ translateError(error) {
3747
+ return timeoutLifecycle.translateError(error);
3748
+ },
3749
+ cleanup() {
3750
+ timeoutLifecycle.cleanup();
3751
+ abortRace.cleanup();
3752
+ removeCallerAbortListener();
3753
+ }
3754
+ };
3755
+ }
3756
+ function createTimeoutAbortLifecycle(options) {
3757
+ if (options.timeoutMs === void 0) {
3758
+ return {
3759
+ translateError(error) {
3760
+ return error;
3761
+ },
3762
+ cleanup() {
3763
+ }
3764
+ };
3765
+ }
3766
+ const timeoutError = createTimeoutError(options.providerId, options.timeoutMs);
3767
+ const timeoutId = setTimeout(() => {
3768
+ options.abortController.abort(timeoutError);
3769
+ }, options.timeoutMs);
3770
+ return {
3771
+ translateError(error) {
3772
+ return options.abortController.signal.reason === timeoutError ? timeoutError : error;
3773
+ },
3774
+ cleanup() {
3775
+ clearTimeout(timeoutId);
3776
+ }
3777
+ };
3778
+ }
3779
+ function createAbortRace(signal, providerId) {
3780
+ let cleanupAbortListener = () => {
3781
+ };
3782
+ return {
3783
+ signal,
3784
+ async run(operation) {
3785
+ if (signal.aborted) {
3786
+ throw createAbortErrorFromSignal(signal, providerId);
3787
+ }
3788
+ const abortPromise = new Promise((_, reject) => {
3789
+ const abortHandler = () => {
3790
+ cleanupAbortListener();
3791
+ reject(createAbortErrorFromSignal(signal, providerId));
3792
+ };
3793
+ cleanupAbortListener = () => {
3794
+ signal.removeEventListener("abort", abortHandler);
3795
+ };
3796
+ signal.addEventListener("abort", abortHandler, { once: true });
3797
+ });
3798
+ try {
3799
+ return await Promise.race([operation, abortPromise]);
3800
+ } finally {
3801
+ cleanupAbortListener();
3802
+ cleanupAbortListener = () => {
3803
+ };
3804
+ }
3805
+ },
3806
+ translateError(error) {
3807
+ return error;
3808
+ },
3809
+ cleanup() {
3810
+ cleanupAbortListener();
3811
+ cleanupAbortListener = () => {
3812
+ };
3813
+ }
3814
+ };
3815
+ }
3816
+ function runtimeTimeoutMs(options) {
3817
+ const budgetTimeoutMs = options.budget?.timeoutMs;
3818
+ const terminationTimeoutMs = timeoutMsFromTermination(options.terminate);
3819
+ if (budgetTimeoutMs === void 0) {
3820
+ return terminationTimeoutMs;
3821
+ }
3822
+ if (terminationTimeoutMs === void 0) {
3823
+ return budgetTimeoutMs;
3824
+ }
3825
+ return Math.min(budgetTimeoutMs, terminationTimeoutMs);
3826
+ }
3827
+ function timeoutMsFromTermination(condition) {
3828
+ if (!condition) {
3829
+ return void 0;
3830
+ }
3831
+ switch (condition.kind) {
3832
+ case "budget":
3833
+ return condition.timeoutMs;
3834
+ case "firstOf":
3835
+ return condition.conditions.reduce((current, child) => {
3836
+ const childTimeoutMs = timeoutMsFromTermination(child);
3837
+ if (childTimeoutMs === void 0) {
3838
+ return current;
3839
+ }
3840
+ return current === void 0 ? childTimeoutMs : Math.min(current, childTimeoutMs);
3841
+ }, void 0);
3842
+ case "convergence":
3843
+ case "judge":
3844
+ return void 0;
3845
+ }
3846
+ }
3847
+ function readAbortSignalReason(signal) {
3848
+ return signal?.aborted ? signal.reason : void 0;
3849
+ }
3850
+ function createStreamErrorEvent(error, runId) {
3851
+ if (DogpileError.isInstance(error)) {
3852
+ return {
3853
+ type: "error",
3854
+ runId,
3855
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3856
+ name: error.name,
3857
+ message: error.message,
3858
+ detail: dogpileErrorStreamDetail(error)
3859
+ };
3860
+ }
3861
+ if (error instanceof Error) {
3862
+ return {
3863
+ type: "error",
3864
+ runId,
3865
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3866
+ name: error.name,
3867
+ message: error.message
3868
+ };
3869
+ }
3870
+ return {
3871
+ type: "error",
3872
+ runId,
3873
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3874
+ name: "Error",
3875
+ message: String(error)
3876
+ };
3877
+ }
3878
+ function dogpileErrorStreamDetail(error) {
3879
+ const detail = {
3880
+ code: error.code
3881
+ };
3882
+ if (error.providerId !== void 0) {
3883
+ detail.providerId = error.providerId;
3884
+ }
3885
+ if (error.retryable !== void 0) {
3886
+ detail.retryable = error.retryable;
3887
+ }
3888
+ if (error.detail !== void 0) {
3889
+ for (const [key, value] of Object.entries(error.detail)) {
3890
+ detail[key] = value;
3891
+ }
3892
+ }
3893
+ return detail;
3894
+ }
3895
+ async function runNonStreamingProtocol(options) {
3896
+ const abortLifecycle = createNonStreamingAbortLifecycle({
3897
+ callerSignal: options.signal,
3898
+ timeoutMs: runtimeTimeoutMs(options),
3899
+ providerId: options.model.id
3900
+ });
3901
+ try {
3902
+ const emittedEvents = [];
3903
+ const result = await abortLifecycle.run(runProtocol({
3904
+ ...options,
3905
+ ...abortLifecycle.signal !== void 0 ? { signal: abortLifecycle.signal } : {},
3906
+ emit(event) {
3907
+ emittedEvents.push(event);
3908
+ }
3909
+ }));
3910
+ const events = emittedEvents.length > 0 ? emittedEvents : result.trace.events;
3911
+ const trace = {
3912
+ ...result.trace,
3913
+ events,
3914
+ budgetStateChanges: createReplayTraceBudgetStateChanges(events),
3915
+ finalOutput: createReplayTraceFinalOutput(result.output, events.at(-1) ?? result.trace.events.at(-1))
3916
+ };
3917
+ const runResult = {
3918
+ ...result,
3919
+ accounting: createRunAccounting({
3920
+ tier: trace.tier,
3921
+ ...trace.budget.caps ? { budget: trace.budget.caps } : {},
3922
+ ...trace.budget.termination ? { termination: trace.budget.termination } : {},
3923
+ cost: result.cost,
3924
+ events
3925
+ }),
3926
+ eventLog: createRunEventLog(trace.runId, trace.protocol, events),
3927
+ trace
3928
+ };
3929
+ return canonicalizeRunResult(await abortLifecycle.run(applyRunEvaluation(runResult, options.evaluate)));
3930
+ } catch (error) {
3931
+ throw abortLifecycle.translateError(error);
3932
+ } finally {
3933
+ abortLifecycle.cleanup();
3934
+ }
3935
+ }
3936
+ async function applyRunEvaluation(result, evaluate) {
3937
+ if (!evaluate) {
3938
+ return canonicalizeRunResult(result);
3939
+ }
3940
+ const evaluation = await evaluate(result);
3941
+ const events = result.trace.events.map((event, index) => {
3942
+ if (index !== result.trace.events.length - 1 || event.type !== "final") {
3943
+ return event;
3944
+ }
3945
+ return finalEventWithEvaluation(event, evaluation);
3946
+ });
3947
+ const trace = {
3948
+ ...result.trace,
3949
+ events
3950
+ };
3951
+ return canonicalizeRunResult({
3952
+ ...result,
3953
+ quality: evaluation.quality,
3954
+ evaluation,
3955
+ trace,
3956
+ eventLog: createRunEventLog(trace.runId, trace.protocol, events)
3957
+ });
3958
+ }
3959
+ function finalEventWithEvaluation(event, evaluation) {
3960
+ return {
3961
+ ...event,
3962
+ quality: evaluation.quality,
3963
+ evaluation
3964
+ };
3965
+ }
3966
+ function runProtocol(options) {
3967
+ switch (options.protocol.kind) {
3968
+ case "sequential":
3969
+ return runSequential({
3970
+ intent: options.intent,
3971
+ protocol: options.protocol,
3972
+ tier: options.tier,
3973
+ model: options.model,
3974
+ agents: options.agents,
3975
+ tools: options.tools,
3976
+ temperature: options.temperature,
3977
+ ...options.budget ? { budget: options.budget } : {},
3978
+ ...options.seed !== void 0 ? { seed: options.seed } : {},
3979
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
3980
+ ...options.terminate ? { terminate: options.terminate } : {},
3981
+ ...options.emit ? { emit: options.emit } : {}
3982
+ });
3983
+ case "broadcast":
3984
+ return runBroadcast({
3985
+ intent: options.intent,
3986
+ protocol: options.protocol,
3987
+ tier: options.tier,
3988
+ model: options.model,
3989
+ agents: options.agents,
3990
+ tools: options.tools,
3991
+ temperature: options.temperature,
3992
+ ...options.budget ? { budget: options.budget } : {},
3993
+ ...options.seed !== void 0 ? { seed: options.seed } : {},
3994
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
3995
+ ...options.terminate ? { terminate: options.terminate } : {},
3996
+ ...options.emit ? { emit: options.emit } : {}
3997
+ });
3998
+ case "coordinator":
3999
+ return runCoordinator({
4000
+ intent: options.intent,
4001
+ protocol: options.protocol,
4002
+ tier: options.tier,
4003
+ model: options.model,
4004
+ agents: options.agents,
4005
+ tools: options.tools,
4006
+ temperature: options.temperature,
4007
+ ...options.budget ? { budget: options.budget } : {},
4008
+ ...options.seed !== void 0 ? { seed: options.seed } : {},
4009
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
4010
+ ...options.terminate ? { terminate: options.terminate } : {},
4011
+ ...options.emit ? { emit: options.emit } : {}
4012
+ });
4013
+ case "shared":
4014
+ return runShared({
4015
+ intent: options.intent,
4016
+ protocol: options.protocol,
4017
+ tier: options.tier,
4018
+ model: options.model,
4019
+ agents: options.agents,
4020
+ tools: options.tools,
4021
+ temperature: options.temperature,
4022
+ ...options.budget ? { budget: options.budget } : {},
4023
+ ...options.seed !== void 0 ? { seed: options.seed } : {},
4024
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
4025
+ ...options.terminate ? { terminate: options.terminate } : {},
4026
+ ...options.emit ? { emit: options.emit } : {}
4027
+ });
4028
+ }
4029
+ }
4030
+ function run(options) {
4031
+ validateDogpileOptions(options);
4032
+ const { intent, ...engineOptions } = withHighLevelDefaults(options);
4033
+ return createEngine(engineOptions).run(intent);
4034
+ }
4035
+ function stream(options) {
4036
+ validateDogpileOptions(options);
4037
+ const { intent, ...engineOptions } = withHighLevelDefaults(options);
4038
+ return createEngine(engineOptions).stream(intent);
4039
+ }
4040
+ function replay(trace) {
4041
+ const cost = trace.finalOutput.cost;
4042
+ const lastEvent = trace.events.at(-1);
4043
+ const baseResult = {
4044
+ output: trace.finalOutput.output,
4045
+ eventLog: createRunEventLog(trace.runId, trace.protocol, trace.events),
4046
+ trace,
4047
+ transcript: trace.transcript,
4048
+ usage: createRunUsage(cost),
4049
+ metadata: createRunMetadata({
4050
+ runId: trace.runId,
4051
+ protocol: trace.protocol,
4052
+ tier: trace.tier,
4053
+ modelProviderId: trace.modelProviderId,
4054
+ agentsUsed: trace.agentsUsed,
4055
+ events: trace.events
4056
+ }),
4057
+ accounting: createRunAccounting({
4058
+ tier: trace.tier,
4059
+ ...trace.budget.caps ? { budget: trace.budget.caps } : {},
4060
+ ...trace.budget.termination ? { termination: trace.budget.termination } : {},
4061
+ cost,
4062
+ events: trace.events
4063
+ }),
4064
+ cost
4065
+ };
4066
+ if (lastEvent?.type !== "final") {
4067
+ return baseResult;
4068
+ }
4069
+ return {
4070
+ ...baseResult,
4071
+ ...lastEvent.quality !== void 0 ? { quality: lastEvent.quality } : {},
4072
+ ...lastEvent.evaluation !== void 0 ? { evaluation: lastEvent.evaluation } : {}
4073
+ };
4074
+ }
4075
+ function replayStream(trace) {
4076
+ const result = Promise.resolve(replay(trace));
4077
+ return {
4078
+ get status() {
4079
+ return "completed";
4080
+ },
4081
+ result,
4082
+ cancel() {
4083
+ },
4084
+ subscribe(subscriber) {
4085
+ for (const event of trace.events) {
4086
+ subscriber(event);
4087
+ }
4088
+ return {
4089
+ unsubscribe() {
4090
+ }
4091
+ };
4092
+ },
4093
+ [Symbol.asyncIterator]() {
4094
+ let index = 0;
4095
+ return {
4096
+ next() {
4097
+ const event = trace.events[index];
4098
+ if (event) {
4099
+ index += 1;
4100
+ return Promise.resolve({ done: false, value: event });
4101
+ }
4102
+ return Promise.resolve({ done: true, value: void 0 });
4103
+ }
4104
+ };
4105
+ }
4106
+ };
4107
+ }
4108
+ function wireCallerAbortSignal(callerSignal, abortController, cancelRun) {
4109
+ if (!callerSignal) {
4110
+ return () => {
4111
+ };
4112
+ }
4113
+ const cancelFromCaller = () => {
4114
+ cancelRun(readAbortSignalReason(callerSignal));
4115
+ };
4116
+ if (callerSignal.aborted) {
4117
+ cancelFromCaller();
4118
+ return () => {
4119
+ };
4120
+ }
4121
+ callerSignal.addEventListener("abort", cancelFromCaller, { once: true });
4122
+ const remove = () => {
4123
+ callerSignal.removeEventListener("abort", cancelFromCaller);
4124
+ };
4125
+ abortController.signal.addEventListener("abort", remove, { once: true });
4126
+ return remove;
4127
+ }
4128
+ function createStreamCancellationError(providerId, cause) {
4129
+ return new DogpileError({
4130
+ code: "aborted",
4131
+ message: "The operation was aborted.",
4132
+ retryable: false,
4133
+ providerId,
4134
+ ...cause !== void 0 ? { cause } : {},
4135
+ detail: {
4136
+ status: "cancelled"
4137
+ }
4138
+ });
4139
+ }
4140
+ function isCancellationError(error) {
4141
+ if (DogpileError.isInstance(error)) {
4142
+ return error.code === "aborted";
4143
+ }
4144
+ return error instanceof Error && error.name === "AbortError";
4145
+ }
4146
+ function withHighLevelDefaults(options) {
4147
+ return {
4148
+ ...options,
4149
+ protocol: options.protocol ?? defaultHighLevelProtocol,
4150
+ tier: options.tier ?? defaultHighLevelTier
4151
+ };
4152
+ }
4153
+ function pile(options) {
4154
+ return run(options);
4155
+ }
4156
+ const Dogpile = {
4157
+ pile,
4158
+ replay,
4159
+ replayStream,
4160
+ stream,
4161
+ createEngine
4162
+ };
4163
+ const defaultBaseURL = "https://api.openai.com/v1";
4164
+ const defaultPath = "/chat/completions";
4165
+ function createOpenAICompatibleProvider(options) {
4166
+ validateOptions(options);
4167
+ const providerId = options.id ?? `openai-compatible:${options.model}`;
4168
+ const fetchImplementation = options.fetch ?? globalThis.fetch?.bind(globalThis);
4169
+ if (!fetchImplementation) {
4170
+ throw new DogpileError({
4171
+ code: "invalid-configuration",
4172
+ message: "createOpenAICompatibleProvider() requires a fetch implementation in this runtime.",
4173
+ retryable: false,
4174
+ providerId,
4175
+ detail: {
4176
+ kind: "configuration-validation",
4177
+ path: "fetch",
4178
+ expected: "a fetch-compatible function"
4179
+ }
4180
+ });
4181
+ }
4182
+ return {
4183
+ id: providerId,
4184
+ async generate(request) {
4185
+ const response = await fetchImplementation(createURL(options), {
4186
+ method: "POST",
4187
+ headers: createHeaders(options),
4188
+ body: JSON.stringify(createBody(options, request)),
4189
+ ...request.signal !== void 0 ? { signal: request.signal } : {}
4190
+ });
4191
+ const payload = await readJson(response, providerId);
4192
+ if (!response.ok) {
4193
+ throw createProviderError(response, payload, providerId);
4194
+ }
4195
+ const completion = asChatCompletionResponse(payload, providerId);
4196
+ const text = readAssistantText(completion, providerId);
4197
+ const usage = normalizeUsage(completion.usage);
4198
+ const finishReason = normalizeFinishReason(completion.choices?.[0]?.finish_reason);
4199
+ const costUsd = options.costEstimator?.({
4200
+ providerId,
4201
+ request,
4202
+ response: completion,
4203
+ ...usage ? { usage } : {}
4204
+ });
4205
+ return {
4206
+ text,
4207
+ ...finishReason !== void 0 ? { finishReason } : {},
4208
+ ...usage ? { usage } : {},
4209
+ ...costUsd !== void 0 ? { costUsd } : {},
4210
+ metadata: {
4211
+ openAICompatible: responseMetadata(completion)
4212
+ }
4213
+ };
4214
+ }
4215
+ };
4216
+ }
4217
+ function validateOptions(options) {
4218
+ if (!isRecord(options)) {
4219
+ throwInvalid("options", "an options object");
4220
+ }
4221
+ if (!isNonEmptyString(options.model)) {
4222
+ throwInvalid("model", "a non-empty model id");
4223
+ }
4224
+ if (options.apiKey !== void 0 && !isNonEmptyString(options.apiKey)) {
4225
+ throwInvalid("apiKey", "a non-empty API key when provided");
4226
+ }
4227
+ if (options.id !== void 0 && !isNonEmptyString(options.id)) {
4228
+ throwInvalid("id", "a non-empty provider id when provided");
4229
+ }
4230
+ if (options.path !== void 0 && !isNonEmptyString(options.path)) {
4231
+ throwInvalid("path", "a non-empty request path when provided");
4232
+ }
4233
+ if (options.fetch !== void 0 && typeof options.fetch !== "function") {
4234
+ throwInvalid("fetch", "a fetch-compatible function when provided");
4235
+ }
4236
+ if (options.maxOutputTokens !== void 0 && (!Number.isInteger(options.maxOutputTokens) || options.maxOutputTokens <= 0)) {
4237
+ throwInvalid("maxOutputTokens", "a positive integer when provided");
4238
+ }
4239
+ if (options.costEstimator !== void 0 && typeof options.costEstimator !== "function") {
4240
+ throwInvalid("costEstimator", "a function when provided");
4241
+ }
4242
+ }
4243
+ function throwInvalid(path, expected) {
4244
+ throw new DogpileError({
4245
+ code: "invalid-configuration",
4246
+ message: `Invalid OpenAI-compatible provider option at ${path}.`,
4247
+ retryable: false,
4248
+ detail: {
4249
+ kind: "configuration-validation",
4250
+ path,
4251
+ expected
4252
+ }
4253
+ });
4254
+ }
4255
+ function createURL(options) {
4256
+ const baseURL = new URL(String(options.baseURL ?? defaultBaseURL));
4257
+ const path = options.path ?? defaultPath;
4258
+ return new URL(path.startsWith("/") ? path.slice(1) : path, ensureTrailingSlash(baseURL));
4259
+ }
4260
+ function ensureTrailingSlash(url) {
4261
+ const next = new URL(url);
4262
+ if (!next.pathname.endsWith("/")) {
4263
+ next.pathname = `${next.pathname}/`;
4264
+ }
4265
+ return next;
4266
+ }
4267
+ function createHeaders(options) {
4268
+ const headers = new Headers();
4269
+ for (const [key, value] of Object.entries(options.headers ?? {})) {
4270
+ if (value !== void 0) {
4271
+ headers.set(key, value);
4272
+ }
4273
+ }
4274
+ headers.set("content-type", "application/json");
4275
+ if (options.apiKey !== void 0 && !headers.has("authorization")) {
4276
+ headers.set("authorization", `Bearer ${options.apiKey}`);
4277
+ }
4278
+ return headers;
4279
+ }
4280
+ function createBody(options, request) {
4281
+ return {
4282
+ ...options.extraBody ?? {},
4283
+ model: options.model,
4284
+ messages: request.messages.map(toChatMessage),
4285
+ temperature: request.temperature,
4286
+ ...options.maxOutputTokens !== void 0 ? { max_tokens: options.maxOutputTokens } : {}
4287
+ };
4288
+ }
4289
+ function toChatMessage(message) {
4290
+ return {
4291
+ role: message.role,
4292
+ content: message.content
4293
+ };
4294
+ }
4295
+ async function readJson(response, providerId) {
4296
+ try {
4297
+ return await response.json();
4298
+ } catch (error) {
4299
+ throw new DogpileError({
4300
+ code: "provider-invalid-response",
4301
+ message: "OpenAI-compatible provider returned a non-JSON response.",
4302
+ cause: error,
4303
+ retryable: response.status >= 500,
4304
+ providerId,
4305
+ detail: {
4306
+ statusCode: response.status,
4307
+ statusText: response.statusText
4308
+ }
4309
+ });
4310
+ }
4311
+ }
4312
+ function asChatCompletionResponse(payload, providerId) {
4313
+ if (!isRecord(payload)) {
4314
+ throw new DogpileError({
4315
+ code: "provider-invalid-response",
4316
+ message: "OpenAI-compatible provider response must be a JSON object.",
4317
+ retryable: true,
4318
+ providerId
4319
+ });
4320
+ }
4321
+ return payload;
4322
+ }
4323
+ function readAssistantText(response, providerId) {
4324
+ const content = response.choices?.[0]?.message?.content;
4325
+ const text = normalizeContent(content);
4326
+ if (!text) {
4327
+ throw new DogpileError({
4328
+ code: "provider-invalid-response",
4329
+ message: "OpenAI-compatible provider response did not include assistant text.",
4330
+ retryable: true,
4331
+ providerId
4332
+ });
4333
+ }
4334
+ return text;
4335
+ }
4336
+ function normalizeContent(content) {
4337
+ if (typeof content === "string") {
4338
+ return content;
4339
+ }
4340
+ if (!Array.isArray(content)) {
4341
+ return "";
4342
+ }
4343
+ return content.map((part) => {
4344
+ if (!isRecord(part)) {
4345
+ return "";
4346
+ }
4347
+ const text = part.text;
4348
+ return typeof text === "string" ? text : "";
4349
+ }).filter(Boolean).join("");
4350
+ }
4351
+ function normalizeUsage(usage) {
4352
+ if (!usage) {
4353
+ return void 0;
4354
+ }
4355
+ const inputTokens = readTokenCount(usage.prompt_tokens ?? usage.input_tokens);
4356
+ const outputTokens = readTokenCount(usage.completion_tokens ?? usage.output_tokens);
4357
+ const totalTokens = readTokenCount(usage.total_tokens) ?? sumIfPresent(inputTokens, outputTokens);
4358
+ if (inputTokens === void 0 || outputTokens === void 0 || totalTokens === void 0) {
4359
+ return void 0;
4360
+ }
4361
+ return {
4362
+ inputTokens,
4363
+ outputTokens,
4364
+ totalTokens
4365
+ };
4366
+ }
4367
+ function readTokenCount(value) {
4368
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
4369
+ }
4370
+ function sumIfPresent(left, right) {
4371
+ return left === void 0 || right === void 0 ? void 0 : left + right;
4372
+ }
4373
+ function normalizeFinishReason(reason) {
4374
+ switch (reason) {
4375
+ case "stop":
4376
+ return "stop";
4377
+ case "length":
4378
+ return "length";
4379
+ case "content_filter":
4380
+ case "content-filter":
4381
+ return "content-filter";
4382
+ case "tool_calls":
4383
+ case "tool-calls":
4384
+ return "tool-calls";
4385
+ case void 0:
4386
+ case null:
4387
+ return void 0;
4388
+ default:
4389
+ return "other";
4390
+ }
4391
+ }
4392
+ function responseMetadata(response) {
4393
+ return removeUndefined({
4394
+ id: response.id,
4395
+ object: response.object,
4396
+ created: response.created,
4397
+ model: response.model,
4398
+ usage: isJsonValue(response.usage) ? response.usage : void 0
4399
+ });
4400
+ }
4401
+ function createProviderError(response, payload, providerId) {
4402
+ return new DogpileError({
4403
+ code: codeForStatus(response.status),
4404
+ message: errorMessage(response, payload),
4405
+ retryable: response.status === 408 || response.status === 429 || response.status >= 500,
4406
+ providerId,
4407
+ detail: removeUndefined({
4408
+ statusCode: response.status,
4409
+ statusText: response.statusText,
4410
+ response: isJsonValue(payload) ? payload : void 0
4411
+ })
4412
+ });
4413
+ }
4414
+ function codeForStatus(status) {
4415
+ if (status === 401 || status === 403) {
4416
+ return "provider-authentication";
4417
+ }
4418
+ if (status === 404) {
4419
+ return "provider-not-found";
4420
+ }
4421
+ if (status === 408 || status === 504) {
4422
+ return "provider-timeout";
4423
+ }
4424
+ if (status === 429) {
4425
+ return "provider-rate-limited";
4426
+ }
4427
+ if (status >= 500) {
4428
+ return "provider-unavailable";
4429
+ }
4430
+ if (status >= 400) {
4431
+ return "provider-invalid-request";
4432
+ }
4433
+ return "provider-error";
4434
+ }
4435
+ function errorMessage(response, payload) {
4436
+ const providerMessage = isRecord(payload) && isRecord(payload.error) && typeof payload.error.message === "string" ? payload.error.message : void 0;
4437
+ return providerMessage ?? `OpenAI-compatible provider request failed with HTTP ${response.status}.`;
4438
+ }
4439
+ function removeUndefined(values) {
4440
+ return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
4441
+ }
4442
+ function isRecord(value) {
4443
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4444
+ }
4445
+ function isNonEmptyString(value) {
4446
+ return typeof value === "string" && value.trim().length > 0;
4447
+ }
4448
+ function isJsonValue(value) {
4449
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4450
+ return typeof value !== "number" || Number.isFinite(value);
4451
+ }
4452
+ if (Array.isArray(value)) {
4453
+ return value.every(isJsonValue);
4454
+ }
4455
+ if (isRecord(value)) {
4456
+ return Object.values(value).every(isJsonValue);
4457
+ }
4458
+ return false;
4459
+ }
4460
+ export {
4461
+ Dogpile,
4462
+ DogpileError,
4463
+ budget,
4464
+ builtInDogpileToolIdentity,
4465
+ builtInDogpileToolInputSchema,
4466
+ builtInDogpileToolPermissions,
4467
+ combineTerminationDecisions,
4468
+ convergence,
4469
+ createCodeExecToolAdapter,
4470
+ createEngine,
4471
+ createOpenAICompatibleProvider,
4472
+ createRuntimeToolExecutor,
4473
+ createWebSearchToolAdapter,
4474
+ evaluateBudget,
4475
+ evaluateConvergence,
4476
+ evaluateFirstOf,
4477
+ evaluateJudge,
4478
+ evaluateTermination,
4479
+ evaluateTerminationStop,
4480
+ firstOf,
4481
+ judge,
4482
+ normalizeBuiltInDogpileTool,
4483
+ normalizeBuiltInDogpileTools,
4484
+ normalizeRuntimeToolAdapterError,
4485
+ replay,
4486
+ replayStream,
4487
+ run,
4488
+ runtimeToolAvailability,
4489
+ runtimeToolManifest,
4490
+ stream,
4491
+ validateBuiltInDogpileToolInput
4492
+ };
4493
+ //# sourceMappingURL=index.js.map