braintrust 3.21.0 → 3.22.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/dist/workerd.js CHANGED
@@ -93,6 +93,8 @@ __export(workerd_exports, {
93
93
  addAzureBlobHeaders: () => addAzureBlobHeaders,
94
94
  agentAssertionScorer: () => agentAssertionScorer,
95
95
  braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
96
+ braintrustEveHook: () => braintrustEveHook,
97
+ braintrustEveInstrumentation: () => braintrustEveInstrumentation,
96
98
  braintrustFlueInstrumentation: () => braintrustFlueInstrumentation,
97
99
  braintrustFlueObserver: () => braintrustFlueObserver,
98
100
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
@@ -2384,19 +2386,30 @@ var CallEvent = import_v36.z.union([
2384
2386
  var ChatCompletionContentPartTextWithTitle = import_v36.z.object({
2385
2387
  text: import_v36.z.string().default(""),
2386
2388
  type: import_v36.z.literal("text"),
2387
- cache_control: import_v36.z.object({ type: import_v36.z.literal("ephemeral") }).optional()
2389
+ cache_control: import_v36.z.object({
2390
+ type: import_v36.z.literal("ephemeral"),
2391
+ ttl: import_v36.z.enum(["5m", "1h"]).optional()
2392
+ }).optional()
2388
2393
  });
2389
2394
  var ChatCompletionContentPartImageWithTitle = import_v36.z.object({
2390
2395
  image_url: import_v36.z.object({
2391
2396
  url: import_v36.z.string(),
2392
2397
  detail: import_v36.z.union([import_v36.z.literal("auto"), import_v36.z.literal("low"), import_v36.z.literal("high")]).optional()
2393
2398
  }),
2394
- type: import_v36.z.literal("image_url")
2399
+ type: import_v36.z.literal("image_url"),
2400
+ cache_control: import_v36.z.object({
2401
+ type: import_v36.z.literal("ephemeral"),
2402
+ ttl: import_v36.z.enum(["5m", "1h"]).optional()
2403
+ }).optional()
2395
2404
  });
2396
2405
  var ChatCompletionContentPartFileFile = import_v36.z.object({ file_data: import_v36.z.string(), filename: import_v36.z.string(), file_id: import_v36.z.string() }).partial();
2397
2406
  var ChatCompletionContentPartFileWithTitle = import_v36.z.object({
2398
2407
  file: ChatCompletionContentPartFileFile,
2399
- type: import_v36.z.literal("file")
2408
+ type: import_v36.z.literal("file"),
2409
+ cache_control: import_v36.z.object({
2410
+ type: import_v36.z.literal("ephemeral"),
2411
+ ttl: import_v36.z.enum(["5m", "1h"]).optional()
2412
+ }).optional()
2400
2413
  });
2401
2414
  var ChatCompletionContentPart = import_v36.z.union([
2402
2415
  ChatCompletionContentPartTextWithTitle,
@@ -2406,7 +2419,10 @@ var ChatCompletionContentPart = import_v36.z.union([
2406
2419
  var ChatCompletionContentPartText = import_v36.z.object({
2407
2420
  text: import_v36.z.string().default(""),
2408
2421
  type: import_v36.z.literal("text"),
2409
- cache_control: import_v36.z.object({ type: import_v36.z.literal("ephemeral") }).optional()
2422
+ cache_control: import_v36.z.object({
2423
+ type: import_v36.z.literal("ephemeral"),
2424
+ ttl: import_v36.z.enum(["5m", "1h"]).optional()
2425
+ }).optional()
2410
2426
  });
2411
2427
  var ChatCompletionMessageToolCall = import_v36.z.object({
2412
2428
  id: import_v36.z.string(),
@@ -4457,13 +4473,23 @@ var LRUCache = class {
4457
4473
  * @returns The cached value if found, undefined otherwise.
4458
4474
  */
4459
4475
  get(key) {
4460
- const value = this.cache.get(key);
4461
- if (value === void 0) {
4476
+ const entry = this.cache.get(key);
4477
+ if (entry === void 0) {
4462
4478
  return void 0;
4463
4479
  }
4464
4480
  this.cache.delete(key);
4465
- this.cache.set(key, value);
4466
- return value;
4481
+ this.cache.set(key, entry);
4482
+ return entry.value;
4483
+ }
4484
+ /**
4485
+ * Checks whether a key exists and marks it as most recently used.
4486
+ */
4487
+ has(key) {
4488
+ if (!this.cache.has(key)) {
4489
+ return false;
4490
+ }
4491
+ this.get(key);
4492
+ return true;
4467
4493
  }
4468
4494
  /**
4469
4495
  * Stores a value in the cache.
@@ -4480,7 +4506,38 @@ var LRUCache = class {
4480
4506
  const first = this.cache.keys().next().value;
4481
4507
  this.cache.delete(first);
4482
4508
  }
4483
- this.cache.set(key, value);
4509
+ this.cache.set(key, { value });
4510
+ }
4511
+ /**
4512
+ * Removes an item from the cache.
4513
+ */
4514
+ delete(key) {
4515
+ return this.cache.delete(key);
4516
+ }
4517
+ /**
4518
+ * Iterates over cache entries from least to most recently used.
4519
+ */
4520
+ *entries() {
4521
+ for (const [key, entry] of this.cache) {
4522
+ yield [key, entry.value];
4523
+ }
4524
+ }
4525
+ /**
4526
+ * Iterates over cache keys from least to most recently used.
4527
+ */
4528
+ keys() {
4529
+ return this.cache.keys();
4530
+ }
4531
+ /**
4532
+ * Iterates over cache values from least to most recently used.
4533
+ */
4534
+ *values() {
4535
+ for (const entry of this.cache.values()) {
4536
+ yield entry.value;
4537
+ }
4538
+ }
4539
+ [Symbol.iterator]() {
4540
+ return this.entries();
4484
4541
  }
4485
4542
  /**
4486
4543
  * Removes all items from the cache.
@@ -5038,6 +5095,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
5038
5095
  return `ERROR: Failed to mask field '${fieldName}' - ${errorType}`;
5039
5096
  }
5040
5097
  }
5098
+ var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
5099
+ "braintrust.initial-span-write-as-merge"
5100
+ );
5041
5101
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
5042
5102
  "braintrust.currentSpanStore"
5043
5103
  );
@@ -8688,6 +8748,12 @@ var traceable = wrapTraced;
8688
8748
  function startSpan(args) {
8689
8749
  return startSpanAndIsLogger(args).span;
8690
8750
  }
8751
+ function _internalStartSpanWithInitialMerge(args) {
8752
+ return startSpanAndIsLogger({
8753
+ ...args,
8754
+ [INITIAL_SPAN_WRITE_AS_MERGE]: true
8755
+ }).span;
8756
+ }
8691
8757
  async function flush(options) {
8692
8758
  const state = options?.state ?? _globalState;
8693
8759
  return await state.bgLogger().flush();
@@ -9598,7 +9664,7 @@ var SpanImpl = class _SpanImpl {
9598
9664
  this._spanId = resolvedIds.spanId;
9599
9665
  this._rootSpanId = resolvedIds.rootSpanId;
9600
9666
  this._spanParents = resolvedIds.spanParents;
9601
- this.isMerge = false;
9667
+ this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
9602
9668
  this.logInternal({ event, internalData });
9603
9669
  this.isMerge = true;
9604
9670
  }
@@ -31580,6 +31646,8 @@ __export(exports_exports, {
31580
31646
  addAzureBlobHeaders: () => addAzureBlobHeaders,
31581
31647
  agentAssertionScorer: () => agentAssertionScorer,
31582
31648
  braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
31649
+ braintrustEveHook: () => braintrustEveHook,
31650
+ braintrustEveInstrumentation: () => braintrustEveInstrumentation,
31583
31651
  braintrustFlueInstrumentation: () => braintrustFlueInstrumentation,
31584
31652
  braintrustFlueObserver: () => braintrustFlueObserver,
31585
31653
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
@@ -33080,6 +33148,1469 @@ function BraintrustMiddleware(config = {}) {
33080
33148
  };
33081
33149
  }
33082
33150
 
33151
+ // src/instrumentation/plugins/eve-plugin.ts
33152
+ var EVE_TRACE_STATE_KEY = "braintrust.eve.tracing";
33153
+ var MAX_EVE_CACHE_ENTRIES = 1e4;
33154
+ var MAX_STORED_LLM_INPUTS = 100;
33155
+ var MAX_STORED_SPAN_REFERENCES = 1e4;
33156
+ var MAX_STORED_STEP_STARTS = 1e4;
33157
+ function braintrustEveHook(options) {
33158
+ const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
33159
+ const bridge = new EveBridge(state);
33160
+ return {
33161
+ events: {
33162
+ "*": async (event, ctx) => {
33163
+ await bridge.handle(event, ctx, options.metadata);
33164
+ }
33165
+ }
33166
+ };
33167
+ }
33168
+ function braintrustEveInstrumentation(options) {
33169
+ const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
33170
+ return {
33171
+ events: {
33172
+ "step.started": (input) => {
33173
+ try {
33174
+ captureEveModelInput(state, input);
33175
+ } catch (error) {
33176
+ debugLogger.warn("Error in Eve LLM input capture:", error);
33177
+ }
33178
+ }
33179
+ },
33180
+ recordInputs: false,
33181
+ recordOutputs: false,
33182
+ setup: options.setup
33183
+ };
33184
+ }
33185
+ function isEveHandleMessageStreamEvent(event) {
33186
+ return isObject(event) && typeof event["type"] === "string";
33187
+ }
33188
+ var ResumedEveSpan = class {
33189
+ constructor(reference) {
33190
+ this.reference = reference;
33191
+ this.endTime = reference.endTime;
33192
+ }
33193
+ endTime;
33194
+ get rootSpanId() {
33195
+ return this.reference.rootSpanId;
33196
+ }
33197
+ get spanId() {
33198
+ return this.reference.spanId;
33199
+ }
33200
+ log(event) {
33201
+ const metrics = {
33202
+ ...this.reference.startEvent?.metrics,
33203
+ ...this.endTime === void 0 ? {} : { end: this.endTime },
33204
+ ...event.metrics
33205
+ };
33206
+ updateSpan({
33207
+ exported: this.reference.exported,
33208
+ ...this.reference.startEvent,
33209
+ ...event,
33210
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
33211
+ });
33212
+ }
33213
+ end(args) {
33214
+ if (this.endTime === void 0) {
33215
+ this.endTime = args?.endTime ?? getCurrentUnixTimestamp();
33216
+ this.log({ metrics: { end: this.endTime } });
33217
+ }
33218
+ return this.endTime;
33219
+ }
33220
+ };
33221
+ var EveBridge = class {
33222
+ constructor(state) {
33223
+ this.state = state;
33224
+ }
33225
+ eventQueuesBySession = /* @__PURE__ */ new Map();
33226
+ sessionsById = new LRUCache({
33227
+ max: MAX_EVE_CACHE_ENTRIES
33228
+ });
33229
+ completedToolKeys = new LRUCache({
33230
+ max: MAX_EVE_CACHE_ENTRIES
33231
+ });
33232
+ toolsByCallKey = new LRUCache({
33233
+ max: MAX_EVE_CACHE_ENTRIES
33234
+ });
33235
+ turnsByKey = new LRUCache({
33236
+ max: MAX_EVE_CACHE_ENTRIES
33237
+ });
33238
+ async startEveSpan(args) {
33239
+ const rowId = args?.event?.id;
33240
+ const reference = typeof rowId === "string" && readEveTraceState(this.state).spanReferences.find(
33241
+ (candidate) => candidate.rowId === rowId
33242
+ );
33243
+ if (reference) {
33244
+ return new ResumedEveSpan(reference);
33245
+ }
33246
+ const startTime = args?.startTime ?? getCurrentUnixTimestamp();
33247
+ const parentSpanIds = args?.parentSpanIds;
33248
+ const startEvent = {
33249
+ created: (/* @__PURE__ */ new Date()).toISOString(),
33250
+ metrics: { start: startTime },
33251
+ span_attributes: {
33252
+ ...args?.name ? { name: args.name } : {},
33253
+ ...args?.type ? { type: args.type } : {},
33254
+ ...args?.spanAttributes
33255
+ },
33256
+ span_parents: parentSpanIds ? "spanId" in parentSpanIds ? [parentSpanIds.spanId] : parentSpanIds.parentSpanIds : []
33257
+ };
33258
+ const span = withCurrent(
33259
+ NOOP_SPAN,
33260
+ () => _internalStartSpanWithInitialMerge({ ...args, startTime })
33261
+ );
33262
+ if (typeof rowId !== "string") {
33263
+ return span;
33264
+ }
33265
+ try {
33266
+ const exported = await span.export();
33267
+ const reference2 = {
33268
+ exported,
33269
+ rootSpanId: span.rootSpanId,
33270
+ rowId,
33271
+ spanId: span.spanId,
33272
+ startEvent
33273
+ };
33274
+ this.state.update((current) => {
33275
+ const normalized = normalizeEveTraceState(current);
33276
+ return normalized.spanReferences.some(
33277
+ (candidate) => candidate.rowId === rowId
33278
+ ) ? normalized : {
33279
+ ...normalized,
33280
+ spanReferences: [...normalized.spanReferences, reference2].slice(
33281
+ -MAX_STORED_SPAN_REFERENCES
33282
+ )
33283
+ };
33284
+ });
33285
+ } catch (error) {
33286
+ debugLogger.warn("Error exporting Eve span for resumption:", error);
33287
+ }
33288
+ return span;
33289
+ }
33290
+ async startEveChildSpan(parent, args) {
33291
+ return await this.startEveSpan({
33292
+ ...args,
33293
+ parentSpanIds: {
33294
+ rootSpanId: parent.rootSpanId,
33295
+ spanId: parent.spanId
33296
+ }
33297
+ });
33298
+ }
33299
+ stepOrdinal(event) {
33300
+ let ordinal = 0;
33301
+ this.state.update((current) => {
33302
+ const state = normalizeEveTraceState(current);
33303
+ const previous = state.stepStarts.filter(
33304
+ (entry) => entry.turnId === event.data.turnId && entry.stepIndex === event.data.stepIndex
33305
+ ).at(-1);
33306
+ if (previous?.open) {
33307
+ ordinal = previous.ordinal;
33308
+ return state;
33309
+ }
33310
+ ordinal = state.stepStarts.filter(
33311
+ (entry) => entry.turnId === event.data.turnId
33312
+ ).length;
33313
+ return {
33314
+ ...state,
33315
+ stepStarts: [
33316
+ ...state.stepStarts,
33317
+ {
33318
+ open: true,
33319
+ ordinal,
33320
+ stepIndex: event.data.stepIndex,
33321
+ turnId: event.data.turnId
33322
+ }
33323
+ ].slice(-MAX_STORED_STEP_STARTS)
33324
+ };
33325
+ });
33326
+ return ordinal;
33327
+ }
33328
+ markStepEnded(turnId, stepIndex) {
33329
+ this.state.update((current) => {
33330
+ const state = normalizeEveTraceState(current);
33331
+ let index = -1;
33332
+ for (let i = state.stepStarts.length - 1; i >= 0; i--) {
33333
+ const entry = state.stepStarts[i];
33334
+ if (entry?.turnId === turnId && entry.stepIndex === stepIndex) {
33335
+ index = i;
33336
+ break;
33337
+ }
33338
+ }
33339
+ if (index < 0 || !state.stepStarts[index]?.open) {
33340
+ return state;
33341
+ }
33342
+ return {
33343
+ ...state,
33344
+ stepStarts: state.stepStarts.map(
33345
+ (entry, entryIndex) => entryIndex === index ? { ...entry, open: false } : entry
33346
+ )
33347
+ };
33348
+ });
33349
+ }
33350
+ async handle(event, ctx, hookMetadata) {
33351
+ if (!isEveHandleMessageStreamEvent(event)) {
33352
+ return;
33353
+ }
33354
+ const run = async () => {
33355
+ try {
33356
+ if (!await this.handleEvent(event, ctx, hookMetadata)) {
33357
+ return;
33358
+ }
33359
+ if (event.type === "session.failed") {
33360
+ const sessionId2 = event.data.sessionId || sessionIdFromContext(ctx);
33361
+ await this.flushInstrumentation();
33362
+ if (sessionId2) {
33363
+ this.cleanupSession(sessionId2);
33364
+ }
33365
+ } else if (event.type === "session.completed") {
33366
+ const sessionId2 = sessionIdFromContext(ctx);
33367
+ await this.flushInstrumentation();
33368
+ if (sessionId2) {
33369
+ this.cleanupSession(sessionId2);
33370
+ }
33371
+ }
33372
+ } catch (error) {
33373
+ debugLogger.warn("Error in Eve hook instrumentation:", error);
33374
+ }
33375
+ };
33376
+ const sessionId = event.type === "session.failed" ? event.data.sessionId || sessionIdFromContext(ctx) : sessionIdFromContext(ctx);
33377
+ if (!sessionId) {
33378
+ await run();
33379
+ return;
33380
+ }
33381
+ const previous = this.eventQueuesBySession.get(sessionId);
33382
+ const queued = previous ? previous.then(run) : run();
33383
+ this.eventQueuesBySession.set(sessionId, queued);
33384
+ try {
33385
+ await queued;
33386
+ } finally {
33387
+ if (this.eventQueuesBySession.get(sessionId) === queued) {
33388
+ this.eventQueuesBySession.delete(sessionId);
33389
+ }
33390
+ }
33391
+ }
33392
+ async handleEvent(event, ctx, hookMetadata) {
33393
+ switch (event.type) {
33394
+ case "session.started":
33395
+ await this.handleSessionStarted(event, ctx, hookMetadata);
33396
+ return true;
33397
+ case "turn.started":
33398
+ await this.handleTurnStarted(event, ctx, hookMetadata);
33399
+ return true;
33400
+ case "message.received":
33401
+ await this.handleMessageReceived(event, ctx, hookMetadata);
33402
+ return true;
33403
+ case "step.started":
33404
+ await this.handleStepStarted(event, ctx, hookMetadata);
33405
+ return true;
33406
+ case "message.completed":
33407
+ this.handleMessageCompleted(event, ctx);
33408
+ return true;
33409
+ case "result.completed":
33410
+ this.handleResultCompleted(event, ctx);
33411
+ return true;
33412
+ case "actions.requested":
33413
+ await this.handleActionsRequested(event, ctx, hookMetadata);
33414
+ return true;
33415
+ case "action.result":
33416
+ await this.handleActionResult(event, ctx, hookMetadata);
33417
+ return true;
33418
+ case "subagent.called":
33419
+ await this.handleSubagentCalled(event, ctx, hookMetadata);
33420
+ return true;
33421
+ case "subagent.completed":
33422
+ await this.handleSubagentCompleted(event, ctx, hookMetadata);
33423
+ return true;
33424
+ case "step.completed":
33425
+ this.handleStepCompleted(event, ctx);
33426
+ return true;
33427
+ case "step.failed":
33428
+ this.handleStepFailed(event, ctx);
33429
+ return true;
33430
+ case "turn.completed":
33431
+ await this.handleTurnCompleted(event, ctx);
33432
+ return true;
33433
+ case "turn.failed":
33434
+ await this.handleTurnFailed(event, ctx);
33435
+ return true;
33436
+ case "session.failed":
33437
+ await this.handleSessionFailed(event, ctx);
33438
+ return true;
33439
+ case "session.completed":
33440
+ await this.handleSessionCompleted(event, ctx);
33441
+ return true;
33442
+ default:
33443
+ return false;
33444
+ }
33445
+ }
33446
+ async handleSessionStarted(event, ctx, hookMetadata) {
33447
+ const sessionId = sessionIdFromContext(ctx);
33448
+ if (!sessionId) {
33449
+ return;
33450
+ }
33451
+ const metadata = {
33452
+ ...hookMetadata ?? {},
33453
+ ...modelMetadataFromRuntime(event.data.runtime)
33454
+ };
33455
+ this.state.update((current) => {
33456
+ const normalized = normalizeEveTraceState(current);
33457
+ return {
33458
+ ...normalized,
33459
+ metadata: { ...normalized.metadata, ...metadata }
33460
+ };
33461
+ });
33462
+ await this.ensureSession(sessionId, ctx, metadata, eventTime2(event));
33463
+ for (const [key, turn] of this.turnsByKey) {
33464
+ if (!key.startsWith(`${sessionId}:`)) {
33465
+ continue;
33466
+ }
33467
+ turn.metadata = { ...turn.metadata, ...metadata };
33468
+ turn.span.log({ metadata: turn.metadata });
33469
+ for (const step of turn.stepsByIndex.values()) {
33470
+ step.metadata = { ...step.metadata, ...metadata };
33471
+ step.span.log({ metadata: step.metadata });
33472
+ }
33473
+ }
33474
+ }
33475
+ async handleTurnStarted(event, ctx, hookMetadata) {
33476
+ const sessionId = sessionIdFromContext(ctx);
33477
+ if (!sessionId) {
33478
+ return;
33479
+ }
33480
+ const session = await this.ensureSession(
33481
+ sessionId,
33482
+ ctx,
33483
+ hookMetadata ?? {},
33484
+ eventTime2(event)
33485
+ );
33486
+ const key = turnKey2(sessionId, event.data.turnId);
33487
+ const metadata = { ...session.metadata };
33488
+ const existing = this.turnsByKey.get(key);
33489
+ if (existing) {
33490
+ existing.metadata = { ...existing.metadata, ...metadata };
33491
+ existing.span.log({ metadata: existing.metadata });
33492
+ return;
33493
+ }
33494
+ const span = await this.startTurnSpan(session, event, metadata);
33495
+ span.log({ metadata });
33496
+ this.turnsByKey.set(key, {
33497
+ key,
33498
+ metadata,
33499
+ metrics: {},
33500
+ span,
33501
+ stepsByIndex: /* @__PURE__ */ new Map(),
33502
+ turnId: event.data.turnId
33503
+ });
33504
+ }
33505
+ async handleMessageReceived(event, ctx, hookMetadata) {
33506
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33507
+ if (!turn) {
33508
+ return;
33509
+ }
33510
+ const input = [{ content: event.data.message, role: "user" }];
33511
+ turn.span.log({ input });
33512
+ }
33513
+ async handleStepStarted(event, ctx, hookMetadata) {
33514
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33515
+ const sessionId = sessionIdFromContext(ctx);
33516
+ if (!turn || !sessionId) {
33517
+ return;
33518
+ }
33519
+ const existing = turn.stepsByIndex.get(event.data.stepIndex);
33520
+ if (existing) {
33521
+ existing.span.log({
33522
+ ...existing.input !== void 0 ? { input: existing.input } : {},
33523
+ metadata: existing.metadata,
33524
+ metrics: existing.metrics,
33525
+ output: existing.output
33526
+ });
33527
+ const endTime = eventTime2(event);
33528
+ existing.span.end(endTime === void 0 ? void 0 : { endTime });
33529
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
33530
+ }
33531
+ const stepOrdinal = this.stepOrdinal(event);
33532
+ const metadata = {
33533
+ ...turn.metadata,
33534
+ ...this.sessionsById.get(sessionId)?.metadata ?? {}
33535
+ };
33536
+ const input = consumeCapturedEveModelInput(
33537
+ this.state,
33538
+ sessionId,
33539
+ event.data.turnId,
33540
+ event.data.stepIndex
33541
+ );
33542
+ const { rowId: eventId, spanId } = await generateEveIds(
33543
+ "step",
33544
+ sessionId,
33545
+ event.data.turnId,
33546
+ String(stepOrdinal)
33547
+ );
33548
+ const span = await this.startEveChildSpan(turn.span, {
33549
+ event: {
33550
+ id: eventId,
33551
+ ...input !== void 0 ? { input } : {},
33552
+ metadata
33553
+ },
33554
+ name: "eve.step",
33555
+ spanAttributes: { type: "llm" /* LLM */ },
33556
+ spanId,
33557
+ startTime: eventTime2(event)
33558
+ });
33559
+ span.log({ ...input !== void 0 ? { input } : {}, metadata });
33560
+ turn.stepsByIndex.set(event.data.stepIndex, {
33561
+ ...input !== void 0 ? { input } : {},
33562
+ metadata,
33563
+ metrics: {},
33564
+ span
33565
+ });
33566
+ }
33567
+ handleMessageCompleted(event, ctx) {
33568
+ const step = this.stepForEvent(event, ctx);
33569
+ if (!step) {
33570
+ return;
33571
+ }
33572
+ const existingMessage = Array.isArray(step.output) && isObject(step.output[0]) ? step.output[0].message : void 0;
33573
+ const existingToolCalls = isObject(existingMessage) ? existingMessage.tool_calls : void 0;
33574
+ step.output = [
33575
+ {
33576
+ finish_reason: normalizedFinishReason(event.data.finishReason),
33577
+ index: 0,
33578
+ message: {
33579
+ content: event.data.message,
33580
+ role: "assistant",
33581
+ ...Array.isArray(existingToolCalls) ? { tool_calls: existingToolCalls } : {}
33582
+ }
33583
+ }
33584
+ ];
33585
+ const turn = this.turnForEvent(event, ctx);
33586
+ if (turn && event.data.finishReason !== "tool-calls") {
33587
+ turn.output = event.data.message;
33588
+ }
33589
+ }
33590
+ handleResultCompleted(event, ctx) {
33591
+ const step = this.stepForEvent(event, ctx);
33592
+ if (step) {
33593
+ step.output = [
33594
+ {
33595
+ finish_reason: "stop",
33596
+ index: 0,
33597
+ message: {
33598
+ content: event.data.result,
33599
+ role: "assistant"
33600
+ }
33601
+ }
33602
+ ];
33603
+ }
33604
+ const turn = this.turnForEvent(event, ctx);
33605
+ if (turn) {
33606
+ turn.output = event.data.result;
33607
+ }
33608
+ }
33609
+ async handleActionsRequested(event, ctx, hookMetadata) {
33610
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33611
+ const sessionId = sessionIdFromContext(ctx);
33612
+ if (!turn || !sessionId) {
33613
+ return;
33614
+ }
33615
+ const traceActions = event.data.actions.filter(isTraceableActionRequest);
33616
+ if (traceActions.length === 0) {
33617
+ return;
33618
+ }
33619
+ for (const action of traceActions) {
33620
+ if (isToolCallAction(action)) {
33621
+ await this.startRequestedTool(event, turn, sessionId, action);
33622
+ } else if (isLocalSubagentCallAction(action)) {
33623
+ await this.startRequestedSubagent(event, turn, sessionId, action);
33624
+ }
33625
+ }
33626
+ const step = turn.stepsByIndex.get(event.data.stepIndex);
33627
+ if (!step) {
33628
+ return;
33629
+ }
33630
+ step.output = [
33631
+ {
33632
+ finish_reason: "tool_calls",
33633
+ index: 0,
33634
+ message: {
33635
+ content: null,
33636
+ role: "assistant",
33637
+ tool_calls: traceActions.map((action) => {
33638
+ const name = action.kind === "tool-call" ? action.toolName : action.subagentName ?? action.name ?? "agent";
33639
+ return {
33640
+ function: {
33641
+ arguments: JSON.stringify(action.input),
33642
+ name
33643
+ },
33644
+ id: action.callId,
33645
+ type: "function"
33646
+ };
33647
+ })
33648
+ }
33649
+ }
33650
+ ];
33651
+ step.span.log({ metadata: step.metadata, output: step.output });
33652
+ }
33653
+ async handleActionResult(event, ctx, hookMetadata) {
33654
+ if (isToolResult(event.data.result)) {
33655
+ await this.handleToolResult(event, ctx, event.data.result, hookMetadata);
33656
+ return;
33657
+ }
33658
+ if (isSubagentResult(event.data.result)) {
33659
+ await this.handleSubagentResult(
33660
+ event,
33661
+ ctx,
33662
+ event.data.result,
33663
+ hookMetadata
33664
+ );
33665
+ }
33666
+ }
33667
+ async handleToolResult(event, ctx, result, hookMetadata) {
33668
+ const sessionId = sessionIdFromContext(ctx);
33669
+ if (!sessionId) {
33670
+ return;
33671
+ }
33672
+ const key = toolKey3(sessionId, result.callId);
33673
+ if (this.completedToolKeys.has(key)) {
33674
+ return;
33675
+ }
33676
+ const tool = this.toolsByCallKey.get(key) ?? await this.startSyntheticTool(event, ctx, result, hookMetadata);
33677
+ if (!tool) {
33678
+ return;
33679
+ }
33680
+ const failed = event.data.status === "failed" || result.isError === true || event.data.error !== void 0;
33681
+ tool.span.log({
33682
+ ...failed ? {
33683
+ error: actionResultError(event.data.error, result.output)
33684
+ } : {},
33685
+ metadata: tool.metadata,
33686
+ output: result.output
33687
+ });
33688
+ const endTime = eventTime2(event);
33689
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
33690
+ this.toolsByCallKey.delete(key);
33691
+ this.completedToolKeys.set(key, true);
33692
+ }
33693
+ async handleSubagentCalled(event, ctx, hookMetadata) {
33694
+ if (event.data.remote?.url) {
33695
+ return;
33696
+ }
33697
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33698
+ const sessionId = sessionIdFromContext(ctx);
33699
+ if (!turn || !sessionId) {
33700
+ return;
33701
+ }
33702
+ const key = toolKey3(sessionId, event.data.callId);
33703
+ const metadata = toolMetadataFromTurn(turn);
33704
+ const existing = this.toolsByCallKey.get(key);
33705
+ if (existing) {
33706
+ existing.metadata = { ...existing.metadata, ...metadata };
33707
+ existing.span.log({ metadata: existing.metadata });
33708
+ return;
33709
+ }
33710
+ if (this.completedToolKeys.has(key)) {
33711
+ return;
33712
+ }
33713
+ const { rowId: eventId, spanId } = await generateEveIds(
33714
+ "subagent",
33715
+ sessionId,
33716
+ event.data.callId
33717
+ );
33718
+ const pending = this.toolsByCallKey.get(key);
33719
+ if (pending || this.completedToolKeys.has(key)) {
33720
+ if (pending) {
33721
+ pending.metadata = { ...pending.metadata, ...metadata };
33722
+ pending.span.log({ metadata: pending.metadata });
33723
+ }
33724
+ return;
33725
+ }
33726
+ const span = await this.startEveChildSpan(turn.span, {
33727
+ event: {
33728
+ id: eventId,
33729
+ metadata
33730
+ },
33731
+ name: event.data.toolName ?? event.data.name,
33732
+ spanAttributes: { type: "tool" /* TOOL */ },
33733
+ spanId,
33734
+ startTime: eventTime2(event)
33735
+ });
33736
+ span.log({ metadata });
33737
+ this.toolsByCallKey.set(key, {
33738
+ metadata,
33739
+ span,
33740
+ turnKey: turnKey2(sessionId, event.data.turnId)
33741
+ });
33742
+ }
33743
+ async handleSubagentCompleted(event, ctx, hookMetadata) {
33744
+ const sessionId = sessionIdFromContext(ctx);
33745
+ if (!sessionId) {
33746
+ return;
33747
+ }
33748
+ const key = toolKey3(sessionId, event.data.callId);
33749
+ if (this.completedToolKeys.has(key)) {
33750
+ return;
33751
+ }
33752
+ const subagent = this.toolsByCallKey.get(key) ?? await this.startSyntheticSubagent(event, ctx, hookMetadata);
33753
+ if (!subagent) {
33754
+ return;
33755
+ }
33756
+ subagent.span.log({
33757
+ ...event.data.status === "failed" ? {
33758
+ error: actionResultError(event.data.error, event.data.output)
33759
+ } : {},
33760
+ metadata: subagent.metadata,
33761
+ ...event.data.output !== void 0 ? { output: event.data.output } : {}
33762
+ });
33763
+ const endTime = eventTime2(event);
33764
+ const recordedEndTime = subagent.span.end(
33765
+ endTime === void 0 ? void 0 : { endTime }
33766
+ );
33767
+ this.state.update((current) => {
33768
+ const normalized = normalizeEveTraceState(current);
33769
+ return {
33770
+ ...normalized,
33771
+ spanReferences: normalized.spanReferences.map(
33772
+ (reference) => reference.spanId === subagent.span.spanId ? { ...reference, endTime: recordedEndTime } : reference
33773
+ )
33774
+ };
33775
+ });
33776
+ }
33777
+ async handleSubagentResult(event, ctx, result, hookMetadata) {
33778
+ const sessionId = sessionIdFromContext(ctx);
33779
+ if (!sessionId) {
33780
+ return;
33781
+ }
33782
+ const key = toolKey3(sessionId, result.callId);
33783
+ if (this.completedToolKeys.has(key)) {
33784
+ return;
33785
+ }
33786
+ const subagent = this.toolsByCallKey.get(key) ?? await this.startSyntheticSubagentResult(
33787
+ event,
33788
+ ctx,
33789
+ result,
33790
+ hookMetadata
33791
+ );
33792
+ if (!subagent) {
33793
+ return;
33794
+ }
33795
+ const isError = event.data.status === "failed" || result.isError === true || event.data.error !== void 0;
33796
+ subagent.span.log({
33797
+ ...isError ? {
33798
+ error: actionResultError(event.data.error, result.output)
33799
+ } : {},
33800
+ metadata: subagent.metadata,
33801
+ output: result.output
33802
+ });
33803
+ const endTime = eventTime2(event);
33804
+ subagent.span.end(endTime === void 0 ? void 0 : { endTime });
33805
+ this.toolsByCallKey.delete(key);
33806
+ this.completedToolKeys.set(key, true);
33807
+ }
33808
+ handleStepCompleted(event, ctx) {
33809
+ const step = this.stepForEvent(event, ctx);
33810
+ if (!step) {
33811
+ return;
33812
+ }
33813
+ const usage = event.data.usage;
33814
+ const inputTokens = typeof usage?.inputTokens === "number" && Number.isFinite(usage.inputTokens) && usage.inputTokens >= 0 ? usage.inputTokens : void 0;
33815
+ const outputTokens = typeof usage?.outputTokens === "number" && Number.isFinite(usage.outputTokens) && usage.outputTokens >= 0 ? usage.outputTokens : void 0;
33816
+ const cacheReadTokens = typeof usage?.cacheReadTokens === "number" && Number.isFinite(usage.cacheReadTokens) && usage.cacheReadTokens >= 0 ? usage.cacheReadTokens : void 0;
33817
+ const cacheWriteTokens = typeof usage?.cacheWriteTokens === "number" && Number.isFinite(usage.cacheWriteTokens) && usage.cacheWriteTokens >= 0 ? usage.cacheWriteTokens : void 0;
33818
+ const costUsd = typeof usage?.costUsd === "number" && Number.isFinite(usage.costUsd) && usage.costUsd >= 0 ? usage.costUsd : void 0;
33819
+ const total = inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0;
33820
+ const metrics = {
33821
+ ...inputTokens !== void 0 ? { prompt_tokens: inputTokens } : {},
33822
+ ...outputTokens !== void 0 ? { completion_tokens: outputTokens } : {},
33823
+ ...total !== void 0 ? { tokens: total } : {},
33824
+ ...cacheReadTokens !== void 0 ? { prompt_cached_tokens: cacheReadTokens } : {},
33825
+ ...cacheWriteTokens !== void 0 ? { prompt_cache_creation_tokens: cacheWriteTokens } : {},
33826
+ ...costUsd !== void 0 ? { estimated_cost: costUsd } : {}
33827
+ };
33828
+ step.metrics = { ...step.metrics, ...metrics };
33829
+ if (Array.isArray(step.output) && isObject(step.output[0])) {
33830
+ const finishReason = step.output[0].finish_reason;
33831
+ if (typeof finishReason !== "string") {
33832
+ step.output[0].finish_reason = normalizedFinishReason(
33833
+ event.data.finishReason
33834
+ );
33835
+ }
33836
+ }
33837
+ step.span.log({
33838
+ ...step.input !== void 0 ? { input: step.input } : {},
33839
+ metadata: step.metadata,
33840
+ metrics,
33841
+ output: step.output
33842
+ });
33843
+ const endTime = eventTime2(event);
33844
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
33845
+ const turn = this.turnForEvent(event, ctx);
33846
+ if (turn) {
33847
+ for (const [key, value] of Object.entries(metrics)) {
33848
+ turn.metrics[key] = (turn.metrics[key] ?? 0) + value;
33849
+ }
33850
+ turn.stepsByIndex.delete(event.data.stepIndex);
33851
+ }
33852
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
33853
+ }
33854
+ handleStepFailed(event, ctx) {
33855
+ const step = this.stepForEvent(event, ctx);
33856
+ if (step) {
33857
+ step.span.log({
33858
+ error: errorFromMessage(
33859
+ event.data.message,
33860
+ event.data.code,
33861
+ event.data.details
33862
+ )
33863
+ });
33864
+ const endTime = eventTime2(event);
33865
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
33866
+ }
33867
+ const turn = this.turnForEvent(event, ctx);
33868
+ turn?.stepsByIndex.delete(event.data.stepIndex);
33869
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
33870
+ }
33871
+ handleTurnCompleted(event, ctx) {
33872
+ const turn = this.turnForEvent(event, ctx);
33873
+ if (!turn) {
33874
+ return;
33875
+ }
33876
+ this.finalizeTurn(turn, {
33877
+ endTime: eventTime2(event)
33878
+ });
33879
+ }
33880
+ handleTurnFailed(event, ctx) {
33881
+ const turn = this.turnForEvent(event, ctx);
33882
+ if (!turn) {
33883
+ return;
33884
+ }
33885
+ this.finalizeTurn(turn, {
33886
+ endTime: eventTime2(event),
33887
+ error: errorFromMessage(
33888
+ event.data.message,
33889
+ event.data.code,
33890
+ event.data.details
33891
+ )
33892
+ });
33893
+ }
33894
+ async handleSessionFailed(event, ctx) {
33895
+ const sessionId = event.data.sessionId || sessionIdFromContext(ctx);
33896
+ if (!sessionId) {
33897
+ return;
33898
+ }
33899
+ const session = await this.ensureSession(
33900
+ sessionId,
33901
+ ctx,
33902
+ {},
33903
+ eventTime2(event)
33904
+ );
33905
+ const error = errorFromMessage(
33906
+ event.data.message,
33907
+ event.data.code,
33908
+ event.data.details
33909
+ );
33910
+ for (const [key, turn] of this.turnsByKey) {
33911
+ if (!key.startsWith(`${sessionId}:`)) {
33912
+ continue;
33913
+ }
33914
+ this.finalizeTurn(turn, {
33915
+ endTime: eventTime2(event),
33916
+ error
33917
+ });
33918
+ }
33919
+ for (const [key, tool] of this.toolsByCallKey) {
33920
+ if (key.startsWith(`${sessionId}:`)) {
33921
+ const endTime2 = eventTime2(event);
33922
+ if (!tool.endedByTurn) {
33923
+ tool.span.log({ metadata: tool.metadata });
33924
+ tool.span.end(endTime2 === void 0 ? void 0 : { endTime: endTime2 });
33925
+ tool.endedByTurn = true;
33926
+ }
33927
+ }
33928
+ }
33929
+ session.span.log({ error });
33930
+ const endTime = eventTime2(event);
33931
+ session.span.end(endTime === void 0 ? void 0 : { endTime });
33932
+ }
33933
+ async handleSessionCompleted(event, ctx) {
33934
+ const sessionId = sessionIdFromContext(ctx);
33935
+ if (!sessionId) {
33936
+ return;
33937
+ }
33938
+ const session = await this.ensureSession(
33939
+ sessionId,
33940
+ ctx,
33941
+ {},
33942
+ eventTime2(event)
33943
+ );
33944
+ for (const [key, turn] of this.turnsByKey) {
33945
+ if (!key.startsWith(`${sessionId}:`)) {
33946
+ continue;
33947
+ }
33948
+ this.finalizeTurn(turn, {
33949
+ endTime: eventTime2(event)
33950
+ });
33951
+ }
33952
+ for (const [key, tool] of this.toolsByCallKey) {
33953
+ if (key.startsWith(`${sessionId}:`) && !tool.endedByTurn) {
33954
+ const endTime2 = eventTime2(event);
33955
+ tool.span.log({ metadata: tool.metadata });
33956
+ tool.span.end(endTime2 === void 0 ? void 0 : { endTime: endTime2 });
33957
+ tool.endedByTurn = true;
33958
+ }
33959
+ }
33960
+ session.span.log({ metadata: session.metadata });
33961
+ const endTime = eventTime2(event);
33962
+ session.span.end(endTime === void 0 ? void 0 : { endTime });
33963
+ }
33964
+ async ensureSession(sessionId, ctx, metadata, startTime) {
33965
+ metadata = {
33966
+ ...readEveTraceState(this.state).metadata,
33967
+ ...metadata
33968
+ };
33969
+ const existing = this.sessionsById.get(sessionId);
33970
+ if (existing) {
33971
+ existing.metadata = { ...existing.metadata, ...metadata };
33972
+ existing.span.log({ metadata: existing.metadata });
33973
+ return existing;
33974
+ }
33975
+ const lineage = parentLineageFromContext(ctx);
33976
+ const parentSubagent = lineage ? this.toolsByCallKey.get(toolKey3(lineage.sessionId, lineage.callId)) : void 0;
33977
+ const activeParent = currentSpan();
33978
+ const [
33979
+ { rowId: eventId, spanId },
33980
+ parentSubagentSpanId,
33981
+ fallbackRootSpanId
33982
+ ] = await Promise.all([
33983
+ generateEveIds("session", sessionId),
33984
+ lineage ? spanIdForSubagent(lineage.sessionId, lineage.callId) : Promise.resolve(void 0),
33985
+ lineage ? rootSpanIdForSession(lineage.rootSessionId) : rootSpanIdForSession(sessionId)
33986
+ ]);
33987
+ const span = await this.startEveSpan({
33988
+ event: {
33989
+ id: eventId,
33990
+ metadata
33991
+ },
33992
+ name: "eve.session",
33993
+ parentSpanIds: lineage && parentSubagentSpanId ? {
33994
+ rootSpanId: parentSubagent?.span.rootSpanId ?? fallbackRootSpanId,
33995
+ spanId: parentSubagentSpanId
33996
+ } : !Object.is(activeParent, NOOP_SPAN) ? {
33997
+ rootSpanId: activeParent.rootSpanId,
33998
+ spanId: activeParent.spanId
33999
+ } : {
34000
+ parentSpanIds: [],
34001
+ rootSpanId: fallbackRootSpanId
34002
+ },
34003
+ spanAttributes: { type: "task" /* TASK */ },
34004
+ spanId,
34005
+ startTime
34006
+ });
34007
+ span.log({ metadata });
34008
+ const session = { metadata, sessionId, span };
34009
+ this.sessionsById.set(sessionId, session);
34010
+ return session;
34011
+ }
34012
+ async ensureTurn(event, ctx, hookMetadata) {
34013
+ const sessionId = sessionIdFromContext(ctx);
34014
+ if (!sessionId) {
34015
+ return void 0;
34016
+ }
34017
+ const session = await this.ensureSession(
34018
+ sessionId,
34019
+ ctx,
34020
+ hookMetadata ?? {},
34021
+ eventTime2(event)
34022
+ );
34023
+ const key = turnKey2(sessionId, event.data.turnId);
34024
+ const existing = this.turnsByKey.get(key);
34025
+ if (existing) {
34026
+ return existing;
34027
+ }
34028
+ const metadata = { ...session.metadata };
34029
+ const span = await this.startTurnSpan(session, event, metadata);
34030
+ span.log({ metadata });
34031
+ const state = {
34032
+ key,
34033
+ metadata,
34034
+ metrics: {},
34035
+ span,
34036
+ stepsByIndex: /* @__PURE__ */ new Map(),
34037
+ turnId: event.data.turnId
34038
+ };
34039
+ this.turnsByKey.set(key, state);
34040
+ return state;
34041
+ }
34042
+ async startRequestedTool(event, turn, sessionId, action) {
34043
+ const key = toolKey3(sessionId, action.callId);
34044
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34045
+ return;
34046
+ }
34047
+ const metadata = toolMetadataFromTurn(turn);
34048
+ const { rowId: eventId, spanId } = await generateEveIds(
34049
+ "tool",
34050
+ sessionId,
34051
+ event.data.turnId,
34052
+ action.callId
34053
+ );
34054
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34055
+ return;
34056
+ }
34057
+ const span = await this.startEveChildSpan(turn.span, {
34058
+ event: {
34059
+ id: eventId,
34060
+ input: action.input,
34061
+ metadata
34062
+ },
34063
+ name: action.toolName,
34064
+ spanAttributes: { type: "tool" /* TOOL */ },
34065
+ spanId,
34066
+ startTime: eventTime2(event)
34067
+ });
34068
+ span.log({ input: action.input, metadata });
34069
+ this.toolsByCallKey.set(key, {
34070
+ metadata,
34071
+ span,
34072
+ turnKey: turnKey2(sessionId, event.data.turnId)
34073
+ });
34074
+ }
34075
+ async startRequestedSubagent(event, turn, sessionId, action) {
34076
+ const key = toolKey3(sessionId, action.callId);
34077
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34078
+ return;
34079
+ }
34080
+ const name = action.subagentName ?? action.name ?? "agent";
34081
+ const metadata = toolMetadataFromTurn(turn);
34082
+ const { rowId: eventId, spanId } = await generateEveIds(
34083
+ "subagent",
34084
+ sessionId,
34085
+ action.callId
34086
+ );
34087
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34088
+ return;
34089
+ }
34090
+ const span = await this.startEveChildSpan(turn.span, {
34091
+ event: {
34092
+ id: eventId,
34093
+ input: action.input,
34094
+ metadata
34095
+ },
34096
+ name,
34097
+ spanAttributes: { type: "tool" /* TOOL */ },
34098
+ spanId,
34099
+ startTime: eventTime2(event)
34100
+ });
34101
+ span.log({ input: action.input, metadata });
34102
+ this.toolsByCallKey.set(key, {
34103
+ metadata,
34104
+ span,
34105
+ turnKey: turnKey2(sessionId, event.data.turnId)
34106
+ });
34107
+ }
34108
+ async startSyntheticTool(event, ctx, result, hookMetadata) {
34109
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34110
+ const sessionId = sessionIdFromContext(ctx);
34111
+ if (!turn || !sessionId) {
34112
+ return void 0;
34113
+ }
34114
+ const metadata = toolMetadataFromTurn(turn);
34115
+ const { rowId: eventId, spanId } = await generateEveIds(
34116
+ "tool",
34117
+ sessionId,
34118
+ event.data.turnId,
34119
+ result.callId
34120
+ );
34121
+ const existing = this.toolsByCallKey.get(toolKey3(sessionId, result.callId));
34122
+ if (existing) {
34123
+ return existing;
34124
+ }
34125
+ const span = await this.startEveChildSpan(turn.span, {
34126
+ event: {
34127
+ id: eventId,
34128
+ metadata
34129
+ },
34130
+ name: result.toolName,
34131
+ spanAttributes: { type: "tool" /* TOOL */ },
34132
+ spanId,
34133
+ startTime: eventTime2(event)
34134
+ });
34135
+ span.log({ metadata });
34136
+ const state = {
34137
+ metadata,
34138
+ span,
34139
+ turnKey: turnKey2(sessionId, event.data.turnId)
34140
+ };
34141
+ this.toolsByCallKey.set(toolKey3(sessionId, result.callId), state);
34142
+ return state;
34143
+ }
34144
+ async startSyntheticSubagent(event, ctx, hookMetadata) {
34145
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34146
+ const sessionId = sessionIdFromContext(ctx);
34147
+ if (!turn || !sessionId) {
34148
+ return void 0;
34149
+ }
34150
+ const metadata = toolMetadataFromTurn(turn);
34151
+ const { rowId: eventId, spanId } = await generateEveIds(
34152
+ "subagent",
34153
+ sessionId,
34154
+ event.data.callId
34155
+ );
34156
+ const existing = this.toolsByCallKey.get(
34157
+ toolKey3(sessionId, event.data.callId)
34158
+ );
34159
+ if (existing) {
34160
+ return existing;
34161
+ }
34162
+ const span = await this.startEveChildSpan(turn.span, {
34163
+ event: {
34164
+ id: eventId,
34165
+ metadata
34166
+ },
34167
+ name: event.data.subagentName,
34168
+ spanAttributes: { type: "tool" /* TOOL */ },
34169
+ spanId,
34170
+ startTime: eventTime2(event)
34171
+ });
34172
+ span.log({ metadata });
34173
+ const state = {
34174
+ metadata,
34175
+ span,
34176
+ turnKey: turnKey2(sessionId, event.data.turnId)
34177
+ };
34178
+ this.toolsByCallKey.set(toolKey3(sessionId, event.data.callId), state);
34179
+ return state;
34180
+ }
34181
+ async startSyntheticSubagentResult(event, ctx, result, hookMetadata) {
34182
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34183
+ const sessionId = sessionIdFromContext(ctx);
34184
+ if (!turn || !sessionId) {
34185
+ return void 0;
34186
+ }
34187
+ const metadata = toolMetadataFromTurn(turn);
34188
+ const { rowId: eventId, spanId } = await generateEveIds(
34189
+ "subagent",
34190
+ sessionId,
34191
+ result.callId
34192
+ );
34193
+ const existing = this.toolsByCallKey.get(toolKey3(sessionId, result.callId));
34194
+ if (existing) {
34195
+ return existing;
34196
+ }
34197
+ const span = await this.startEveChildSpan(turn.span, {
34198
+ event: {
34199
+ id: eventId,
34200
+ metadata
34201
+ },
34202
+ name: result.subagentName,
34203
+ spanAttributes: { type: "tool" /* TOOL */ },
34204
+ spanId,
34205
+ startTime: eventTime2(event)
34206
+ });
34207
+ span.log({ metadata });
34208
+ const state = {
34209
+ metadata,
34210
+ span,
34211
+ turnKey: turnKey2(sessionId, event.data.turnId)
34212
+ };
34213
+ this.toolsByCallKey.set(toolKey3(sessionId, result.callId), state);
34214
+ return state;
34215
+ }
34216
+ async startTurnSpan(session, event, metadata) {
34217
+ const { rowId: eventId, spanId } = await generateEveIds(
34218
+ "turn",
34219
+ session.sessionId,
34220
+ event.data.turnId
34221
+ );
34222
+ return await this.startEveSpan({
34223
+ event: {
34224
+ id: eventId,
34225
+ metadata
34226
+ },
34227
+ name: "eve.turn",
34228
+ parentSpanIds: {
34229
+ rootSpanId: session.span.rootSpanId,
34230
+ spanId: session.span.spanId
34231
+ },
34232
+ spanAttributes: { type: "task" /* TASK */ },
34233
+ spanId,
34234
+ startTime: eventTime2(event)
34235
+ });
34236
+ }
34237
+ turnForEvent(event, ctx) {
34238
+ const sessionId = sessionIdFromContext(ctx);
34239
+ return sessionId ? this.turnsByKey.get(turnKey2(sessionId, event.data.turnId)) : void 0;
34240
+ }
34241
+ stepForEvent(event, ctx) {
34242
+ return this.turnForEvent(event, ctx)?.stepsByIndex.get(
34243
+ event.data.stepIndex
34244
+ );
34245
+ }
34246
+ finalizeTurn(turn, args) {
34247
+ const { endTime } = args;
34248
+ for (const step of turn.stepsByIndex.values()) {
34249
+ step.span.log({
34250
+ ...step.input !== void 0 ? { input: step.input } : {},
34251
+ metadata: step.metadata,
34252
+ metrics: step.metrics,
34253
+ output: step.output
34254
+ });
34255
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
34256
+ }
34257
+ turn.stepsByIndex.clear();
34258
+ for (const tool of this.toolsByCallKey.values()) {
34259
+ if (tool.turnKey !== turn.key) {
34260
+ continue;
34261
+ }
34262
+ if (tool.endedByTurn) {
34263
+ continue;
34264
+ }
34265
+ tool.span.log({ metadata: tool.metadata });
34266
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
34267
+ tool.endedByTurn = true;
34268
+ }
34269
+ if (args.error) {
34270
+ turn.span.log({ error: args.error });
34271
+ } else {
34272
+ turn.span.log({
34273
+ metadata: turn.metadata,
34274
+ metrics: turn.metrics,
34275
+ output: turn.output
34276
+ });
34277
+ }
34278
+ turn.span.end(endTime === void 0 ? void 0 : { endTime });
34279
+ this.turnsByKey.delete(turn.key);
34280
+ this.state.update((current) => {
34281
+ const normalized = normalizeEveTraceState(current);
34282
+ return {
34283
+ ...normalized,
34284
+ stepStarts: normalized.stepStarts.filter(
34285
+ (entry) => entry.turnId !== turn.turnId
34286
+ )
34287
+ };
34288
+ });
34289
+ }
34290
+ cleanupSession(sessionId) {
34291
+ const keyPrefix = `${sessionId}:`;
34292
+ this.sessionsById.delete(sessionId);
34293
+ for (const key of this.turnsByKey.keys()) {
34294
+ if (key.startsWith(keyPrefix)) {
34295
+ this.turnsByKey.delete(key);
34296
+ }
34297
+ }
34298
+ for (const key of this.toolsByCallKey.keys()) {
34299
+ if (key.startsWith(keyPrefix)) {
34300
+ this.toolsByCallKey.delete(key);
34301
+ }
34302
+ }
34303
+ for (const key of this.completedToolKeys.keys()) {
34304
+ if (key.startsWith(keyPrefix)) {
34305
+ this.completedToolKeys.delete(key);
34306
+ }
34307
+ }
34308
+ this.state.update(() => emptyEveTraceState());
34309
+ }
34310
+ async flushInstrumentation() {
34311
+ try {
34312
+ await flush();
34313
+ return true;
34314
+ } catch (error) {
34315
+ debugLogger.warn("Error in Eve flush instrumentation:", error);
34316
+ return false;
34317
+ }
34318
+ }
34319
+ };
34320
+ function emptyEveTraceState() {
34321
+ return {
34322
+ llmInputs: [],
34323
+ metadata: {},
34324
+ spanReferences: [],
34325
+ stepStarts: []
34326
+ };
34327
+ }
34328
+ function normalizeEveTraceState(state) {
34329
+ if (!isObject(state)) {
34330
+ return emptyEveTraceState();
34331
+ }
34332
+ const metadata = isObject(state["metadata"]) ? state["metadata"] : {};
34333
+ const spanReferences = Array.isArray(state["spanReferences"]) ? state["spanReferences"].flatMap((entry) => {
34334
+ if (!isObject(entry)) {
34335
+ return [];
34336
+ }
34337
+ const exported = entry["exported"];
34338
+ const endTime = entry["endTime"];
34339
+ const rootSpanId = entry["rootSpanId"];
34340
+ const rowId = entry["rowId"];
34341
+ const spanId = entry["spanId"];
34342
+ const startEvent = entry["startEvent"];
34343
+ const startEventCreated = isObject(startEvent) ? startEvent["created"] : void 0;
34344
+ const startEventMetrics = isObject(startEvent) ? startEvent["metrics"] : void 0;
34345
+ const startEventSpanAttributes = isObject(startEvent) ? startEvent["span_attributes"] : void 0;
34346
+ const startEventSpanParents = isObject(startEvent) ? startEvent["span_parents"] : void 0;
34347
+ const normalizedStartEvent = typeof startEventCreated === "string" && isObject(startEventMetrics) && typeof startEventMetrics["start"] === "number" && Number.isFinite(startEventMetrics["start"]) && isObject(startEventSpanAttributes) && Array.isArray(startEventSpanParents) && startEventSpanParents.every(
34348
+ (parent) => typeof parent === "string"
34349
+ ) ? {
34350
+ created: startEventCreated,
34351
+ metrics: { start: startEventMetrics["start"] },
34352
+ span_attributes: { ...startEventSpanAttributes },
34353
+ span_parents: [...startEventSpanParents]
34354
+ } : void 0;
34355
+ return typeof exported === "string" && typeof rootSpanId === "string" && typeof rowId === "string" && typeof spanId === "string" ? [
34356
+ {
34357
+ ...typeof endTime === "number" && Number.isFinite(endTime) ? { endTime } : {},
34358
+ exported,
34359
+ rootSpanId,
34360
+ rowId,
34361
+ spanId,
34362
+ ...normalizedStartEvent ? { startEvent: normalizedStartEvent } : {}
34363
+ }
34364
+ ] : [];
34365
+ }).slice(-MAX_STORED_SPAN_REFERENCES) : [];
34366
+ const llmInputs = Array.isArray(state["llmInputs"]) ? state["llmInputs"].flatMap((entry) => {
34367
+ if (!isObject(entry)) {
34368
+ return [];
34369
+ }
34370
+ const key = entry["key"];
34371
+ const input = entry["input"];
34372
+ return typeof key === "string" && isCapturedModelInput(input) ? [{ input, key }] : [];
34373
+ }).slice(-MAX_STORED_LLM_INPUTS) : [];
34374
+ const stepStarts = Array.isArray(state["stepStarts"]) ? state["stepStarts"].flatMap((entry) => {
34375
+ if (!isObject(entry)) {
34376
+ return [];
34377
+ }
34378
+ const ordinal = entry["ordinal"];
34379
+ const open = entry["open"];
34380
+ const stepIndex = entry["stepIndex"];
34381
+ const turnId = entry["turnId"];
34382
+ return typeof ordinal === "number" && Number.isInteger(ordinal) && ordinal >= 0 && typeof open === "boolean" && typeof stepIndex === "number" && Number.isInteger(stepIndex) && typeof turnId === "string" ? [{ open, ordinal, stepIndex, turnId }] : [];
34383
+ }).slice(-MAX_STORED_STEP_STARTS) : [];
34384
+ return { llmInputs, metadata: { ...metadata }, spanReferences, stepStarts };
34385
+ }
34386
+ function readEveTraceState(state) {
34387
+ try {
34388
+ return normalizeEveTraceState(state.get());
34389
+ } catch {
34390
+ return emptyEveTraceState();
34391
+ }
34392
+ }
34393
+ function captureEveModelInput(state, input) {
34394
+ if (!isObject(input)) {
34395
+ return;
34396
+ }
34397
+ const session = input["session"];
34398
+ const turn = input["turn"];
34399
+ const step = input["step"];
34400
+ if (!isObject(session) || !isObject(turn) || !isObject(step)) {
34401
+ return;
34402
+ }
34403
+ const sessionId = session["id"];
34404
+ const turnId = turn["id"];
34405
+ const stepIndex = step["index"];
34406
+ if (typeof sessionId !== "string" || typeof turnId !== "string" || typeof stepIndex !== "number" || !Number.isInteger(stepIndex)) {
34407
+ return;
34408
+ }
34409
+ const captured = capturedModelInput(input["modelInput"]);
34410
+ if (!captured) {
34411
+ return;
34412
+ }
34413
+ const key = llmInputKey(sessionId, turnId, stepIndex);
34414
+ state.update((current) => {
34415
+ const normalized = normalizeEveTraceState(current);
34416
+ const llmInputs = [...normalized.llmInputs, { input: captured, key }];
34417
+ return {
34418
+ ...normalized,
34419
+ llmInputs: llmInputs.slice(-MAX_STORED_LLM_INPUTS)
34420
+ };
34421
+ });
34422
+ }
34423
+ function consumeCapturedEveModelInput(state, sessionId, turnId, stepIndex) {
34424
+ try {
34425
+ const key = llmInputKey(sessionId, turnId, stepIndex);
34426
+ let input;
34427
+ state.update((current) => {
34428
+ const normalized = normalizeEveTraceState(current);
34429
+ const index = normalized.llmInputs.findIndex(
34430
+ (candidate) => candidate.key === key
34431
+ );
34432
+ if (index < 0) {
34433
+ return normalized;
34434
+ }
34435
+ input = normalized.llmInputs[index]?.input;
34436
+ return {
34437
+ ...normalized,
34438
+ llmInputs: normalized.llmInputs.filter(
34439
+ (_, candidateIndex) => candidateIndex !== index
34440
+ )
34441
+ };
34442
+ });
34443
+ return input;
34444
+ } catch (error) {
34445
+ debugLogger.warn("Error in Eve LLM input consumption:", error);
34446
+ return void 0;
34447
+ }
34448
+ }
34449
+ function capturedModelInput(modelInput) {
34450
+ if (!isObject(modelInput)) {
34451
+ return void 0;
34452
+ }
34453
+ const messages = modelInput["messages"];
34454
+ if (!Array.isArray(messages)) {
34455
+ return void 0;
34456
+ }
34457
+ const instructions = modelInput["instructions"];
34458
+ const value = [
34459
+ ...instructions !== void 0 ? [{ content: instructions, role: "system" }] : [],
34460
+ ...messages
34461
+ ];
34462
+ try {
34463
+ const cloned = JSON.parse(JSON.stringify(value));
34464
+ if (!Array.isArray(cloned)) {
34465
+ return void 0;
34466
+ }
34467
+ return cloned;
34468
+ } catch {
34469
+ return void 0;
34470
+ }
34471
+ }
34472
+ function isCapturedModelInput(input) {
34473
+ return Array.isArray(input);
34474
+ }
34475
+ function llmInputKey(sessionId, turnId, stepIndex) {
34476
+ return `${sessionId}\0${turnId}\0${stepIndex}`;
34477
+ }
34478
+ function modelMetadataFromRuntime(runtime) {
34479
+ if (!isObject(runtime)) {
34480
+ return {};
34481
+ }
34482
+ const modelId = runtime["modelId"];
34483
+ return typeof modelId === "string" ? modelMetadataFromModelId(modelId) : {};
34484
+ }
34485
+ function modelMetadataFromModelId(modelId) {
34486
+ const normalized = modelId.trim();
34487
+ if (!normalized) {
34488
+ return {};
34489
+ }
34490
+ const slashIndex = normalized.indexOf("/");
34491
+ if (slashIndex > 0 && slashIndex < normalized.length - 1) {
34492
+ return {
34493
+ model: normalized.slice(slashIndex + 1),
34494
+ provider: normalized.slice(0, slashIndex)
34495
+ };
34496
+ }
34497
+ return {
34498
+ model: normalized
34499
+ };
34500
+ }
34501
+ function sessionIdFromContext(ctx) {
34502
+ if (!isObject(ctx)) {
34503
+ return void 0;
34504
+ }
34505
+ const session = ctx["session"];
34506
+ if (!isObject(session)) {
34507
+ return void 0;
34508
+ }
34509
+ const id = session["id"];
34510
+ return typeof id === "string" ? id : void 0;
34511
+ }
34512
+ function toolMetadataFromTurn(turn) {
34513
+ const { model: _model, provider: _provider, ...metadata } = turn.metadata;
34514
+ return metadata;
34515
+ }
34516
+ function parentLineageFromContext(ctx) {
34517
+ if (!isObject(ctx)) {
34518
+ return void 0;
34519
+ }
34520
+ const session = ctx.session;
34521
+ if (!isObject(session)) {
34522
+ return void 0;
34523
+ }
34524
+ const parent = session["parent"];
34525
+ if (!isObject(parent)) {
34526
+ return void 0;
34527
+ }
34528
+ const callId = parent["callId"];
34529
+ const rootSessionId = parent["rootSessionId"];
34530
+ const sessionId = parent["sessionId"];
34531
+ if (typeof callId !== "string" || typeof rootSessionId !== "string" || typeof sessionId !== "string") {
34532
+ return void 0;
34533
+ }
34534
+ return { callId, rootSessionId, sessionId };
34535
+ }
34536
+ function isToolCallAction(action) {
34537
+ return isObject(action) && action["kind"] === "tool-call" && typeof action["callId"] === "string" && typeof action["toolName"] === "string" && isObject(action["input"]);
34538
+ }
34539
+ function isLocalSubagentCallAction(action) {
34540
+ return isObject(action) && action["kind"] === "subagent-call" && typeof action["callId"] === "string" && isObject(action["input"]);
34541
+ }
34542
+ function isTraceableActionRequest(action) {
34543
+ return isToolCallAction(action) || isLocalSubagentCallAction(action);
34544
+ }
34545
+ function isToolResult(result) {
34546
+ return isObject(result) && result["kind"] === "tool-result" && typeof result["callId"] === "string" && typeof result["toolName"] === "string";
34547
+ }
34548
+ function isSubagentResult(result) {
34549
+ return isObject(result) && result["kind"] === "subagent-result" && typeof result["callId"] === "string" && typeof result["subagentName"] === "string";
34550
+ }
34551
+ function normalizedFinishReason(finishReason) {
34552
+ switch (finishReason) {
34553
+ case "content-filter":
34554
+ return "content_filter";
34555
+ case "tool-calls":
34556
+ return "tool_calls";
34557
+ default:
34558
+ return finishReason;
34559
+ }
34560
+ }
34561
+ function errorFromMessage(message, code, details) {
34562
+ const error = new Error(`${code}: ${message}`);
34563
+ if (details !== void 0) {
34564
+ error.cause = details;
34565
+ }
34566
+ return error;
34567
+ }
34568
+ function actionResultError(error, output) {
34569
+ if (error) {
34570
+ return errorFromMessage(error.message, error.code);
34571
+ }
34572
+ const result = new Error("Eve action failed");
34573
+ if (output !== void 0) {
34574
+ result.cause = output;
34575
+ }
34576
+ return result;
34577
+ }
34578
+ function eventTime2(event) {
34579
+ if (!event.meta?.at) {
34580
+ return void 0;
34581
+ }
34582
+ const timestamp = Date.parse(event.meta.at);
34583
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
34584
+ }
34585
+ function turnKey2(sessionId, turnId) {
34586
+ return `${sessionId}:${turnId}`;
34587
+ }
34588
+ function toolKey3(sessionId, callId) {
34589
+ return `${sessionId}:${callId}`;
34590
+ }
34591
+ async function rootSpanIdForSession(sessionId) {
34592
+ return deterministicEveId("eve:root", sessionId);
34593
+ }
34594
+ async function generateEveIds(kind, ...parts) {
34595
+ const [rowId, spanId] = await Promise.all([
34596
+ deterministicEveId(`eve:row:${kind}`, ...parts),
34597
+ deterministicEveId(`eve:${kind}`, ...parts)
34598
+ ]);
34599
+ return { rowId, spanId };
34600
+ }
34601
+ async function spanIdForSubagent(sessionId, callId) {
34602
+ return deterministicEveId("eve:subagent", sessionId, callId);
34603
+ }
34604
+ async function deterministicEveId(...parts) {
34605
+ const data = new TextEncoder().encode(
34606
+ parts.map((part) => `${part.length}:${part}`).join("\0")
34607
+ );
34608
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", data);
34609
+ const bytes = Array.from(new Uint8Array(digest, 0, 16));
34610
+ const hex = bytes.map((byte) => byte.toString(16).padStart(2, "0")).join("");
34611
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
34612
+ }
34613
+
33083
34614
  // src/typed-instrumentation-helpers.ts
33084
34615
  var TypedApplyProxy = Proxy;
33085
34616
 
@@ -33311,7 +34842,13 @@ var BraintrustObservabilityExporter = class {
33311
34842
  const args = {
33312
34843
  name: exported.name,
33313
34844
  spanAttributes: { type: spanTypeFor(exported.type) },
33314
- startTime: epochSeconds(exported.startTime)
34845
+ startTime: epochSeconds(exported.startTime),
34846
+ // Use the Mastra span id as the Braintrust row id so that
34847
+ // `logFeedback({ id: <mastra span id> })` (and Mastra's score events)
34848
+ // attach to the right row. Without this, `SpanImpl` auto-generates a
34849
+ // row id (`this._id = eventId ?? idGenerator.getSpanId()`) that no
34850
+ // external caller could know.
34851
+ event: { id: exported.id }
33315
34852
  };
33316
34853
  const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
33317
34854
  if (!this.capturedParent) {