@dogpile/sdk 0.4.0 → 0.6.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.
- package/CHANGELOG.md +92 -0
- package/dist/browser/index.js +4156 -4611
- package/dist/browser/index.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/openai-compatible.d.ts.map +1 -1
- package/dist/providers/openai-compatible.js +6 -1
- package/dist/providers/openai-compatible.js.map +1 -1
- package/dist/runtime/audit.d.ts +42 -0
- package/dist/runtime/audit.d.ts.map +1 -0
- package/dist/runtime/audit.js +73 -0
- package/dist/runtime/audit.js.map +1 -0
- package/dist/runtime/broadcast.d.ts +1 -0
- package/dist/runtime/broadcast.d.ts.map +1 -1
- package/dist/runtime/broadcast.js +171 -105
- package/dist/runtime/broadcast.js.map +1 -1
- package/dist/runtime/coordinator.d.ts +9 -2
- package/dist/runtime/coordinator.d.ts.map +1 -1
- package/dist/runtime/coordinator.js +164 -78
- package/dist/runtime/coordinator.js.map +1 -1
- package/dist/runtime/defaults.d.ts.map +1 -1
- package/dist/runtime/defaults.js +14 -5
- package/dist/runtime/defaults.js.map +1 -1
- package/dist/runtime/engine.d.ts +17 -4
- package/dist/runtime/engine.d.ts.map +1 -1
- package/dist/runtime/engine.js +577 -52
- package/dist/runtime/engine.js.map +1 -1
- package/dist/runtime/health.d.ts +51 -0
- package/dist/runtime/health.d.ts.map +1 -0
- package/dist/runtime/health.js +85 -0
- package/dist/runtime/health.js.map +1 -0
- package/dist/runtime/introspection.d.ts +96 -0
- package/dist/runtime/introspection.d.ts.map +1 -0
- package/dist/runtime/introspection.js +31 -0
- package/dist/runtime/introspection.js.map +1 -0
- package/dist/runtime/metrics.d.ts +44 -0
- package/dist/runtime/metrics.d.ts.map +1 -0
- package/dist/runtime/metrics.js +12 -0
- package/dist/runtime/metrics.js.map +1 -0
- package/dist/runtime/model.d.ts.map +1 -1
- package/dist/runtime/model.js +40 -10
- package/dist/runtime/model.js.map +1 -1
- package/dist/runtime/provenance.d.ts +25 -0
- package/dist/runtime/provenance.d.ts.map +1 -0
- package/dist/runtime/provenance.js +13 -0
- package/dist/runtime/provenance.js.map +1 -0
- package/dist/runtime/redaction.d.ts +13 -0
- package/dist/runtime/redaction.d.ts.map +1 -0
- package/dist/runtime/redaction.js +278 -0
- package/dist/runtime/redaction.js.map +1 -0
- package/dist/runtime/sanitization.d.ts +4 -0
- package/dist/runtime/sanitization.d.ts.map +1 -0
- package/dist/runtime/sanitization.js +63 -0
- package/dist/runtime/sanitization.js.map +1 -0
- package/dist/runtime/sequential.d.ts.map +1 -1
- package/dist/runtime/sequential.js +39 -36
- package/dist/runtime/sequential.js.map +1 -1
- package/dist/runtime/shared.d.ts +1 -0
- package/dist/runtime/shared.d.ts.map +1 -1
- package/dist/runtime/shared.js +167 -101
- package/dist/runtime/shared.js.map +1 -1
- package/dist/runtime/tools/built-in.d.ts +2 -0
- package/dist/runtime/tools/built-in.d.ts.map +1 -1
- package/dist/runtime/tools/built-in.js +153 -15
- package/dist/runtime/tools/built-in.js.map +1 -1
- package/dist/runtime/tools.d.ts.map +1 -1
- package/dist/runtime/tools.js +29 -7
- package/dist/runtime/tools.js.map +1 -1
- package/dist/runtime/tracing.d.ts +31 -0
- package/dist/runtime/tracing.d.ts.map +1 -0
- package/dist/runtime/tracing.js +18 -0
- package/dist/runtime/tracing.js.map +1 -0
- package/dist/runtime/validation.d.ts.map +1 -1
- package/dist/runtime/validation.js +3 -0
- package/dist/runtime/validation.js.map +1 -1
- package/dist/types/events.d.ts +13 -7
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/replay.d.ts +5 -1
- package/dist/types/replay.d.ts.map +1 -1
- package/dist/types.d.ts +144 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +46 -1
- package/src/index.ts +5 -0
- package/src/providers/openai-compatible.ts +6 -1
- package/src/runtime/audit.ts +121 -0
- package/src/runtime/broadcast.ts +195 -108
- package/src/runtime/coordinator.ts +197 -86
- package/src/runtime/defaults.ts +15 -5
- package/src/runtime/engine.ts +725 -58
- package/src/runtime/health.ts +136 -0
- package/src/runtime/introspection.ts +122 -0
- package/src/runtime/metrics.ts +45 -0
- package/src/runtime/model.ts +44 -9
- package/src/runtime/provenance.ts +43 -0
- package/src/runtime/redaction.ts +355 -0
- package/src/runtime/sanitization.ts +81 -0
- package/src/runtime/sequential.ts +40 -37
- package/src/runtime/shared.ts +191 -104
- package/src/runtime/tools/built-in.ts +168 -15
- package/src/runtime/tools.ts +39 -8
- package/src/runtime/tracing.ts +35 -0
- package/src/runtime/validation.ts +3 -0
- package/src/types/events.ts +13 -7
- package/src/types/replay.ts +5 -1
- package/src/types.ts +152 -1
package/dist/runtime/engine.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { DogpileError } from "../types.js";
|
|
2
2
|
import { runBroadcast } from "./broadcast.js";
|
|
3
3
|
import { runCoordinator } from "./coordinator.js";
|
|
4
|
-
import { createReplayTraceFinalOutput, createReplayTraceBudgetStateChanges, canonicalizeRunResult, canonicalizeSerializable, createRunAccounting, createRunEventLog, createRunMetadata, createRunUsage, defaultAgents, normalizeProtocol, orderAgentsForTemperature, recomputeAccountingFromTrace, resolveOnChildFailure, tierTemperature } from "./defaults.js";
|
|
4
|
+
import { addCost, createReplayTraceFinalOutput, createReplayTraceBudgetStateChanges, canonicalizeRunResult, canonicalizeSerializable, createRunAccounting, createRunEventLog, createRunMetadata, createRunUsage, defaultAgents, emptyCost, normalizeProtocol, orderAgentsForTemperature, recomputeAccountingFromTrace, resolveOnChildFailure, tierTemperature } from "./defaults.js";
|
|
5
|
+
import { computeHealth, DEFAULT_HEALTH_THRESHOLDS } from "./health.js";
|
|
5
6
|
import { runSequential } from "./sequential.js";
|
|
6
7
|
import { runShared } from "./shared.js";
|
|
7
8
|
import { classifyChildTimeoutSource, createAbortErrorFromSignal, createEngineDeadlineTimeoutError, createTimeoutError } from "./cancellation.js";
|
|
8
9
|
import { budget as budgetCondition } from "./termination.js";
|
|
9
10
|
import { validateDogpileOptions, validateEngineOptions, validateMissionIntent, validateProviderLocality, validateRunCallOptions } from "./validation.js";
|
|
11
|
+
import { DOGPILE_SPAN_NAMES } from "./tracing.js";
|
|
10
12
|
const DEFAULT_MAX_DEPTH = 4;
|
|
11
13
|
const DEFAULT_MAX_CONCURRENT_CHILDREN = 4;
|
|
14
|
+
const DEFAULT_MAX_CONCURRENT_AGENT_TURNS = 4;
|
|
12
15
|
const defaultHighLevelProtocol = "sequential";
|
|
13
16
|
const defaultHighLevelTier = "balanced";
|
|
14
17
|
/**
|
|
@@ -31,6 +34,7 @@ export function createEngine(options) {
|
|
|
31
34
|
const terminate = options.terminate ?? (options.budget ? conditionFromBudget(options.budget) : undefined);
|
|
32
35
|
const engineMaxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
33
36
|
const engineMaxConcurrentChildren = options.maxConcurrentChildren ?? DEFAULT_MAX_CONCURRENT_CHILDREN;
|
|
37
|
+
const engineMaxConcurrentAgentTurns = options.maxConcurrentAgentTurns ?? DEFAULT_MAX_CONCURRENT_AGENT_TURNS;
|
|
34
38
|
const engineOnChildFailure = options.onChildFailure;
|
|
35
39
|
return {
|
|
36
40
|
run(intent, runOptions) {
|
|
@@ -40,6 +44,8 @@ export function createEngine(options) {
|
|
|
40
44
|
const effectiveMaxDepth = Math.min(engineMaxDepth, runOptions?.maxDepth ?? Number.POSITIVE_INFINITY);
|
|
41
45
|
assertRunDoesNotRaiseEngineMax("maxConcurrentChildren", runOptions?.maxConcurrentChildren, engineMaxConcurrentChildren);
|
|
42
46
|
const effectiveMaxConcurrentChildren = Math.min(engineMaxConcurrentChildren, runOptions?.maxConcurrentChildren ?? Number.POSITIVE_INFINITY);
|
|
47
|
+
assertRunDoesNotRaiseEngineMax("maxConcurrentAgentTurns", runOptions?.maxConcurrentAgentTurns, engineMaxConcurrentAgentTurns);
|
|
48
|
+
const effectiveMaxConcurrentAgentTurns = Math.min(engineMaxConcurrentAgentTurns, runOptions?.maxConcurrentAgentTurns ?? Number.POSITIVE_INFINITY);
|
|
43
49
|
const onChildFailure = resolveOnChildFailure(runOptions?.onChildFailure, engineOnChildFailure);
|
|
44
50
|
const startedAtMs = Date.now();
|
|
45
51
|
const parentDeadlineMs = options.budget?.timeoutMs !== undefined ? startedAtMs + options.budget.timeoutMs : undefined;
|
|
@@ -57,9 +63,13 @@ export function createEngine(options) {
|
|
|
57
63
|
...(terminate ? { terminate } : {}),
|
|
58
64
|
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
59
65
|
...(options.evaluate ? { evaluate: options.evaluate } : {}),
|
|
66
|
+
...(options.tracer ? { tracer: options.tracer } : {}),
|
|
67
|
+
...(options.metricsHook ? { metricsHook: options.metricsHook } : {}),
|
|
68
|
+
...(options.logger ? { logger: options.logger } : {}),
|
|
60
69
|
currentDepth: 0,
|
|
61
70
|
effectiveMaxDepth,
|
|
62
71
|
effectiveMaxConcurrentChildren,
|
|
72
|
+
effectiveMaxConcurrentAgentTurns,
|
|
63
73
|
onChildFailure,
|
|
64
74
|
...(parentDeadlineMs !== undefined ? { parentDeadlineMs } : {}),
|
|
65
75
|
...(options.defaultSubRunTimeoutMs !== undefined
|
|
@@ -74,9 +84,10 @@ export function createEngine(options) {
|
|
|
74
84
|
const effectiveMaxDepth = Math.min(engineMaxDepth, runOptions?.maxDepth ?? Number.POSITIVE_INFINITY);
|
|
75
85
|
assertRunDoesNotRaiseEngineMax("maxConcurrentChildren", runOptions?.maxConcurrentChildren, engineMaxConcurrentChildren);
|
|
76
86
|
const effectiveMaxConcurrentChildren = Math.min(engineMaxConcurrentChildren, runOptions?.maxConcurrentChildren ?? Number.POSITIVE_INFINITY);
|
|
87
|
+
assertRunDoesNotRaiseEngineMax("maxConcurrentAgentTurns", runOptions?.maxConcurrentAgentTurns, engineMaxConcurrentAgentTurns);
|
|
88
|
+
const effectiveMaxConcurrentAgentTurns = Math.min(engineMaxConcurrentAgentTurns, runOptions?.maxConcurrentAgentTurns ?? Number.POSITIVE_INFINITY);
|
|
77
89
|
const onChildFailure = resolveOnChildFailure(runOptions?.onChildFailure, engineOnChildFailure);
|
|
78
|
-
const
|
|
79
|
-
const pendingResolvers = [];
|
|
90
|
+
const pendingIteratorResolvers = [];
|
|
80
91
|
const emittedEvents = [];
|
|
81
92
|
const subscribers = new Set();
|
|
82
93
|
const abortController = new AbortController();
|
|
@@ -111,10 +122,17 @@ export function createEngine(options) {
|
|
|
111
122
|
cancelRun();
|
|
112
123
|
},
|
|
113
124
|
subscribe(subscriber) {
|
|
114
|
-
subscribers.add(subscriber);
|
|
115
125
|
for (const event of emittedEvents) {
|
|
116
126
|
subscriber(event);
|
|
117
127
|
}
|
|
128
|
+
if (complete) {
|
|
129
|
+
return {
|
|
130
|
+
unsubscribe() {
|
|
131
|
+
// Completed streams replay synchronously and have no live source.
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
subscribers.add(subscriber);
|
|
118
136
|
return {
|
|
119
137
|
unsubscribe() {
|
|
120
138
|
subscribers.delete(subscriber);
|
|
@@ -122,20 +140,27 @@ export function createEngine(options) {
|
|
|
122
140
|
};
|
|
123
141
|
},
|
|
124
142
|
[Symbol.asyncIterator]() {
|
|
143
|
+
let cursor = 0;
|
|
125
144
|
return {
|
|
126
145
|
next() {
|
|
127
|
-
|
|
128
|
-
if (event) {
|
|
129
|
-
return Promise.resolve({ done: false, value: event });
|
|
130
|
-
}
|
|
131
|
-
if (complete) {
|
|
132
|
-
return Promise.resolve({ done: true, value: undefined });
|
|
133
|
-
}
|
|
134
|
-
return new Promise((resolve) => {
|
|
135
|
-
pendingResolvers.push(resolve);
|
|
136
|
-
});
|
|
146
|
+
return readNext();
|
|
137
147
|
}
|
|
138
148
|
};
|
|
149
|
+
function readNext() {
|
|
150
|
+
const event = emittedEvents[cursor];
|
|
151
|
+
if (event !== undefined) {
|
|
152
|
+
cursor += 1;
|
|
153
|
+
return Promise.resolve({ done: false, value: event });
|
|
154
|
+
}
|
|
155
|
+
if (complete) {
|
|
156
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
157
|
+
}
|
|
158
|
+
return new Promise((resolve) => {
|
|
159
|
+
pendingIteratorResolvers.push(() => {
|
|
160
|
+
void readNext().then(resolve);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
139
164
|
}
|
|
140
165
|
};
|
|
141
166
|
async function execute() {
|
|
@@ -160,11 +185,15 @@ export function createEngine(options) {
|
|
|
160
185
|
currentDepth: 0,
|
|
161
186
|
effectiveMaxDepth,
|
|
162
187
|
effectiveMaxConcurrentChildren,
|
|
188
|
+
effectiveMaxConcurrentAgentTurns,
|
|
163
189
|
onChildFailure,
|
|
164
190
|
...(streamParentDeadlineMs !== undefined ? { parentDeadlineMs: streamParentDeadlineMs } : {}),
|
|
165
191
|
...(options.defaultSubRunTimeoutMs !== undefined
|
|
166
192
|
? { defaultSubRunTimeoutMs: options.defaultSubRunTimeoutMs }
|
|
167
193
|
: {}),
|
|
194
|
+
...(options.tracer ? { tracer: options.tracer } : {}),
|
|
195
|
+
...(options.metricsHook ? { metricsHook: options.metricsHook } : {}),
|
|
196
|
+
...(options.logger ? { logger: options.logger } : {}),
|
|
168
197
|
streamEvents: true,
|
|
169
198
|
emit(event) {
|
|
170
199
|
if (status !== "running") {
|
|
@@ -246,8 +275,8 @@ export function createEngine(options) {
|
|
|
246
275
|
timeoutLifecycle.cleanup();
|
|
247
276
|
abortRace.cleanup();
|
|
248
277
|
subscribers.clear();
|
|
249
|
-
for (const
|
|
250
|
-
|
|
278
|
+
for (const resolvePending of pendingIteratorResolvers.splice(0)) {
|
|
279
|
+
resolvePending();
|
|
251
280
|
}
|
|
252
281
|
}
|
|
253
282
|
function publish(event) {
|
|
@@ -264,12 +293,9 @@ export function createEngine(options) {
|
|
|
264
293
|
// Subscriber failures should not cancel the underlying SDK run.
|
|
265
294
|
}
|
|
266
295
|
}
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
resolver({ done: false, value: canonicalEvent });
|
|
270
|
-
return;
|
|
296
|
+
for (const resolvePending of pendingIteratorResolvers.splice(0)) {
|
|
297
|
+
resolvePending();
|
|
271
298
|
}
|
|
272
|
-
pendingEvents.push(canonicalEvent);
|
|
273
299
|
}
|
|
274
300
|
}
|
|
275
301
|
};
|
|
@@ -485,6 +511,387 @@ function dogpileErrorStreamDetail(error) {
|
|
|
485
511
|
}
|
|
486
512
|
return detail;
|
|
487
513
|
}
|
|
514
|
+
function openRunTracing(options) {
|
|
515
|
+
if (!options.tracer) {
|
|
516
|
+
return undefined;
|
|
517
|
+
}
|
|
518
|
+
const runSpan = options.tracer.startSpan(DOGPILE_SPAN_NAMES.RUN, {
|
|
519
|
+
...(options.parentSpan ? { parent: options.parentSpan } : {}),
|
|
520
|
+
attributes: {
|
|
521
|
+
"dogpile.run.protocol": options.protocolKind,
|
|
522
|
+
"dogpile.run.tier": String(options.tier),
|
|
523
|
+
"dogpile.run.intent": options.intent.slice(0, 200)
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
return {
|
|
527
|
+
tracer: options.tracer,
|
|
528
|
+
runSpan,
|
|
529
|
+
subRunSpans: new Map(),
|
|
530
|
+
agentTurnSpans: new Map(),
|
|
531
|
+
modelCallSpans: new Map(),
|
|
532
|
+
pendingModelRequests: new Map(),
|
|
533
|
+
agentTurnCounters: new Map(),
|
|
534
|
+
turnAccumByAgent: new Map(),
|
|
535
|
+
agentIds: new Set(),
|
|
536
|
+
turnCount: 0,
|
|
537
|
+
lastCost: emptyCost()
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function openRunMetrics(options) {
|
|
541
|
+
if (!options.metricsHook) {
|
|
542
|
+
return undefined;
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
metricsHook: options.metricsHook,
|
|
546
|
+
logger: options.logger,
|
|
547
|
+
startedAtMs: Date.now(),
|
|
548
|
+
subRunStartTimes: new Map(),
|
|
549
|
+
totalCost: emptyCost(),
|
|
550
|
+
nestedCost: emptyCost(),
|
|
551
|
+
turns: 0
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
function routeMetricsError(err, logger) {
|
|
555
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
556
|
+
try {
|
|
557
|
+
if (logger !== undefined) {
|
|
558
|
+
logger.error("dogpile:metricsHook threw", { error: msg });
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
console.error("dogpile:metricsHook threw", { error: msg });
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
// A logger that throws from error() cannot be helped.
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function fireHook(callback, snapshot, logger) {
|
|
569
|
+
if (!callback) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
try {
|
|
573
|
+
const result = callback(snapshot);
|
|
574
|
+
if (result && typeof result.catch === "function") {
|
|
575
|
+
result.catch((err) => {
|
|
576
|
+
routeMetricsError(err, logger);
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
catch (err) {
|
|
581
|
+
routeMetricsError(err, logger);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
function buildRunSnapshot(result, startedAtMs) {
|
|
585
|
+
const nestedCosts = nestedSubRunCosts(result);
|
|
586
|
+
const budgetStopEvent = result.trace.events.find((event) => event.type === "budget-stop");
|
|
587
|
+
const outcome = budgetStopEvent !== undefined ? "budget-stopped" : "completed";
|
|
588
|
+
const totalInputTokens = result.cost.inputTokens;
|
|
589
|
+
const totalOutputTokens = result.cost.outputTokens;
|
|
590
|
+
const totalCostUsd = result.cost.usd;
|
|
591
|
+
const ownInputTokens = totalInputTokens - nestedCosts.reduce((sum, cost) => sum + cost.inputTokens, 0);
|
|
592
|
+
const ownOutputTokens = totalOutputTokens - nestedCosts.reduce((sum, cost) => sum + cost.outputTokens, 0);
|
|
593
|
+
const ownCostUsd = totalCostUsd - nestedCosts.reduce((sum, cost) => sum + cost.usd, 0);
|
|
594
|
+
const turns = result.trace.events.filter((event) => event.type === "agent-turn").length;
|
|
595
|
+
return {
|
|
596
|
+
outcome,
|
|
597
|
+
inputTokens: ownInputTokens,
|
|
598
|
+
outputTokens: ownOutputTokens,
|
|
599
|
+
costUsd: ownCostUsd,
|
|
600
|
+
totalInputTokens,
|
|
601
|
+
totalOutputTokens,
|
|
602
|
+
totalCostUsd,
|
|
603
|
+
turns,
|
|
604
|
+
durationMs: Date.now() - startedAtMs
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
function buildSubRunSnapshot(subResult, durationMs) {
|
|
608
|
+
const nestedCosts = nestedSubRunCosts(subResult);
|
|
609
|
+
const budgetStopEvent = subResult.trace.events.find((event) => event.type === "budget-stop");
|
|
610
|
+
const outcome = budgetStopEvent !== undefined ? "budget-stopped" : "completed";
|
|
611
|
+
const totalInputTokens = subResult.cost.inputTokens;
|
|
612
|
+
const totalOutputTokens = subResult.cost.outputTokens;
|
|
613
|
+
const totalCostUsd = subResult.cost.usd;
|
|
614
|
+
const ownInputTokens = totalInputTokens - nestedCosts.reduce((sum, cost) => sum + cost.inputTokens, 0);
|
|
615
|
+
const ownOutputTokens = totalOutputTokens - nestedCosts.reduce((sum, cost) => sum + cost.outputTokens, 0);
|
|
616
|
+
const ownCostUsd = totalCostUsd - nestedCosts.reduce((sum, cost) => sum + cost.usd, 0);
|
|
617
|
+
const turns = subResult.trace.events.filter((event) => event.type === "agent-turn").length;
|
|
618
|
+
return {
|
|
619
|
+
outcome,
|
|
620
|
+
inputTokens: ownInputTokens,
|
|
621
|
+
outputTokens: ownOutputTokens,
|
|
622
|
+
costUsd: ownCostUsd,
|
|
623
|
+
totalInputTokens,
|
|
624
|
+
totalOutputTokens,
|
|
625
|
+
totalCostUsd,
|
|
626
|
+
turns,
|
|
627
|
+
durationMs
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function nestedSubRunCosts(result) {
|
|
631
|
+
return result.trace.events.flatMap((event) => {
|
|
632
|
+
if (event.type === "sub-run-completed") {
|
|
633
|
+
return [event.subResult.cost];
|
|
634
|
+
}
|
|
635
|
+
if (event.type === "sub-run-failed") {
|
|
636
|
+
return [event.partialCost];
|
|
637
|
+
}
|
|
638
|
+
return [];
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
function subtractCost(total, nested) {
|
|
642
|
+
return {
|
|
643
|
+
usd: total.usd - nested.usd,
|
|
644
|
+
inputTokens: total.inputTokens - nested.inputTokens,
|
|
645
|
+
outputTokens: total.outputTokens - nested.outputTokens,
|
|
646
|
+
totalTokens: total.totalTokens - nested.totalTokens
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
function handleMetricsEvent(state, event) {
|
|
650
|
+
const parentRunIds = event.parentRunIds;
|
|
651
|
+
if (parentRunIds !== undefined) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
switch (event.type) {
|
|
655
|
+
case "agent-turn": {
|
|
656
|
+
state.totalCost = event.cost;
|
|
657
|
+
state.turns += 1;
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
case "broadcast":
|
|
661
|
+
case "budget-stop":
|
|
662
|
+
case "final": {
|
|
663
|
+
state.totalCost = event.cost;
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
case "sub-run-started": {
|
|
667
|
+
state.subRunStartTimes.set(event.childRunId, Date.now());
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
case "sub-run-completed": {
|
|
671
|
+
state.totalCost = addCost(state.totalCost, event.subResult.cost);
|
|
672
|
+
state.nestedCost = addCost(state.nestedCost, event.subResult.cost);
|
|
673
|
+
const startMs = state.subRunStartTimes.get(event.childRunId);
|
|
674
|
+
const durationMs = startMs !== undefined ? Date.now() - startMs : 0;
|
|
675
|
+
state.subRunStartTimes.delete(event.childRunId);
|
|
676
|
+
const snapshot = buildSubRunSnapshot(event.subResult, durationMs);
|
|
677
|
+
fireHook(state.metricsHook.onSubRunComplete, snapshot, state.logger);
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
case "sub-run-failed": {
|
|
681
|
+
state.totalCost = addCost(state.totalCost, event.partialCost);
|
|
682
|
+
state.nestedCost = addCost(state.nestedCost, event.partialCost);
|
|
683
|
+
state.subRunStartTimes.delete(event.childRunId);
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
default:
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function closeRunMetrics(state, result) {
|
|
691
|
+
if (result !== undefined) {
|
|
692
|
+
const snapshot = buildRunSnapshot(result, state.startedAtMs);
|
|
693
|
+
fireHook(state.metricsHook.onRunComplete, snapshot, state.logger);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const ownCost = subtractCost(state.totalCost, state.nestedCost);
|
|
697
|
+
const snapshot = {
|
|
698
|
+
outcome: "aborted",
|
|
699
|
+
inputTokens: ownCost.inputTokens,
|
|
700
|
+
outputTokens: ownCost.outputTokens,
|
|
701
|
+
costUsd: ownCost.usd,
|
|
702
|
+
totalInputTokens: state.totalCost.inputTokens,
|
|
703
|
+
totalOutputTokens: state.totalCost.outputTokens,
|
|
704
|
+
totalCostUsd: state.totalCost.usd,
|
|
705
|
+
turns: state.turns,
|
|
706
|
+
durationMs: Date.now() - state.startedAtMs
|
|
707
|
+
};
|
|
708
|
+
fireHook(state.metricsHook.onRunComplete, snapshot, state.logger);
|
|
709
|
+
}
|
|
710
|
+
function handleTracingEvent(state, event) {
|
|
711
|
+
const parentRunIds = event.parentRunIds;
|
|
712
|
+
if (parentRunIds !== undefined) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (state.runId === undefined) {
|
|
716
|
+
state.runId = event.runId;
|
|
717
|
+
state.runSpan.setAttribute("dogpile.run.id", event.runId);
|
|
718
|
+
}
|
|
719
|
+
switch (event.type) {
|
|
720
|
+
case "model-request": {
|
|
721
|
+
state.pendingModelRequests.set(event.callId, event);
|
|
722
|
+
state.agentIds.add(event.agentId);
|
|
723
|
+
if (!state.agentTurnSpans.has(event.agentId)) {
|
|
724
|
+
const turnNumber = (state.agentTurnCounters.get(event.agentId) ?? 0) + 1;
|
|
725
|
+
state.agentTurnCounters.set(event.agentId, turnNumber);
|
|
726
|
+
const turnParent = state.subRunSpans.get(event.runId) ?? state.runSpan;
|
|
727
|
+
const turnSpan = state.tracer.startSpan(DOGPILE_SPAN_NAMES.AGENT_TURN, {
|
|
728
|
+
parent: turnParent,
|
|
729
|
+
attributes: {
|
|
730
|
+
"dogpile.agent.id": event.agentId,
|
|
731
|
+
"dogpile.agent.role": event.role,
|
|
732
|
+
"dogpile.turn.number": turnNumber,
|
|
733
|
+
"dogpile.model.id": event.modelId
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
state.agentTurnSpans.set(event.agentId, turnSpan);
|
|
737
|
+
}
|
|
738
|
+
const callParent = state.agentTurnSpans.get(event.agentId) ??
|
|
739
|
+
state.subRunSpans.get(event.runId) ??
|
|
740
|
+
state.runSpan;
|
|
741
|
+
const callSpan = state.tracer.startSpan(DOGPILE_SPAN_NAMES.MODEL_CALL, {
|
|
742
|
+
parent: callParent,
|
|
743
|
+
attributes: {
|
|
744
|
+
"dogpile.model.id": event.modelId,
|
|
745
|
+
"dogpile.call.id": event.callId,
|
|
746
|
+
"dogpile.provider.id": event.providerId
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
state.modelCallSpans.set(event.callId, callSpan);
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
case "model-response": {
|
|
753
|
+
const span = state.modelCallSpans.get(event.callId);
|
|
754
|
+
if (span) {
|
|
755
|
+
const inputTokens = event.response.usage?.inputTokens ?? 0;
|
|
756
|
+
const outputTokens = event.response.usage?.outputTokens ?? 0;
|
|
757
|
+
const responseCost = {
|
|
758
|
+
usd: event.response.costUsd ?? 0,
|
|
759
|
+
inputTokens,
|
|
760
|
+
outputTokens,
|
|
761
|
+
totalTokens: event.response.usage?.totalTokens ?? inputTokens + outputTokens
|
|
762
|
+
};
|
|
763
|
+
span.setAttribute("dogpile.model.input_tokens", inputTokens);
|
|
764
|
+
span.setAttribute("dogpile.model.output_tokens", outputTokens);
|
|
765
|
+
if (event.response.costUsd !== undefined) {
|
|
766
|
+
span.setAttribute("dogpile.model.cost_usd", event.response.costUsd);
|
|
767
|
+
}
|
|
768
|
+
span.setStatus("ok");
|
|
769
|
+
span.end();
|
|
770
|
+
state.modelCallSpans.delete(event.callId);
|
|
771
|
+
const accum = state.turnAccumByAgent.get(event.agentId) ?? {
|
|
772
|
+
inputTokens: 0,
|
|
773
|
+
outputTokens: 0,
|
|
774
|
+
costUsd: 0
|
|
775
|
+
};
|
|
776
|
+
accum.inputTokens += inputTokens;
|
|
777
|
+
accum.outputTokens += outputTokens;
|
|
778
|
+
accum.costUsd += responseCost.usd;
|
|
779
|
+
state.turnAccumByAgent.set(event.agentId, accum);
|
|
780
|
+
state.lastCost = addCost(state.lastCost, responseCost);
|
|
781
|
+
}
|
|
782
|
+
state.pendingModelRequests.delete(event.callId);
|
|
783
|
+
break;
|
|
784
|
+
}
|
|
785
|
+
case "agent-turn": {
|
|
786
|
+
state.agentIds.add(event.agentId);
|
|
787
|
+
state.turnCount += 1;
|
|
788
|
+
state.lastCost = event.cost;
|
|
789
|
+
const turnSpan = state.agentTurnSpans.get(event.agentId);
|
|
790
|
+
if (turnSpan) {
|
|
791
|
+
turnSpan.setAttribute("dogpile.agent.role", event.role);
|
|
792
|
+
const accum = state.turnAccumByAgent.get(event.agentId);
|
|
793
|
+
turnSpan.setAttribute("dogpile.turn.cost_usd", accum?.costUsd ?? 0);
|
|
794
|
+
turnSpan.setAttribute("dogpile.turn.input_tokens", accum?.inputTokens ?? 0);
|
|
795
|
+
turnSpan.setAttribute("dogpile.turn.output_tokens", accum?.outputTokens ?? 0);
|
|
796
|
+
turnSpan.setStatus("ok");
|
|
797
|
+
turnSpan.end();
|
|
798
|
+
state.agentTurnSpans.delete(event.agentId);
|
|
799
|
+
}
|
|
800
|
+
state.turnAccumByAgent.delete(event.agentId);
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
case "broadcast":
|
|
804
|
+
case "budget-stop":
|
|
805
|
+
case "final": {
|
|
806
|
+
state.lastCost = event.cost;
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
809
|
+
case "sub-run-started": {
|
|
810
|
+
const span = state.tracer.startSpan(DOGPILE_SPAN_NAMES.SUB_RUN, {
|
|
811
|
+
parent: state.runSpan,
|
|
812
|
+
attributes: {
|
|
813
|
+
"dogpile.sub_run.child_run_id": event.childRunId,
|
|
814
|
+
"dogpile.sub_run.parent_run_id": event.parentRunId,
|
|
815
|
+
"dogpile.sub_run.depth": event.depth
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
state.subRunSpans.set(event.childRunId, span);
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
case "sub-run-completed": {
|
|
822
|
+
const span = state.subRunSpans.get(event.childRunId);
|
|
823
|
+
if (span) {
|
|
824
|
+
span.setStatus("ok");
|
|
825
|
+
span.end();
|
|
826
|
+
state.subRunSpans.delete(event.childRunId);
|
|
827
|
+
}
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
case "sub-run-failed": {
|
|
831
|
+
const span = state.subRunSpans.get(event.childRunId);
|
|
832
|
+
if (span) {
|
|
833
|
+
span.setStatus("error", event.error.message);
|
|
834
|
+
span.end();
|
|
835
|
+
state.subRunSpans.delete(event.childRunId);
|
|
836
|
+
}
|
|
837
|
+
break;
|
|
838
|
+
}
|
|
839
|
+
default:
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
function closeRunTracing(state, result, error) {
|
|
844
|
+
if (error !== undefined) {
|
|
845
|
+
if (state.runId !== undefined) {
|
|
846
|
+
state.runSpan.setAttribute("dogpile.run.id", state.runId);
|
|
847
|
+
}
|
|
848
|
+
state.runSpan.setAttribute("dogpile.run.agent_count", state.agentIds.size);
|
|
849
|
+
state.runSpan.setAttribute("dogpile.run.turn_count", state.turnCount);
|
|
850
|
+
state.runSpan.setAttribute("dogpile.run.cost_usd", state.lastCost.usd);
|
|
851
|
+
state.runSpan.setAttribute("dogpile.run.input_tokens", state.lastCost.inputTokens);
|
|
852
|
+
state.runSpan.setAttribute("dogpile.run.output_tokens", state.lastCost.outputTokens);
|
|
853
|
+
state.runSpan.setAttribute("dogpile.run.outcome", "aborted");
|
|
854
|
+
state.runSpan.setStatus("error", error instanceof Error ? error.message : String(error));
|
|
855
|
+
closeOpenTracingSpans(state);
|
|
856
|
+
state.runSpan.end();
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
if (result === undefined) {
|
|
860
|
+
closeOpenTracingSpans(state);
|
|
861
|
+
state.runSpan.end();
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const budgetStopEvent = result.trace.events.find((event) => event.type === "budget-stop");
|
|
865
|
+
const terminationReason = budgetStopEvent?.reason;
|
|
866
|
+
const outcome = terminationReason !== undefined ? "budget-stopped" : "completed";
|
|
867
|
+
state.runSpan.setAttribute("dogpile.run.id", result.trace.runId);
|
|
868
|
+
state.runSpan.setAttribute("dogpile.run.agent_count", result.trace.agentsUsed.length);
|
|
869
|
+
state.runSpan.setAttribute("dogpile.run.turn_count", result.trace.events.filter((event) => event.type === "agent-turn").length);
|
|
870
|
+
state.runSpan.setAttribute("dogpile.run.cost_usd", result.cost.usd);
|
|
871
|
+
state.runSpan.setAttribute("dogpile.run.input_tokens", result.cost.inputTokens);
|
|
872
|
+
state.runSpan.setAttribute("dogpile.run.output_tokens", result.cost.outputTokens);
|
|
873
|
+
state.runSpan.setAttribute("dogpile.run.outcome", outcome);
|
|
874
|
+
if (terminationReason !== undefined) {
|
|
875
|
+
state.runSpan.setAttribute("dogpile.run.termination_reason", terminationReason);
|
|
876
|
+
}
|
|
877
|
+
state.runSpan.setStatus("ok");
|
|
878
|
+
closeOpenTracingSpans(state);
|
|
879
|
+
state.runSpan.end();
|
|
880
|
+
}
|
|
881
|
+
function closeOpenTracingSpans(state) {
|
|
882
|
+
for (const span of state.modelCallSpans.values()) {
|
|
883
|
+
span.end();
|
|
884
|
+
}
|
|
885
|
+
state.modelCallSpans.clear();
|
|
886
|
+
for (const span of state.agentTurnSpans.values()) {
|
|
887
|
+
span.end();
|
|
888
|
+
}
|
|
889
|
+
state.agentTurnSpans.clear();
|
|
890
|
+
for (const span of state.subRunSpans.values()) {
|
|
891
|
+
span.end();
|
|
892
|
+
}
|
|
893
|
+
state.subRunSpans.clear();
|
|
894
|
+
}
|
|
488
895
|
async function runNonStreamingProtocol(options) {
|
|
489
896
|
const failureInstancesByChildRunId = new Map();
|
|
490
897
|
const abortLifecycle = createNonStreamingAbortLifecycle({
|
|
@@ -524,7 +931,8 @@ async function runNonStreamingProtocol(options) {
|
|
|
524
931
|
events
|
|
525
932
|
}),
|
|
526
933
|
eventLog: createRunEventLog(trace.runId, trace.protocol, events),
|
|
527
|
-
trace
|
|
934
|
+
trace,
|
|
935
|
+
health: computeHealth(trace, DEFAULT_HEALTH_THRESHOLDS)
|
|
528
936
|
};
|
|
529
937
|
const terminalThrow = resolveRuntimeTerminalThrow(runResult.trace, failureInstancesByChildRunId);
|
|
530
938
|
if (terminalThrow) {
|
|
@@ -570,7 +978,56 @@ function finalEventWithEvaluation(event, evaluation) {
|
|
|
570
978
|
evaluation
|
|
571
979
|
};
|
|
572
980
|
}
|
|
573
|
-
function runProtocol(options) {
|
|
981
|
+
async function runProtocol(options) {
|
|
982
|
+
const tracing = openRunTracing({
|
|
983
|
+
...(options.tracer ? { tracer: options.tracer } : {}),
|
|
984
|
+
...(options.parentSpan ? { parentSpan: options.parentSpan } : {}),
|
|
985
|
+
intent: options.intent,
|
|
986
|
+
protocolKind: options.protocol.kind,
|
|
987
|
+
tier: options.tier
|
|
988
|
+
});
|
|
989
|
+
const metrics = openRunMetrics({
|
|
990
|
+
...(options.metricsHook ? { metricsHook: options.metricsHook } : {}),
|
|
991
|
+
...(options.logger ? { logger: options.logger } : {})
|
|
992
|
+
});
|
|
993
|
+
const emitForProtocol = tracing || metrics || options.emit
|
|
994
|
+
? (event) => {
|
|
995
|
+
if (tracing) {
|
|
996
|
+
handleTracingEvent(tracing, event);
|
|
997
|
+
}
|
|
998
|
+
if (metrics) {
|
|
999
|
+
handleMetricsEvent(metrics, event);
|
|
1000
|
+
}
|
|
1001
|
+
options.emit?.(event);
|
|
1002
|
+
}
|
|
1003
|
+
: undefined;
|
|
1004
|
+
const protocolOptions = tracing
|
|
1005
|
+
? {
|
|
1006
|
+
...options,
|
|
1007
|
+
subRunSpansByChildId: tracing.subRunSpans
|
|
1008
|
+
}
|
|
1009
|
+
: options;
|
|
1010
|
+
try {
|
|
1011
|
+
const result = await runProtocolInner(protocolOptions, emitForProtocol);
|
|
1012
|
+
if (tracing) {
|
|
1013
|
+
closeRunTracing(tracing, result);
|
|
1014
|
+
}
|
|
1015
|
+
if (metrics && (options.currentDepth === 0 || options.currentDepth === undefined)) {
|
|
1016
|
+
closeRunMetrics(metrics, result);
|
|
1017
|
+
}
|
|
1018
|
+
return result;
|
|
1019
|
+
}
|
|
1020
|
+
catch (error) {
|
|
1021
|
+
if (tracing) {
|
|
1022
|
+
closeRunTracing(tracing, undefined, error);
|
|
1023
|
+
}
|
|
1024
|
+
if (metrics && (options.currentDepth === 0 || options.currentDepth === undefined)) {
|
|
1025
|
+
closeRunMetrics(metrics, undefined);
|
|
1026
|
+
}
|
|
1027
|
+
throw error;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
function runProtocolInner(options, emitForProtocol) {
|
|
574
1031
|
switch (options.protocol.kind) {
|
|
575
1032
|
case "sequential":
|
|
576
1033
|
return runSequential({
|
|
@@ -586,7 +1043,7 @@ function runProtocol(options) {
|
|
|
586
1043
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
587
1044
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
588
1045
|
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
589
|
-
...(
|
|
1046
|
+
...(emitForProtocol ? { emit: emitForProtocol } : {})
|
|
590
1047
|
});
|
|
591
1048
|
case "broadcast":
|
|
592
1049
|
return runBroadcast({
|
|
@@ -602,7 +1059,10 @@ function runProtocol(options) {
|
|
|
602
1059
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
603
1060
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
604
1061
|
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
605
|
-
...(options.
|
|
1062
|
+
...(options.effectiveMaxConcurrentAgentTurns !== undefined
|
|
1063
|
+
? { maxConcurrentAgentTurns: options.effectiveMaxConcurrentAgentTurns }
|
|
1064
|
+
: {}),
|
|
1065
|
+
...(emitForProtocol ? { emit: emitForProtocol } : {})
|
|
606
1066
|
});
|
|
607
1067
|
case "coordinator":
|
|
608
1068
|
return runCoordinator({
|
|
@@ -618,11 +1078,15 @@ function runProtocol(options) {
|
|
|
618
1078
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
619
1079
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
620
1080
|
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
621
|
-
...(options.
|
|
1081
|
+
...(options.effectiveMaxConcurrentAgentTurns !== undefined
|
|
1082
|
+
? { maxConcurrentAgentTurns: options.effectiveMaxConcurrentAgentTurns }
|
|
1083
|
+
: {}),
|
|
1084
|
+
...(emitForProtocol ? { emit: emitForProtocol } : {}),
|
|
622
1085
|
...(options.streamEvents !== undefined ? { streamEvents: options.streamEvents } : {}),
|
|
623
1086
|
currentDepth: options.currentDepth ?? 0,
|
|
624
1087
|
effectiveMaxDepth: options.effectiveMaxDepth ?? Infinity,
|
|
625
1088
|
effectiveMaxConcurrentChildren: options.effectiveMaxConcurrentChildren ?? DEFAULT_MAX_CONCURRENT_CHILDREN,
|
|
1089
|
+
effectiveMaxConcurrentAgentTurns: options.effectiveMaxConcurrentAgentTurns ?? DEFAULT_MAX_CONCURRENT_AGENT_TURNS,
|
|
626
1090
|
onChildFailure: options.onChildFailure ?? "continue",
|
|
627
1091
|
...(options.parentDeadlineMs !== undefined ? { parentDeadlineMs: options.parentDeadlineMs } : {}),
|
|
628
1092
|
...(options.defaultSubRunTimeoutMs !== undefined
|
|
@@ -632,10 +1096,17 @@ function runProtocol(options) {
|
|
|
632
1096
|
...(options.failureInstancesByChildRunId !== undefined
|
|
633
1097
|
? { failureInstancesByChildRunId: options.failureInstancesByChildRunId }
|
|
634
1098
|
: {}),
|
|
635
|
-
runProtocol: (childInput) =>
|
|
636
|
-
...childInput
|
|
637
|
-
|
|
638
|
-
|
|
1099
|
+
runProtocol: (childInput) => {
|
|
1100
|
+
const { runId: childRunId, ...childProtocolInput } = childInput;
|
|
1101
|
+
const childParent = options.subRunSpansByChildId?.get(childRunId) ?? options.parentSpan;
|
|
1102
|
+
return runProtocol({
|
|
1103
|
+
...childProtocolInput,
|
|
1104
|
+
protocol: normalizeProtocol(childProtocolInput.protocol),
|
|
1105
|
+
...(options.tracer ? { tracer: options.tracer } : {}),
|
|
1106
|
+
...(childParent ? { parentSpan: childParent } : {}),
|
|
1107
|
+
...(options.logger ? { logger: options.logger } : {})
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
639
1110
|
});
|
|
640
1111
|
case "shared":
|
|
641
1112
|
return runShared({
|
|
@@ -651,7 +1122,10 @@ function runProtocol(options) {
|
|
|
651
1122
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
652
1123
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
653
1124
|
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
654
|
-
...(options.
|
|
1125
|
+
...(options.effectiveMaxConcurrentAgentTurns !== undefined
|
|
1126
|
+
? { maxConcurrentAgentTurns: options.effectiveMaxConcurrentAgentTurns }
|
|
1127
|
+
: {}),
|
|
1128
|
+
...(emitForProtocol ? { emit: emitForProtocol } : {})
|
|
655
1129
|
});
|
|
656
1130
|
}
|
|
657
1131
|
}
|
|
@@ -699,7 +1173,14 @@ export function stream(options) {
|
|
|
699
1173
|
* the ergonomic {@link RunResult} wrapper from the JSON-serializable
|
|
700
1174
|
* {@link Trace} returned by a previous `run()`, `stream()`, or
|
|
701
1175
|
* `Dogpile.pile()` call.
|
|
1176
|
+
*
|
|
1177
|
+
* Tracing and metrics: replay is intentionally tracing-free and metrics-free.
|
|
1178
|
+
* Even when an engine instance has been configured with a `tracer` or
|
|
1179
|
+
* `metricsHook` on its `EngineOptions`, calling this function emits no spans
|
|
1180
|
+
* or callbacks — replaying historical events with current timestamps would
|
|
1181
|
+
* confuse observability backends. See `docs/developer-usage.md`.
|
|
702
1182
|
*/
|
|
1183
|
+
// Tracing/metrics-free: replay never uses EngineOptions tracer or metricsHook.
|
|
703
1184
|
export function replay(trace) {
|
|
704
1185
|
const cost = trace.finalOutput.cost;
|
|
705
1186
|
const lastEvent = trace.events.at(-1);
|
|
@@ -714,7 +1195,7 @@ export function replay(trace) {
|
|
|
714
1195
|
}
|
|
715
1196
|
const baseResult = {
|
|
716
1197
|
output: trace.finalOutput.output,
|
|
717
|
-
eventLog: createRunEventLog(trace.runId, trace.protocol, trace.
|
|
1198
|
+
eventLog: createRunEventLog(trace.runId, trace.protocol, synthesizeProviderEvents(trace, trace.providerCalls)),
|
|
718
1199
|
trace,
|
|
719
1200
|
transcript: trace.transcript,
|
|
720
1201
|
usage: createRunUsage(cost),
|
|
@@ -727,7 +1208,8 @@ export function replay(trace) {
|
|
|
727
1208
|
events: trace.events
|
|
728
1209
|
}),
|
|
729
1210
|
accounting,
|
|
730
|
-
cost
|
|
1211
|
+
cost,
|
|
1212
|
+
health: computeHealth(trace, DEFAULT_HEALTH_THRESHOLDS)
|
|
731
1213
|
};
|
|
732
1214
|
if (lastEvent?.type !== "final") {
|
|
733
1215
|
return baseResult;
|
|
@@ -738,6 +1220,49 @@ export function replay(trace) {
|
|
|
738
1220
|
...(lastEvent.evaluation !== undefined ? { evaluation: lastEvent.evaluation } : {})
|
|
739
1221
|
};
|
|
740
1222
|
}
|
|
1223
|
+
function synthesizeProviderEvents(trace, providerCalls) {
|
|
1224
|
+
const hasLiveProvenance = trace.events.some((event) => event.type === "model-request" || event.type === "model-response");
|
|
1225
|
+
if (hasLiveProvenance) {
|
|
1226
|
+
return trace.events;
|
|
1227
|
+
}
|
|
1228
|
+
const baseEvents = trace.events.filter((event) => event.type !== "model-request" && event.type !== "model-response");
|
|
1229
|
+
const result = [];
|
|
1230
|
+
let turnCount = 0;
|
|
1231
|
+
for (const event of baseEvents) {
|
|
1232
|
+
if (event.type === "agent-turn") {
|
|
1233
|
+
const call = providerCalls[turnCount];
|
|
1234
|
+
if (call !== undefined) {
|
|
1235
|
+
const modelId = typeof call.modelId === "string" && call.modelId.length > 0 ? call.modelId : call.providerId;
|
|
1236
|
+
result.push({
|
|
1237
|
+
type: "model-request",
|
|
1238
|
+
runId: trace.runId,
|
|
1239
|
+
callId: call.callId,
|
|
1240
|
+
providerId: call.providerId,
|
|
1241
|
+
modelId,
|
|
1242
|
+
startedAt: call.startedAt,
|
|
1243
|
+
agentId: call.agentId,
|
|
1244
|
+
role: call.role,
|
|
1245
|
+
request: call.request
|
|
1246
|
+
});
|
|
1247
|
+
result.push({
|
|
1248
|
+
type: "model-response",
|
|
1249
|
+
runId: trace.runId,
|
|
1250
|
+
callId: call.callId,
|
|
1251
|
+
providerId: call.providerId,
|
|
1252
|
+
modelId,
|
|
1253
|
+
startedAt: call.startedAt,
|
|
1254
|
+
completedAt: call.completedAt,
|
|
1255
|
+
agentId: call.agentId,
|
|
1256
|
+
role: call.role,
|
|
1257
|
+
response: call.response
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
turnCount += 1;
|
|
1261
|
+
}
|
|
1262
|
+
result.push(event);
|
|
1263
|
+
}
|
|
1264
|
+
return result;
|
|
1265
|
+
}
|
|
741
1266
|
function resolveRuntimeTerminalThrow(trace, failureInstancesByChildRunId) {
|
|
742
1267
|
if (trace.triggeringFailureForAbortMode !== undefined) {
|
|
743
1268
|
return failureInstancesByChildRunId.get(trace.triggeringFailureForAbortMode.childRunId) ?? null;
|
|
@@ -816,14 +1341,21 @@ function dogpileErrorFromSerializedPayload(input) {
|
|
|
816
1341
|
* Replay a saved completed trace as a stream without invoking a model provider.
|
|
817
1342
|
*
|
|
818
1343
|
* @remarks
|
|
819
|
-
* This is the streaming counterpart to {@link replay}. It yields the
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
* replay remains storage-free and
|
|
1344
|
+
* This is the streaming counterpart to {@link replay}. It yields the same
|
|
1345
|
+
* event sequence exposed by the replayed result event log, including legacy
|
|
1346
|
+
* provenance synthesis when a saved trace predates model request/response
|
|
1347
|
+
* events. Since all data comes from the trace, replay remains storage-free and
|
|
1348
|
+
* provider-free.
|
|
1349
|
+
*
|
|
1350
|
+
* Tracing and metrics: replayStream is intentionally tracing-free and
|
|
1351
|
+
* metrics-free. Even when an engine instance has been configured with a
|
|
1352
|
+
* `tracer` or `metricsHook` on its `EngineOptions`, calling this function
|
|
1353
|
+
* emits no spans or callbacks — replaying historical events with current
|
|
1354
|
+
* timestamps would confuse observability backends. See `docs/developer-usage.md`.
|
|
823
1355
|
*/
|
|
1356
|
+
// Tracing/metrics-free: replayStream never uses EngineOptions tracer or metricsHook.
|
|
824
1357
|
export function replayStream(trace) {
|
|
825
1358
|
const result = Promise.resolve(replay(trace));
|
|
826
|
-
const replayEvents = replayStreamEvents(trace);
|
|
827
1359
|
return {
|
|
828
1360
|
get status() {
|
|
829
1361
|
return "completed";
|
|
@@ -833,7 +1365,7 @@ export function replayStream(trace) {
|
|
|
833
1365
|
// Replay streams are already completed snapshots, so cancellation is a no-op.
|
|
834
1366
|
},
|
|
835
1367
|
subscribe(subscriber) {
|
|
836
|
-
for (const event of
|
|
1368
|
+
for (const event of replayStreamEvents(trace)) {
|
|
837
1369
|
subscriber(event);
|
|
838
1370
|
}
|
|
839
1371
|
return {
|
|
@@ -843,29 +1375,22 @@ export function replayStream(trace) {
|
|
|
843
1375
|
};
|
|
844
1376
|
},
|
|
845
1377
|
[Symbol.asyncIterator]() {
|
|
846
|
-
|
|
1378
|
+
const iterator = replayStreamEvents(trace)[Symbol.iterator]();
|
|
847
1379
|
return {
|
|
848
1380
|
next() {
|
|
849
|
-
|
|
850
|
-
if (event) {
|
|
851
|
-
index += 1;
|
|
852
|
-
return Promise.resolve({ done: false, value: event });
|
|
853
|
-
}
|
|
854
|
-
return Promise.resolve({ done: true, value: undefined });
|
|
1381
|
+
return Promise.resolve(iterator.next());
|
|
855
1382
|
}
|
|
856
1383
|
};
|
|
857
1384
|
}
|
|
858
1385
|
};
|
|
859
1386
|
}
|
|
860
|
-
function replayStreamEvents(trace, parentRunIds = []) {
|
|
861
|
-
const
|
|
862
|
-
for (const event of trace.events) {
|
|
1387
|
+
function* replayStreamEvents(trace, parentRunIds = []) {
|
|
1388
|
+
for (const event of synthesizeProviderEvents(trace, trace.providerCalls)) {
|
|
863
1389
|
if (event.type === "sub-run-completed") {
|
|
864
|
-
|
|
1390
|
+
yield* replayStreamEvents(event.subResult.trace, [...parentRunIds, trace.runId]);
|
|
865
1391
|
}
|
|
866
|
-
|
|
1392
|
+
yield wrapReplayStreamEvent(event, parentRunIds);
|
|
867
1393
|
}
|
|
868
|
-
return events;
|
|
869
1394
|
}
|
|
870
1395
|
function wrapReplayStreamEvent(event, parentRunIds) {
|
|
871
1396
|
if (parentRunIds.length === 0) {
|