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.mjs CHANGED
@@ -2191,19 +2191,30 @@ var CallEvent = z6.union([
2191
2191
  var ChatCompletionContentPartTextWithTitle = z6.object({
2192
2192
  text: z6.string().default(""),
2193
2193
  type: z6.literal("text"),
2194
- cache_control: z6.object({ type: z6.literal("ephemeral") }).optional()
2194
+ cache_control: z6.object({
2195
+ type: z6.literal("ephemeral"),
2196
+ ttl: z6.enum(["5m", "1h"]).optional()
2197
+ }).optional()
2195
2198
  });
2196
2199
  var ChatCompletionContentPartImageWithTitle = z6.object({
2197
2200
  image_url: z6.object({
2198
2201
  url: z6.string(),
2199
2202
  detail: z6.union([z6.literal("auto"), z6.literal("low"), z6.literal("high")]).optional()
2200
2203
  }),
2201
- type: z6.literal("image_url")
2204
+ type: z6.literal("image_url"),
2205
+ cache_control: z6.object({
2206
+ type: z6.literal("ephemeral"),
2207
+ ttl: z6.enum(["5m", "1h"]).optional()
2208
+ }).optional()
2202
2209
  });
2203
2210
  var ChatCompletionContentPartFileFile = z6.object({ file_data: z6.string(), filename: z6.string(), file_id: z6.string() }).partial();
2204
2211
  var ChatCompletionContentPartFileWithTitle = z6.object({
2205
2212
  file: ChatCompletionContentPartFileFile,
2206
- type: z6.literal("file")
2213
+ type: z6.literal("file"),
2214
+ cache_control: z6.object({
2215
+ type: z6.literal("ephemeral"),
2216
+ ttl: z6.enum(["5m", "1h"]).optional()
2217
+ }).optional()
2207
2218
  });
2208
2219
  var ChatCompletionContentPart = z6.union([
2209
2220
  ChatCompletionContentPartTextWithTitle,
@@ -2213,7 +2224,10 @@ var ChatCompletionContentPart = z6.union([
2213
2224
  var ChatCompletionContentPartText = z6.object({
2214
2225
  text: z6.string().default(""),
2215
2226
  type: z6.literal("text"),
2216
- cache_control: z6.object({ type: z6.literal("ephemeral") }).optional()
2227
+ cache_control: z6.object({
2228
+ type: z6.literal("ephemeral"),
2229
+ ttl: z6.enum(["5m", "1h"]).optional()
2230
+ }).optional()
2217
2231
  });
2218
2232
  var ChatCompletionMessageToolCall = z6.object({
2219
2233
  id: z6.string(),
@@ -4266,13 +4280,23 @@ var LRUCache = class {
4266
4280
  * @returns The cached value if found, undefined otherwise.
4267
4281
  */
4268
4282
  get(key) {
4269
- const value = this.cache.get(key);
4270
- if (value === void 0) {
4283
+ const entry = this.cache.get(key);
4284
+ if (entry === void 0) {
4271
4285
  return void 0;
4272
4286
  }
4273
4287
  this.cache.delete(key);
4274
- this.cache.set(key, value);
4275
- return value;
4288
+ this.cache.set(key, entry);
4289
+ return entry.value;
4290
+ }
4291
+ /**
4292
+ * Checks whether a key exists and marks it as most recently used.
4293
+ */
4294
+ has(key) {
4295
+ if (!this.cache.has(key)) {
4296
+ return false;
4297
+ }
4298
+ this.get(key);
4299
+ return true;
4276
4300
  }
4277
4301
  /**
4278
4302
  * Stores a value in the cache.
@@ -4289,7 +4313,38 @@ var LRUCache = class {
4289
4313
  const first = this.cache.keys().next().value;
4290
4314
  this.cache.delete(first);
4291
4315
  }
4292
- this.cache.set(key, value);
4316
+ this.cache.set(key, { value });
4317
+ }
4318
+ /**
4319
+ * Removes an item from the cache.
4320
+ */
4321
+ delete(key) {
4322
+ return this.cache.delete(key);
4323
+ }
4324
+ /**
4325
+ * Iterates over cache entries from least to most recently used.
4326
+ */
4327
+ *entries() {
4328
+ for (const [key, entry] of this.cache) {
4329
+ yield [key, entry.value];
4330
+ }
4331
+ }
4332
+ /**
4333
+ * Iterates over cache keys from least to most recently used.
4334
+ */
4335
+ keys() {
4336
+ return this.cache.keys();
4337
+ }
4338
+ /**
4339
+ * Iterates over cache values from least to most recently used.
4340
+ */
4341
+ *values() {
4342
+ for (const entry of this.cache.values()) {
4343
+ yield entry.value;
4344
+ }
4345
+ }
4346
+ [Symbol.iterator]() {
4347
+ return this.entries();
4293
4348
  }
4294
4349
  /**
4295
4350
  * Removes all items from the cache.
@@ -4847,6 +4902,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
4847
4902
  return `ERROR: Failed to mask field '${fieldName}' - ${errorType}`;
4848
4903
  }
4849
4904
  }
4905
+ var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
4906
+ "braintrust.initial-span-write-as-merge"
4907
+ );
4850
4908
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
4851
4909
  "braintrust.currentSpanStore"
4852
4910
  );
@@ -8497,6 +8555,12 @@ var traceable = wrapTraced;
8497
8555
  function startSpan(args) {
8498
8556
  return startSpanAndIsLogger(args).span;
8499
8557
  }
8558
+ function _internalStartSpanWithInitialMerge(args) {
8559
+ return startSpanAndIsLogger({
8560
+ ...args,
8561
+ [INITIAL_SPAN_WRITE_AS_MERGE]: true
8562
+ }).span;
8563
+ }
8500
8564
  async function flush(options) {
8501
8565
  const state = options?.state ?? _globalState;
8502
8566
  return await state.bgLogger().flush();
@@ -9407,7 +9471,7 @@ var SpanImpl = class _SpanImpl {
9407
9471
  this._spanId = resolvedIds.spanId;
9408
9472
  this._rootSpanId = resolvedIds.rootSpanId;
9409
9473
  this._spanParents = resolvedIds.spanParents;
9410
- this.isMerge = false;
9474
+ this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
9411
9475
  this.logInternal({ event, internalData });
9412
9476
  this.isMerge = true;
9413
9477
  }
@@ -31389,6 +31453,8 @@ __export(exports_exports, {
31389
31453
  addAzureBlobHeaders: () => addAzureBlobHeaders,
31390
31454
  agentAssertionScorer: () => agentAssertionScorer,
31391
31455
  braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
31456
+ braintrustEveHook: () => braintrustEveHook,
31457
+ braintrustEveInstrumentation: () => braintrustEveInstrumentation,
31392
31458
  braintrustFlueInstrumentation: () => braintrustFlueInstrumentation,
31393
31459
  braintrustFlueObserver: () => braintrustFlueObserver,
31394
31460
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
@@ -32889,6 +32955,1469 @@ function BraintrustMiddleware(config = {}) {
32889
32955
  };
32890
32956
  }
32891
32957
 
32958
+ // src/instrumentation/plugins/eve-plugin.ts
32959
+ var EVE_TRACE_STATE_KEY = "braintrust.eve.tracing";
32960
+ var MAX_EVE_CACHE_ENTRIES = 1e4;
32961
+ var MAX_STORED_LLM_INPUTS = 100;
32962
+ var MAX_STORED_SPAN_REFERENCES = 1e4;
32963
+ var MAX_STORED_STEP_STARTS = 1e4;
32964
+ function braintrustEveHook(options) {
32965
+ const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
32966
+ const bridge = new EveBridge(state);
32967
+ return {
32968
+ events: {
32969
+ "*": async (event, ctx) => {
32970
+ await bridge.handle(event, ctx, options.metadata);
32971
+ }
32972
+ }
32973
+ };
32974
+ }
32975
+ function braintrustEveInstrumentation(options) {
32976
+ const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
32977
+ return {
32978
+ events: {
32979
+ "step.started": (input) => {
32980
+ try {
32981
+ captureEveModelInput(state, input);
32982
+ } catch (error) {
32983
+ debugLogger.warn("Error in Eve LLM input capture:", error);
32984
+ }
32985
+ }
32986
+ },
32987
+ recordInputs: false,
32988
+ recordOutputs: false,
32989
+ setup: options.setup
32990
+ };
32991
+ }
32992
+ function isEveHandleMessageStreamEvent(event) {
32993
+ return isObject(event) && typeof event["type"] === "string";
32994
+ }
32995
+ var ResumedEveSpan = class {
32996
+ constructor(reference) {
32997
+ this.reference = reference;
32998
+ this.endTime = reference.endTime;
32999
+ }
33000
+ endTime;
33001
+ get rootSpanId() {
33002
+ return this.reference.rootSpanId;
33003
+ }
33004
+ get spanId() {
33005
+ return this.reference.spanId;
33006
+ }
33007
+ log(event) {
33008
+ const metrics = {
33009
+ ...this.reference.startEvent?.metrics,
33010
+ ...this.endTime === void 0 ? {} : { end: this.endTime },
33011
+ ...event.metrics
33012
+ };
33013
+ updateSpan({
33014
+ exported: this.reference.exported,
33015
+ ...this.reference.startEvent,
33016
+ ...event,
33017
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
33018
+ });
33019
+ }
33020
+ end(args) {
33021
+ if (this.endTime === void 0) {
33022
+ this.endTime = args?.endTime ?? getCurrentUnixTimestamp();
33023
+ this.log({ metrics: { end: this.endTime } });
33024
+ }
33025
+ return this.endTime;
33026
+ }
33027
+ };
33028
+ var EveBridge = class {
33029
+ constructor(state) {
33030
+ this.state = state;
33031
+ }
33032
+ eventQueuesBySession = /* @__PURE__ */ new Map();
33033
+ sessionsById = new LRUCache({
33034
+ max: MAX_EVE_CACHE_ENTRIES
33035
+ });
33036
+ completedToolKeys = new LRUCache({
33037
+ max: MAX_EVE_CACHE_ENTRIES
33038
+ });
33039
+ toolsByCallKey = new LRUCache({
33040
+ max: MAX_EVE_CACHE_ENTRIES
33041
+ });
33042
+ turnsByKey = new LRUCache({
33043
+ max: MAX_EVE_CACHE_ENTRIES
33044
+ });
33045
+ async startEveSpan(args) {
33046
+ const rowId = args?.event?.id;
33047
+ const reference = typeof rowId === "string" && readEveTraceState(this.state).spanReferences.find(
33048
+ (candidate) => candidate.rowId === rowId
33049
+ );
33050
+ if (reference) {
33051
+ return new ResumedEveSpan(reference);
33052
+ }
33053
+ const startTime = args?.startTime ?? getCurrentUnixTimestamp();
33054
+ const parentSpanIds = args?.parentSpanIds;
33055
+ const startEvent = {
33056
+ created: (/* @__PURE__ */ new Date()).toISOString(),
33057
+ metrics: { start: startTime },
33058
+ span_attributes: {
33059
+ ...args?.name ? { name: args.name } : {},
33060
+ ...args?.type ? { type: args.type } : {},
33061
+ ...args?.spanAttributes
33062
+ },
33063
+ span_parents: parentSpanIds ? "spanId" in parentSpanIds ? [parentSpanIds.spanId] : parentSpanIds.parentSpanIds : []
33064
+ };
33065
+ const span = withCurrent(
33066
+ NOOP_SPAN,
33067
+ () => _internalStartSpanWithInitialMerge({ ...args, startTime })
33068
+ );
33069
+ if (typeof rowId !== "string") {
33070
+ return span;
33071
+ }
33072
+ try {
33073
+ const exported = await span.export();
33074
+ const reference2 = {
33075
+ exported,
33076
+ rootSpanId: span.rootSpanId,
33077
+ rowId,
33078
+ spanId: span.spanId,
33079
+ startEvent
33080
+ };
33081
+ this.state.update((current) => {
33082
+ const normalized = normalizeEveTraceState(current);
33083
+ return normalized.spanReferences.some(
33084
+ (candidate) => candidate.rowId === rowId
33085
+ ) ? normalized : {
33086
+ ...normalized,
33087
+ spanReferences: [...normalized.spanReferences, reference2].slice(
33088
+ -MAX_STORED_SPAN_REFERENCES
33089
+ )
33090
+ };
33091
+ });
33092
+ } catch (error) {
33093
+ debugLogger.warn("Error exporting Eve span for resumption:", error);
33094
+ }
33095
+ return span;
33096
+ }
33097
+ async startEveChildSpan(parent, args) {
33098
+ return await this.startEveSpan({
33099
+ ...args,
33100
+ parentSpanIds: {
33101
+ rootSpanId: parent.rootSpanId,
33102
+ spanId: parent.spanId
33103
+ }
33104
+ });
33105
+ }
33106
+ stepOrdinal(event) {
33107
+ let ordinal = 0;
33108
+ this.state.update((current) => {
33109
+ const state = normalizeEveTraceState(current);
33110
+ const previous = state.stepStarts.filter(
33111
+ (entry) => entry.turnId === event.data.turnId && entry.stepIndex === event.data.stepIndex
33112
+ ).at(-1);
33113
+ if (previous?.open) {
33114
+ ordinal = previous.ordinal;
33115
+ return state;
33116
+ }
33117
+ ordinal = state.stepStarts.filter(
33118
+ (entry) => entry.turnId === event.data.turnId
33119
+ ).length;
33120
+ return {
33121
+ ...state,
33122
+ stepStarts: [
33123
+ ...state.stepStarts,
33124
+ {
33125
+ open: true,
33126
+ ordinal,
33127
+ stepIndex: event.data.stepIndex,
33128
+ turnId: event.data.turnId
33129
+ }
33130
+ ].slice(-MAX_STORED_STEP_STARTS)
33131
+ };
33132
+ });
33133
+ return ordinal;
33134
+ }
33135
+ markStepEnded(turnId, stepIndex) {
33136
+ this.state.update((current) => {
33137
+ const state = normalizeEveTraceState(current);
33138
+ let index = -1;
33139
+ for (let i = state.stepStarts.length - 1; i >= 0; i--) {
33140
+ const entry = state.stepStarts[i];
33141
+ if (entry?.turnId === turnId && entry.stepIndex === stepIndex) {
33142
+ index = i;
33143
+ break;
33144
+ }
33145
+ }
33146
+ if (index < 0 || !state.stepStarts[index]?.open) {
33147
+ return state;
33148
+ }
33149
+ return {
33150
+ ...state,
33151
+ stepStarts: state.stepStarts.map(
33152
+ (entry, entryIndex) => entryIndex === index ? { ...entry, open: false } : entry
33153
+ )
33154
+ };
33155
+ });
33156
+ }
33157
+ async handle(event, ctx, hookMetadata) {
33158
+ if (!isEveHandleMessageStreamEvent(event)) {
33159
+ return;
33160
+ }
33161
+ const run = async () => {
33162
+ try {
33163
+ if (!await this.handleEvent(event, ctx, hookMetadata)) {
33164
+ return;
33165
+ }
33166
+ if (event.type === "session.failed") {
33167
+ const sessionId2 = event.data.sessionId || sessionIdFromContext(ctx);
33168
+ await this.flushInstrumentation();
33169
+ if (sessionId2) {
33170
+ this.cleanupSession(sessionId2);
33171
+ }
33172
+ } else if (event.type === "session.completed") {
33173
+ const sessionId2 = sessionIdFromContext(ctx);
33174
+ await this.flushInstrumentation();
33175
+ if (sessionId2) {
33176
+ this.cleanupSession(sessionId2);
33177
+ }
33178
+ }
33179
+ } catch (error) {
33180
+ debugLogger.warn("Error in Eve hook instrumentation:", error);
33181
+ }
33182
+ };
33183
+ const sessionId = event.type === "session.failed" ? event.data.sessionId || sessionIdFromContext(ctx) : sessionIdFromContext(ctx);
33184
+ if (!sessionId) {
33185
+ await run();
33186
+ return;
33187
+ }
33188
+ const previous = this.eventQueuesBySession.get(sessionId);
33189
+ const queued = previous ? previous.then(run) : run();
33190
+ this.eventQueuesBySession.set(sessionId, queued);
33191
+ try {
33192
+ await queued;
33193
+ } finally {
33194
+ if (this.eventQueuesBySession.get(sessionId) === queued) {
33195
+ this.eventQueuesBySession.delete(sessionId);
33196
+ }
33197
+ }
33198
+ }
33199
+ async handleEvent(event, ctx, hookMetadata) {
33200
+ switch (event.type) {
33201
+ case "session.started":
33202
+ await this.handleSessionStarted(event, ctx, hookMetadata);
33203
+ return true;
33204
+ case "turn.started":
33205
+ await this.handleTurnStarted(event, ctx, hookMetadata);
33206
+ return true;
33207
+ case "message.received":
33208
+ await this.handleMessageReceived(event, ctx, hookMetadata);
33209
+ return true;
33210
+ case "step.started":
33211
+ await this.handleStepStarted(event, ctx, hookMetadata);
33212
+ return true;
33213
+ case "message.completed":
33214
+ this.handleMessageCompleted(event, ctx);
33215
+ return true;
33216
+ case "result.completed":
33217
+ this.handleResultCompleted(event, ctx);
33218
+ return true;
33219
+ case "actions.requested":
33220
+ await this.handleActionsRequested(event, ctx, hookMetadata);
33221
+ return true;
33222
+ case "action.result":
33223
+ await this.handleActionResult(event, ctx, hookMetadata);
33224
+ return true;
33225
+ case "subagent.called":
33226
+ await this.handleSubagentCalled(event, ctx, hookMetadata);
33227
+ return true;
33228
+ case "subagent.completed":
33229
+ await this.handleSubagentCompleted(event, ctx, hookMetadata);
33230
+ return true;
33231
+ case "step.completed":
33232
+ this.handleStepCompleted(event, ctx);
33233
+ return true;
33234
+ case "step.failed":
33235
+ this.handleStepFailed(event, ctx);
33236
+ return true;
33237
+ case "turn.completed":
33238
+ await this.handleTurnCompleted(event, ctx);
33239
+ return true;
33240
+ case "turn.failed":
33241
+ await this.handleTurnFailed(event, ctx);
33242
+ return true;
33243
+ case "session.failed":
33244
+ await this.handleSessionFailed(event, ctx);
33245
+ return true;
33246
+ case "session.completed":
33247
+ await this.handleSessionCompleted(event, ctx);
33248
+ return true;
33249
+ default:
33250
+ return false;
33251
+ }
33252
+ }
33253
+ async handleSessionStarted(event, ctx, hookMetadata) {
33254
+ const sessionId = sessionIdFromContext(ctx);
33255
+ if (!sessionId) {
33256
+ return;
33257
+ }
33258
+ const metadata = {
33259
+ ...hookMetadata ?? {},
33260
+ ...modelMetadataFromRuntime(event.data.runtime)
33261
+ };
33262
+ this.state.update((current) => {
33263
+ const normalized = normalizeEveTraceState(current);
33264
+ return {
33265
+ ...normalized,
33266
+ metadata: { ...normalized.metadata, ...metadata }
33267
+ };
33268
+ });
33269
+ await this.ensureSession(sessionId, ctx, metadata, eventTime2(event));
33270
+ for (const [key, turn] of this.turnsByKey) {
33271
+ if (!key.startsWith(`${sessionId}:`)) {
33272
+ continue;
33273
+ }
33274
+ turn.metadata = { ...turn.metadata, ...metadata };
33275
+ turn.span.log({ metadata: turn.metadata });
33276
+ for (const step of turn.stepsByIndex.values()) {
33277
+ step.metadata = { ...step.metadata, ...metadata };
33278
+ step.span.log({ metadata: step.metadata });
33279
+ }
33280
+ }
33281
+ }
33282
+ async handleTurnStarted(event, ctx, hookMetadata) {
33283
+ const sessionId = sessionIdFromContext(ctx);
33284
+ if (!sessionId) {
33285
+ return;
33286
+ }
33287
+ const session = await this.ensureSession(
33288
+ sessionId,
33289
+ ctx,
33290
+ hookMetadata ?? {},
33291
+ eventTime2(event)
33292
+ );
33293
+ const key = turnKey2(sessionId, event.data.turnId);
33294
+ const metadata = { ...session.metadata };
33295
+ const existing = this.turnsByKey.get(key);
33296
+ if (existing) {
33297
+ existing.metadata = { ...existing.metadata, ...metadata };
33298
+ existing.span.log({ metadata: existing.metadata });
33299
+ return;
33300
+ }
33301
+ const span = await this.startTurnSpan(session, event, metadata);
33302
+ span.log({ metadata });
33303
+ this.turnsByKey.set(key, {
33304
+ key,
33305
+ metadata,
33306
+ metrics: {},
33307
+ span,
33308
+ stepsByIndex: /* @__PURE__ */ new Map(),
33309
+ turnId: event.data.turnId
33310
+ });
33311
+ }
33312
+ async handleMessageReceived(event, ctx, hookMetadata) {
33313
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33314
+ if (!turn) {
33315
+ return;
33316
+ }
33317
+ const input = [{ content: event.data.message, role: "user" }];
33318
+ turn.span.log({ input });
33319
+ }
33320
+ async handleStepStarted(event, ctx, hookMetadata) {
33321
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33322
+ const sessionId = sessionIdFromContext(ctx);
33323
+ if (!turn || !sessionId) {
33324
+ return;
33325
+ }
33326
+ const existing = turn.stepsByIndex.get(event.data.stepIndex);
33327
+ if (existing) {
33328
+ existing.span.log({
33329
+ ...existing.input !== void 0 ? { input: existing.input } : {},
33330
+ metadata: existing.metadata,
33331
+ metrics: existing.metrics,
33332
+ output: existing.output
33333
+ });
33334
+ const endTime = eventTime2(event);
33335
+ existing.span.end(endTime === void 0 ? void 0 : { endTime });
33336
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
33337
+ }
33338
+ const stepOrdinal = this.stepOrdinal(event);
33339
+ const metadata = {
33340
+ ...turn.metadata,
33341
+ ...this.sessionsById.get(sessionId)?.metadata ?? {}
33342
+ };
33343
+ const input = consumeCapturedEveModelInput(
33344
+ this.state,
33345
+ sessionId,
33346
+ event.data.turnId,
33347
+ event.data.stepIndex
33348
+ );
33349
+ const { rowId: eventId, spanId } = await generateEveIds(
33350
+ "step",
33351
+ sessionId,
33352
+ event.data.turnId,
33353
+ String(stepOrdinal)
33354
+ );
33355
+ const span = await this.startEveChildSpan(turn.span, {
33356
+ event: {
33357
+ id: eventId,
33358
+ ...input !== void 0 ? { input } : {},
33359
+ metadata
33360
+ },
33361
+ name: "eve.step",
33362
+ spanAttributes: { type: "llm" /* LLM */ },
33363
+ spanId,
33364
+ startTime: eventTime2(event)
33365
+ });
33366
+ span.log({ ...input !== void 0 ? { input } : {}, metadata });
33367
+ turn.stepsByIndex.set(event.data.stepIndex, {
33368
+ ...input !== void 0 ? { input } : {},
33369
+ metadata,
33370
+ metrics: {},
33371
+ span
33372
+ });
33373
+ }
33374
+ handleMessageCompleted(event, ctx) {
33375
+ const step = this.stepForEvent(event, ctx);
33376
+ if (!step) {
33377
+ return;
33378
+ }
33379
+ const existingMessage = Array.isArray(step.output) && isObject(step.output[0]) ? step.output[0].message : void 0;
33380
+ const existingToolCalls = isObject(existingMessage) ? existingMessage.tool_calls : void 0;
33381
+ step.output = [
33382
+ {
33383
+ finish_reason: normalizedFinishReason(event.data.finishReason),
33384
+ index: 0,
33385
+ message: {
33386
+ content: event.data.message,
33387
+ role: "assistant",
33388
+ ...Array.isArray(existingToolCalls) ? { tool_calls: existingToolCalls } : {}
33389
+ }
33390
+ }
33391
+ ];
33392
+ const turn = this.turnForEvent(event, ctx);
33393
+ if (turn && event.data.finishReason !== "tool-calls") {
33394
+ turn.output = event.data.message;
33395
+ }
33396
+ }
33397
+ handleResultCompleted(event, ctx) {
33398
+ const step = this.stepForEvent(event, ctx);
33399
+ if (step) {
33400
+ step.output = [
33401
+ {
33402
+ finish_reason: "stop",
33403
+ index: 0,
33404
+ message: {
33405
+ content: event.data.result,
33406
+ role: "assistant"
33407
+ }
33408
+ }
33409
+ ];
33410
+ }
33411
+ const turn = this.turnForEvent(event, ctx);
33412
+ if (turn) {
33413
+ turn.output = event.data.result;
33414
+ }
33415
+ }
33416
+ async handleActionsRequested(event, ctx, hookMetadata) {
33417
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33418
+ const sessionId = sessionIdFromContext(ctx);
33419
+ if (!turn || !sessionId) {
33420
+ return;
33421
+ }
33422
+ const traceActions = event.data.actions.filter(isTraceableActionRequest);
33423
+ if (traceActions.length === 0) {
33424
+ return;
33425
+ }
33426
+ for (const action of traceActions) {
33427
+ if (isToolCallAction(action)) {
33428
+ await this.startRequestedTool(event, turn, sessionId, action);
33429
+ } else if (isLocalSubagentCallAction(action)) {
33430
+ await this.startRequestedSubagent(event, turn, sessionId, action);
33431
+ }
33432
+ }
33433
+ const step = turn.stepsByIndex.get(event.data.stepIndex);
33434
+ if (!step) {
33435
+ return;
33436
+ }
33437
+ step.output = [
33438
+ {
33439
+ finish_reason: "tool_calls",
33440
+ index: 0,
33441
+ message: {
33442
+ content: null,
33443
+ role: "assistant",
33444
+ tool_calls: traceActions.map((action) => {
33445
+ const name = action.kind === "tool-call" ? action.toolName : action.subagentName ?? action.name ?? "agent";
33446
+ return {
33447
+ function: {
33448
+ arguments: JSON.stringify(action.input),
33449
+ name
33450
+ },
33451
+ id: action.callId,
33452
+ type: "function"
33453
+ };
33454
+ })
33455
+ }
33456
+ }
33457
+ ];
33458
+ step.span.log({ metadata: step.metadata, output: step.output });
33459
+ }
33460
+ async handleActionResult(event, ctx, hookMetadata) {
33461
+ if (isToolResult(event.data.result)) {
33462
+ await this.handleToolResult(event, ctx, event.data.result, hookMetadata);
33463
+ return;
33464
+ }
33465
+ if (isSubagentResult(event.data.result)) {
33466
+ await this.handleSubagentResult(
33467
+ event,
33468
+ ctx,
33469
+ event.data.result,
33470
+ hookMetadata
33471
+ );
33472
+ }
33473
+ }
33474
+ async handleToolResult(event, ctx, result, hookMetadata) {
33475
+ const sessionId = sessionIdFromContext(ctx);
33476
+ if (!sessionId) {
33477
+ return;
33478
+ }
33479
+ const key = toolKey3(sessionId, result.callId);
33480
+ if (this.completedToolKeys.has(key)) {
33481
+ return;
33482
+ }
33483
+ const tool = this.toolsByCallKey.get(key) ?? await this.startSyntheticTool(event, ctx, result, hookMetadata);
33484
+ if (!tool) {
33485
+ return;
33486
+ }
33487
+ const failed = event.data.status === "failed" || result.isError === true || event.data.error !== void 0;
33488
+ tool.span.log({
33489
+ ...failed ? {
33490
+ error: actionResultError(event.data.error, result.output)
33491
+ } : {},
33492
+ metadata: tool.metadata,
33493
+ output: result.output
33494
+ });
33495
+ const endTime = eventTime2(event);
33496
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
33497
+ this.toolsByCallKey.delete(key);
33498
+ this.completedToolKeys.set(key, true);
33499
+ }
33500
+ async handleSubagentCalled(event, ctx, hookMetadata) {
33501
+ if (event.data.remote?.url) {
33502
+ return;
33503
+ }
33504
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33505
+ const sessionId = sessionIdFromContext(ctx);
33506
+ if (!turn || !sessionId) {
33507
+ return;
33508
+ }
33509
+ const key = toolKey3(sessionId, event.data.callId);
33510
+ const metadata = toolMetadataFromTurn(turn);
33511
+ const existing = this.toolsByCallKey.get(key);
33512
+ if (existing) {
33513
+ existing.metadata = { ...existing.metadata, ...metadata };
33514
+ existing.span.log({ metadata: existing.metadata });
33515
+ return;
33516
+ }
33517
+ if (this.completedToolKeys.has(key)) {
33518
+ return;
33519
+ }
33520
+ const { rowId: eventId, spanId } = await generateEveIds(
33521
+ "subagent",
33522
+ sessionId,
33523
+ event.data.callId
33524
+ );
33525
+ const pending = this.toolsByCallKey.get(key);
33526
+ if (pending || this.completedToolKeys.has(key)) {
33527
+ if (pending) {
33528
+ pending.metadata = { ...pending.metadata, ...metadata };
33529
+ pending.span.log({ metadata: pending.metadata });
33530
+ }
33531
+ return;
33532
+ }
33533
+ const span = await this.startEveChildSpan(turn.span, {
33534
+ event: {
33535
+ id: eventId,
33536
+ metadata
33537
+ },
33538
+ name: event.data.toolName ?? event.data.name,
33539
+ spanAttributes: { type: "tool" /* TOOL */ },
33540
+ spanId,
33541
+ startTime: eventTime2(event)
33542
+ });
33543
+ span.log({ metadata });
33544
+ this.toolsByCallKey.set(key, {
33545
+ metadata,
33546
+ span,
33547
+ turnKey: turnKey2(sessionId, event.data.turnId)
33548
+ });
33549
+ }
33550
+ async handleSubagentCompleted(event, ctx, hookMetadata) {
33551
+ const sessionId = sessionIdFromContext(ctx);
33552
+ if (!sessionId) {
33553
+ return;
33554
+ }
33555
+ const key = toolKey3(sessionId, event.data.callId);
33556
+ if (this.completedToolKeys.has(key)) {
33557
+ return;
33558
+ }
33559
+ const subagent = this.toolsByCallKey.get(key) ?? await this.startSyntheticSubagent(event, ctx, hookMetadata);
33560
+ if (!subagent) {
33561
+ return;
33562
+ }
33563
+ subagent.span.log({
33564
+ ...event.data.status === "failed" ? {
33565
+ error: actionResultError(event.data.error, event.data.output)
33566
+ } : {},
33567
+ metadata: subagent.metadata,
33568
+ ...event.data.output !== void 0 ? { output: event.data.output } : {}
33569
+ });
33570
+ const endTime = eventTime2(event);
33571
+ const recordedEndTime = subagent.span.end(
33572
+ endTime === void 0 ? void 0 : { endTime }
33573
+ );
33574
+ this.state.update((current) => {
33575
+ const normalized = normalizeEveTraceState(current);
33576
+ return {
33577
+ ...normalized,
33578
+ spanReferences: normalized.spanReferences.map(
33579
+ (reference) => reference.spanId === subagent.span.spanId ? { ...reference, endTime: recordedEndTime } : reference
33580
+ )
33581
+ };
33582
+ });
33583
+ }
33584
+ async handleSubagentResult(event, ctx, result, hookMetadata) {
33585
+ const sessionId = sessionIdFromContext(ctx);
33586
+ if (!sessionId) {
33587
+ return;
33588
+ }
33589
+ const key = toolKey3(sessionId, result.callId);
33590
+ if (this.completedToolKeys.has(key)) {
33591
+ return;
33592
+ }
33593
+ const subagent = this.toolsByCallKey.get(key) ?? await this.startSyntheticSubagentResult(
33594
+ event,
33595
+ ctx,
33596
+ result,
33597
+ hookMetadata
33598
+ );
33599
+ if (!subagent) {
33600
+ return;
33601
+ }
33602
+ const isError = event.data.status === "failed" || result.isError === true || event.data.error !== void 0;
33603
+ subagent.span.log({
33604
+ ...isError ? {
33605
+ error: actionResultError(event.data.error, result.output)
33606
+ } : {},
33607
+ metadata: subagent.metadata,
33608
+ output: result.output
33609
+ });
33610
+ const endTime = eventTime2(event);
33611
+ subagent.span.end(endTime === void 0 ? void 0 : { endTime });
33612
+ this.toolsByCallKey.delete(key);
33613
+ this.completedToolKeys.set(key, true);
33614
+ }
33615
+ handleStepCompleted(event, ctx) {
33616
+ const step = this.stepForEvent(event, ctx);
33617
+ if (!step) {
33618
+ return;
33619
+ }
33620
+ const usage = event.data.usage;
33621
+ const inputTokens = typeof usage?.inputTokens === "number" && Number.isFinite(usage.inputTokens) && usage.inputTokens >= 0 ? usage.inputTokens : void 0;
33622
+ const outputTokens = typeof usage?.outputTokens === "number" && Number.isFinite(usage.outputTokens) && usage.outputTokens >= 0 ? usage.outputTokens : void 0;
33623
+ const cacheReadTokens = typeof usage?.cacheReadTokens === "number" && Number.isFinite(usage.cacheReadTokens) && usage.cacheReadTokens >= 0 ? usage.cacheReadTokens : void 0;
33624
+ const cacheWriteTokens = typeof usage?.cacheWriteTokens === "number" && Number.isFinite(usage.cacheWriteTokens) && usage.cacheWriteTokens >= 0 ? usage.cacheWriteTokens : void 0;
33625
+ const costUsd = typeof usage?.costUsd === "number" && Number.isFinite(usage.costUsd) && usage.costUsd >= 0 ? usage.costUsd : void 0;
33626
+ const total = inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0;
33627
+ const metrics = {
33628
+ ...inputTokens !== void 0 ? { prompt_tokens: inputTokens } : {},
33629
+ ...outputTokens !== void 0 ? { completion_tokens: outputTokens } : {},
33630
+ ...total !== void 0 ? { tokens: total } : {},
33631
+ ...cacheReadTokens !== void 0 ? { prompt_cached_tokens: cacheReadTokens } : {},
33632
+ ...cacheWriteTokens !== void 0 ? { prompt_cache_creation_tokens: cacheWriteTokens } : {},
33633
+ ...costUsd !== void 0 ? { estimated_cost: costUsd } : {}
33634
+ };
33635
+ step.metrics = { ...step.metrics, ...metrics };
33636
+ if (Array.isArray(step.output) && isObject(step.output[0])) {
33637
+ const finishReason = step.output[0].finish_reason;
33638
+ if (typeof finishReason !== "string") {
33639
+ step.output[0].finish_reason = normalizedFinishReason(
33640
+ event.data.finishReason
33641
+ );
33642
+ }
33643
+ }
33644
+ step.span.log({
33645
+ ...step.input !== void 0 ? { input: step.input } : {},
33646
+ metadata: step.metadata,
33647
+ metrics,
33648
+ output: step.output
33649
+ });
33650
+ const endTime = eventTime2(event);
33651
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
33652
+ const turn = this.turnForEvent(event, ctx);
33653
+ if (turn) {
33654
+ for (const [key, value] of Object.entries(metrics)) {
33655
+ turn.metrics[key] = (turn.metrics[key] ?? 0) + value;
33656
+ }
33657
+ turn.stepsByIndex.delete(event.data.stepIndex);
33658
+ }
33659
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
33660
+ }
33661
+ handleStepFailed(event, ctx) {
33662
+ const step = this.stepForEvent(event, ctx);
33663
+ if (step) {
33664
+ step.span.log({
33665
+ error: errorFromMessage(
33666
+ event.data.message,
33667
+ event.data.code,
33668
+ event.data.details
33669
+ )
33670
+ });
33671
+ const endTime = eventTime2(event);
33672
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
33673
+ }
33674
+ const turn = this.turnForEvent(event, ctx);
33675
+ turn?.stepsByIndex.delete(event.data.stepIndex);
33676
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
33677
+ }
33678
+ handleTurnCompleted(event, ctx) {
33679
+ const turn = this.turnForEvent(event, ctx);
33680
+ if (!turn) {
33681
+ return;
33682
+ }
33683
+ this.finalizeTurn(turn, {
33684
+ endTime: eventTime2(event)
33685
+ });
33686
+ }
33687
+ handleTurnFailed(event, ctx) {
33688
+ const turn = this.turnForEvent(event, ctx);
33689
+ if (!turn) {
33690
+ return;
33691
+ }
33692
+ this.finalizeTurn(turn, {
33693
+ endTime: eventTime2(event),
33694
+ error: errorFromMessage(
33695
+ event.data.message,
33696
+ event.data.code,
33697
+ event.data.details
33698
+ )
33699
+ });
33700
+ }
33701
+ async handleSessionFailed(event, ctx) {
33702
+ const sessionId = event.data.sessionId || sessionIdFromContext(ctx);
33703
+ if (!sessionId) {
33704
+ return;
33705
+ }
33706
+ const session = await this.ensureSession(
33707
+ sessionId,
33708
+ ctx,
33709
+ {},
33710
+ eventTime2(event)
33711
+ );
33712
+ const error = errorFromMessage(
33713
+ event.data.message,
33714
+ event.data.code,
33715
+ event.data.details
33716
+ );
33717
+ for (const [key, turn] of this.turnsByKey) {
33718
+ if (!key.startsWith(`${sessionId}:`)) {
33719
+ continue;
33720
+ }
33721
+ this.finalizeTurn(turn, {
33722
+ endTime: eventTime2(event),
33723
+ error
33724
+ });
33725
+ }
33726
+ for (const [key, tool] of this.toolsByCallKey) {
33727
+ if (key.startsWith(`${sessionId}:`)) {
33728
+ const endTime2 = eventTime2(event);
33729
+ if (!tool.endedByTurn) {
33730
+ tool.span.log({ metadata: tool.metadata });
33731
+ tool.span.end(endTime2 === void 0 ? void 0 : { endTime: endTime2 });
33732
+ tool.endedByTurn = true;
33733
+ }
33734
+ }
33735
+ }
33736
+ session.span.log({ error });
33737
+ const endTime = eventTime2(event);
33738
+ session.span.end(endTime === void 0 ? void 0 : { endTime });
33739
+ }
33740
+ async handleSessionCompleted(event, ctx) {
33741
+ const sessionId = sessionIdFromContext(ctx);
33742
+ if (!sessionId) {
33743
+ return;
33744
+ }
33745
+ const session = await this.ensureSession(
33746
+ sessionId,
33747
+ ctx,
33748
+ {},
33749
+ eventTime2(event)
33750
+ );
33751
+ for (const [key, turn] of this.turnsByKey) {
33752
+ if (!key.startsWith(`${sessionId}:`)) {
33753
+ continue;
33754
+ }
33755
+ this.finalizeTurn(turn, {
33756
+ endTime: eventTime2(event)
33757
+ });
33758
+ }
33759
+ for (const [key, tool] of this.toolsByCallKey) {
33760
+ if (key.startsWith(`${sessionId}:`) && !tool.endedByTurn) {
33761
+ const endTime2 = eventTime2(event);
33762
+ tool.span.log({ metadata: tool.metadata });
33763
+ tool.span.end(endTime2 === void 0 ? void 0 : { endTime: endTime2 });
33764
+ tool.endedByTurn = true;
33765
+ }
33766
+ }
33767
+ session.span.log({ metadata: session.metadata });
33768
+ const endTime = eventTime2(event);
33769
+ session.span.end(endTime === void 0 ? void 0 : { endTime });
33770
+ }
33771
+ async ensureSession(sessionId, ctx, metadata, startTime) {
33772
+ metadata = {
33773
+ ...readEveTraceState(this.state).metadata,
33774
+ ...metadata
33775
+ };
33776
+ const existing = this.sessionsById.get(sessionId);
33777
+ if (existing) {
33778
+ existing.metadata = { ...existing.metadata, ...metadata };
33779
+ existing.span.log({ metadata: existing.metadata });
33780
+ return existing;
33781
+ }
33782
+ const lineage = parentLineageFromContext(ctx);
33783
+ const parentSubagent = lineage ? this.toolsByCallKey.get(toolKey3(lineage.sessionId, lineage.callId)) : void 0;
33784
+ const activeParent = currentSpan();
33785
+ const [
33786
+ { rowId: eventId, spanId },
33787
+ parentSubagentSpanId,
33788
+ fallbackRootSpanId
33789
+ ] = await Promise.all([
33790
+ generateEveIds("session", sessionId),
33791
+ lineage ? spanIdForSubagent(lineage.sessionId, lineage.callId) : Promise.resolve(void 0),
33792
+ lineage ? rootSpanIdForSession(lineage.rootSessionId) : rootSpanIdForSession(sessionId)
33793
+ ]);
33794
+ const span = await this.startEveSpan({
33795
+ event: {
33796
+ id: eventId,
33797
+ metadata
33798
+ },
33799
+ name: "eve.session",
33800
+ parentSpanIds: lineage && parentSubagentSpanId ? {
33801
+ rootSpanId: parentSubagent?.span.rootSpanId ?? fallbackRootSpanId,
33802
+ spanId: parentSubagentSpanId
33803
+ } : !Object.is(activeParent, NOOP_SPAN) ? {
33804
+ rootSpanId: activeParent.rootSpanId,
33805
+ spanId: activeParent.spanId
33806
+ } : {
33807
+ parentSpanIds: [],
33808
+ rootSpanId: fallbackRootSpanId
33809
+ },
33810
+ spanAttributes: { type: "task" /* TASK */ },
33811
+ spanId,
33812
+ startTime
33813
+ });
33814
+ span.log({ metadata });
33815
+ const session = { metadata, sessionId, span };
33816
+ this.sessionsById.set(sessionId, session);
33817
+ return session;
33818
+ }
33819
+ async ensureTurn(event, ctx, hookMetadata) {
33820
+ const sessionId = sessionIdFromContext(ctx);
33821
+ if (!sessionId) {
33822
+ return void 0;
33823
+ }
33824
+ const session = await this.ensureSession(
33825
+ sessionId,
33826
+ ctx,
33827
+ hookMetadata ?? {},
33828
+ eventTime2(event)
33829
+ );
33830
+ const key = turnKey2(sessionId, event.data.turnId);
33831
+ const existing = this.turnsByKey.get(key);
33832
+ if (existing) {
33833
+ return existing;
33834
+ }
33835
+ const metadata = { ...session.metadata };
33836
+ const span = await this.startTurnSpan(session, event, metadata);
33837
+ span.log({ metadata });
33838
+ const state = {
33839
+ key,
33840
+ metadata,
33841
+ metrics: {},
33842
+ span,
33843
+ stepsByIndex: /* @__PURE__ */ new Map(),
33844
+ turnId: event.data.turnId
33845
+ };
33846
+ this.turnsByKey.set(key, state);
33847
+ return state;
33848
+ }
33849
+ async startRequestedTool(event, turn, sessionId, action) {
33850
+ const key = toolKey3(sessionId, action.callId);
33851
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
33852
+ return;
33853
+ }
33854
+ const metadata = toolMetadataFromTurn(turn);
33855
+ const { rowId: eventId, spanId } = await generateEveIds(
33856
+ "tool",
33857
+ sessionId,
33858
+ event.data.turnId,
33859
+ action.callId
33860
+ );
33861
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
33862
+ return;
33863
+ }
33864
+ const span = await this.startEveChildSpan(turn.span, {
33865
+ event: {
33866
+ id: eventId,
33867
+ input: action.input,
33868
+ metadata
33869
+ },
33870
+ name: action.toolName,
33871
+ spanAttributes: { type: "tool" /* TOOL */ },
33872
+ spanId,
33873
+ startTime: eventTime2(event)
33874
+ });
33875
+ span.log({ input: action.input, metadata });
33876
+ this.toolsByCallKey.set(key, {
33877
+ metadata,
33878
+ span,
33879
+ turnKey: turnKey2(sessionId, event.data.turnId)
33880
+ });
33881
+ }
33882
+ async startRequestedSubagent(event, turn, sessionId, action) {
33883
+ const key = toolKey3(sessionId, action.callId);
33884
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
33885
+ return;
33886
+ }
33887
+ const name = action.subagentName ?? action.name ?? "agent";
33888
+ const metadata = toolMetadataFromTurn(turn);
33889
+ const { rowId: eventId, spanId } = await generateEveIds(
33890
+ "subagent",
33891
+ sessionId,
33892
+ action.callId
33893
+ );
33894
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
33895
+ return;
33896
+ }
33897
+ const span = await this.startEveChildSpan(turn.span, {
33898
+ event: {
33899
+ id: eventId,
33900
+ input: action.input,
33901
+ metadata
33902
+ },
33903
+ name,
33904
+ spanAttributes: { type: "tool" /* TOOL */ },
33905
+ spanId,
33906
+ startTime: eventTime2(event)
33907
+ });
33908
+ span.log({ input: action.input, metadata });
33909
+ this.toolsByCallKey.set(key, {
33910
+ metadata,
33911
+ span,
33912
+ turnKey: turnKey2(sessionId, event.data.turnId)
33913
+ });
33914
+ }
33915
+ async startSyntheticTool(event, ctx, result, hookMetadata) {
33916
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33917
+ const sessionId = sessionIdFromContext(ctx);
33918
+ if (!turn || !sessionId) {
33919
+ return void 0;
33920
+ }
33921
+ const metadata = toolMetadataFromTurn(turn);
33922
+ const { rowId: eventId, spanId } = await generateEveIds(
33923
+ "tool",
33924
+ sessionId,
33925
+ event.data.turnId,
33926
+ result.callId
33927
+ );
33928
+ const existing = this.toolsByCallKey.get(toolKey3(sessionId, result.callId));
33929
+ if (existing) {
33930
+ return existing;
33931
+ }
33932
+ const span = await this.startEveChildSpan(turn.span, {
33933
+ event: {
33934
+ id: eventId,
33935
+ metadata
33936
+ },
33937
+ name: result.toolName,
33938
+ spanAttributes: { type: "tool" /* TOOL */ },
33939
+ spanId,
33940
+ startTime: eventTime2(event)
33941
+ });
33942
+ span.log({ metadata });
33943
+ const state = {
33944
+ metadata,
33945
+ span,
33946
+ turnKey: turnKey2(sessionId, event.data.turnId)
33947
+ };
33948
+ this.toolsByCallKey.set(toolKey3(sessionId, result.callId), state);
33949
+ return state;
33950
+ }
33951
+ async startSyntheticSubagent(event, ctx, hookMetadata) {
33952
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33953
+ const sessionId = sessionIdFromContext(ctx);
33954
+ if (!turn || !sessionId) {
33955
+ return void 0;
33956
+ }
33957
+ const metadata = toolMetadataFromTurn(turn);
33958
+ const { rowId: eventId, spanId } = await generateEveIds(
33959
+ "subagent",
33960
+ sessionId,
33961
+ event.data.callId
33962
+ );
33963
+ const existing = this.toolsByCallKey.get(
33964
+ toolKey3(sessionId, event.data.callId)
33965
+ );
33966
+ if (existing) {
33967
+ return existing;
33968
+ }
33969
+ const span = await this.startEveChildSpan(turn.span, {
33970
+ event: {
33971
+ id: eventId,
33972
+ metadata
33973
+ },
33974
+ name: event.data.subagentName,
33975
+ spanAttributes: { type: "tool" /* TOOL */ },
33976
+ spanId,
33977
+ startTime: eventTime2(event)
33978
+ });
33979
+ span.log({ metadata });
33980
+ const state = {
33981
+ metadata,
33982
+ span,
33983
+ turnKey: turnKey2(sessionId, event.data.turnId)
33984
+ };
33985
+ this.toolsByCallKey.set(toolKey3(sessionId, event.data.callId), state);
33986
+ return state;
33987
+ }
33988
+ async startSyntheticSubagentResult(event, ctx, result, hookMetadata) {
33989
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33990
+ const sessionId = sessionIdFromContext(ctx);
33991
+ if (!turn || !sessionId) {
33992
+ return void 0;
33993
+ }
33994
+ const metadata = toolMetadataFromTurn(turn);
33995
+ const { rowId: eventId, spanId } = await generateEveIds(
33996
+ "subagent",
33997
+ sessionId,
33998
+ result.callId
33999
+ );
34000
+ const existing = this.toolsByCallKey.get(toolKey3(sessionId, result.callId));
34001
+ if (existing) {
34002
+ return existing;
34003
+ }
34004
+ const span = await this.startEveChildSpan(turn.span, {
34005
+ event: {
34006
+ id: eventId,
34007
+ metadata
34008
+ },
34009
+ name: result.subagentName,
34010
+ spanAttributes: { type: "tool" /* TOOL */ },
34011
+ spanId,
34012
+ startTime: eventTime2(event)
34013
+ });
34014
+ span.log({ metadata });
34015
+ const state = {
34016
+ metadata,
34017
+ span,
34018
+ turnKey: turnKey2(sessionId, event.data.turnId)
34019
+ };
34020
+ this.toolsByCallKey.set(toolKey3(sessionId, result.callId), state);
34021
+ return state;
34022
+ }
34023
+ async startTurnSpan(session, event, metadata) {
34024
+ const { rowId: eventId, spanId } = await generateEveIds(
34025
+ "turn",
34026
+ session.sessionId,
34027
+ event.data.turnId
34028
+ );
34029
+ return await this.startEveSpan({
34030
+ event: {
34031
+ id: eventId,
34032
+ metadata
34033
+ },
34034
+ name: "eve.turn",
34035
+ parentSpanIds: {
34036
+ rootSpanId: session.span.rootSpanId,
34037
+ spanId: session.span.spanId
34038
+ },
34039
+ spanAttributes: { type: "task" /* TASK */ },
34040
+ spanId,
34041
+ startTime: eventTime2(event)
34042
+ });
34043
+ }
34044
+ turnForEvent(event, ctx) {
34045
+ const sessionId = sessionIdFromContext(ctx);
34046
+ return sessionId ? this.turnsByKey.get(turnKey2(sessionId, event.data.turnId)) : void 0;
34047
+ }
34048
+ stepForEvent(event, ctx) {
34049
+ return this.turnForEvent(event, ctx)?.stepsByIndex.get(
34050
+ event.data.stepIndex
34051
+ );
34052
+ }
34053
+ finalizeTurn(turn, args) {
34054
+ const { endTime } = args;
34055
+ for (const step of turn.stepsByIndex.values()) {
34056
+ step.span.log({
34057
+ ...step.input !== void 0 ? { input: step.input } : {},
34058
+ metadata: step.metadata,
34059
+ metrics: step.metrics,
34060
+ output: step.output
34061
+ });
34062
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
34063
+ }
34064
+ turn.stepsByIndex.clear();
34065
+ for (const tool of this.toolsByCallKey.values()) {
34066
+ if (tool.turnKey !== turn.key) {
34067
+ continue;
34068
+ }
34069
+ if (tool.endedByTurn) {
34070
+ continue;
34071
+ }
34072
+ tool.span.log({ metadata: tool.metadata });
34073
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
34074
+ tool.endedByTurn = true;
34075
+ }
34076
+ if (args.error) {
34077
+ turn.span.log({ error: args.error });
34078
+ } else {
34079
+ turn.span.log({
34080
+ metadata: turn.metadata,
34081
+ metrics: turn.metrics,
34082
+ output: turn.output
34083
+ });
34084
+ }
34085
+ turn.span.end(endTime === void 0 ? void 0 : { endTime });
34086
+ this.turnsByKey.delete(turn.key);
34087
+ this.state.update((current) => {
34088
+ const normalized = normalizeEveTraceState(current);
34089
+ return {
34090
+ ...normalized,
34091
+ stepStarts: normalized.stepStarts.filter(
34092
+ (entry) => entry.turnId !== turn.turnId
34093
+ )
34094
+ };
34095
+ });
34096
+ }
34097
+ cleanupSession(sessionId) {
34098
+ const keyPrefix = `${sessionId}:`;
34099
+ this.sessionsById.delete(sessionId);
34100
+ for (const key of this.turnsByKey.keys()) {
34101
+ if (key.startsWith(keyPrefix)) {
34102
+ this.turnsByKey.delete(key);
34103
+ }
34104
+ }
34105
+ for (const key of this.toolsByCallKey.keys()) {
34106
+ if (key.startsWith(keyPrefix)) {
34107
+ this.toolsByCallKey.delete(key);
34108
+ }
34109
+ }
34110
+ for (const key of this.completedToolKeys.keys()) {
34111
+ if (key.startsWith(keyPrefix)) {
34112
+ this.completedToolKeys.delete(key);
34113
+ }
34114
+ }
34115
+ this.state.update(() => emptyEveTraceState());
34116
+ }
34117
+ async flushInstrumentation() {
34118
+ try {
34119
+ await flush();
34120
+ return true;
34121
+ } catch (error) {
34122
+ debugLogger.warn("Error in Eve flush instrumentation:", error);
34123
+ return false;
34124
+ }
34125
+ }
34126
+ };
34127
+ function emptyEveTraceState() {
34128
+ return {
34129
+ llmInputs: [],
34130
+ metadata: {},
34131
+ spanReferences: [],
34132
+ stepStarts: []
34133
+ };
34134
+ }
34135
+ function normalizeEveTraceState(state) {
34136
+ if (!isObject(state)) {
34137
+ return emptyEveTraceState();
34138
+ }
34139
+ const metadata = isObject(state["metadata"]) ? state["metadata"] : {};
34140
+ const spanReferences = Array.isArray(state["spanReferences"]) ? state["spanReferences"].flatMap((entry) => {
34141
+ if (!isObject(entry)) {
34142
+ return [];
34143
+ }
34144
+ const exported = entry["exported"];
34145
+ const endTime = entry["endTime"];
34146
+ const rootSpanId = entry["rootSpanId"];
34147
+ const rowId = entry["rowId"];
34148
+ const spanId = entry["spanId"];
34149
+ const startEvent = entry["startEvent"];
34150
+ const startEventCreated = isObject(startEvent) ? startEvent["created"] : void 0;
34151
+ const startEventMetrics = isObject(startEvent) ? startEvent["metrics"] : void 0;
34152
+ const startEventSpanAttributes = isObject(startEvent) ? startEvent["span_attributes"] : void 0;
34153
+ const startEventSpanParents = isObject(startEvent) ? startEvent["span_parents"] : void 0;
34154
+ const normalizedStartEvent = typeof startEventCreated === "string" && isObject(startEventMetrics) && typeof startEventMetrics["start"] === "number" && Number.isFinite(startEventMetrics["start"]) && isObject(startEventSpanAttributes) && Array.isArray(startEventSpanParents) && startEventSpanParents.every(
34155
+ (parent) => typeof parent === "string"
34156
+ ) ? {
34157
+ created: startEventCreated,
34158
+ metrics: { start: startEventMetrics["start"] },
34159
+ span_attributes: { ...startEventSpanAttributes },
34160
+ span_parents: [...startEventSpanParents]
34161
+ } : void 0;
34162
+ return typeof exported === "string" && typeof rootSpanId === "string" && typeof rowId === "string" && typeof spanId === "string" ? [
34163
+ {
34164
+ ...typeof endTime === "number" && Number.isFinite(endTime) ? { endTime } : {},
34165
+ exported,
34166
+ rootSpanId,
34167
+ rowId,
34168
+ spanId,
34169
+ ...normalizedStartEvent ? { startEvent: normalizedStartEvent } : {}
34170
+ }
34171
+ ] : [];
34172
+ }).slice(-MAX_STORED_SPAN_REFERENCES) : [];
34173
+ const llmInputs = Array.isArray(state["llmInputs"]) ? state["llmInputs"].flatMap((entry) => {
34174
+ if (!isObject(entry)) {
34175
+ return [];
34176
+ }
34177
+ const key = entry["key"];
34178
+ const input = entry["input"];
34179
+ return typeof key === "string" && isCapturedModelInput(input) ? [{ input, key }] : [];
34180
+ }).slice(-MAX_STORED_LLM_INPUTS) : [];
34181
+ const stepStarts = Array.isArray(state["stepStarts"]) ? state["stepStarts"].flatMap((entry) => {
34182
+ if (!isObject(entry)) {
34183
+ return [];
34184
+ }
34185
+ const ordinal = entry["ordinal"];
34186
+ const open = entry["open"];
34187
+ const stepIndex = entry["stepIndex"];
34188
+ const turnId = entry["turnId"];
34189
+ 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 }] : [];
34190
+ }).slice(-MAX_STORED_STEP_STARTS) : [];
34191
+ return { llmInputs, metadata: { ...metadata }, spanReferences, stepStarts };
34192
+ }
34193
+ function readEveTraceState(state) {
34194
+ try {
34195
+ return normalizeEveTraceState(state.get());
34196
+ } catch {
34197
+ return emptyEveTraceState();
34198
+ }
34199
+ }
34200
+ function captureEveModelInput(state, input) {
34201
+ if (!isObject(input)) {
34202
+ return;
34203
+ }
34204
+ const session = input["session"];
34205
+ const turn = input["turn"];
34206
+ const step = input["step"];
34207
+ if (!isObject(session) || !isObject(turn) || !isObject(step)) {
34208
+ return;
34209
+ }
34210
+ const sessionId = session["id"];
34211
+ const turnId = turn["id"];
34212
+ const stepIndex = step["index"];
34213
+ if (typeof sessionId !== "string" || typeof turnId !== "string" || typeof stepIndex !== "number" || !Number.isInteger(stepIndex)) {
34214
+ return;
34215
+ }
34216
+ const captured = capturedModelInput(input["modelInput"]);
34217
+ if (!captured) {
34218
+ return;
34219
+ }
34220
+ const key = llmInputKey(sessionId, turnId, stepIndex);
34221
+ state.update((current) => {
34222
+ const normalized = normalizeEveTraceState(current);
34223
+ const llmInputs = [...normalized.llmInputs, { input: captured, key }];
34224
+ return {
34225
+ ...normalized,
34226
+ llmInputs: llmInputs.slice(-MAX_STORED_LLM_INPUTS)
34227
+ };
34228
+ });
34229
+ }
34230
+ function consumeCapturedEveModelInput(state, sessionId, turnId, stepIndex) {
34231
+ try {
34232
+ const key = llmInputKey(sessionId, turnId, stepIndex);
34233
+ let input;
34234
+ state.update((current) => {
34235
+ const normalized = normalizeEveTraceState(current);
34236
+ const index = normalized.llmInputs.findIndex(
34237
+ (candidate) => candidate.key === key
34238
+ );
34239
+ if (index < 0) {
34240
+ return normalized;
34241
+ }
34242
+ input = normalized.llmInputs[index]?.input;
34243
+ return {
34244
+ ...normalized,
34245
+ llmInputs: normalized.llmInputs.filter(
34246
+ (_, candidateIndex) => candidateIndex !== index
34247
+ )
34248
+ };
34249
+ });
34250
+ return input;
34251
+ } catch (error) {
34252
+ debugLogger.warn("Error in Eve LLM input consumption:", error);
34253
+ return void 0;
34254
+ }
34255
+ }
34256
+ function capturedModelInput(modelInput) {
34257
+ if (!isObject(modelInput)) {
34258
+ return void 0;
34259
+ }
34260
+ const messages = modelInput["messages"];
34261
+ if (!Array.isArray(messages)) {
34262
+ return void 0;
34263
+ }
34264
+ const instructions = modelInput["instructions"];
34265
+ const value = [
34266
+ ...instructions !== void 0 ? [{ content: instructions, role: "system" }] : [],
34267
+ ...messages
34268
+ ];
34269
+ try {
34270
+ const cloned = JSON.parse(JSON.stringify(value));
34271
+ if (!Array.isArray(cloned)) {
34272
+ return void 0;
34273
+ }
34274
+ return cloned;
34275
+ } catch {
34276
+ return void 0;
34277
+ }
34278
+ }
34279
+ function isCapturedModelInput(input) {
34280
+ return Array.isArray(input);
34281
+ }
34282
+ function llmInputKey(sessionId, turnId, stepIndex) {
34283
+ return `${sessionId}\0${turnId}\0${stepIndex}`;
34284
+ }
34285
+ function modelMetadataFromRuntime(runtime) {
34286
+ if (!isObject(runtime)) {
34287
+ return {};
34288
+ }
34289
+ const modelId = runtime["modelId"];
34290
+ return typeof modelId === "string" ? modelMetadataFromModelId(modelId) : {};
34291
+ }
34292
+ function modelMetadataFromModelId(modelId) {
34293
+ const normalized = modelId.trim();
34294
+ if (!normalized) {
34295
+ return {};
34296
+ }
34297
+ const slashIndex = normalized.indexOf("/");
34298
+ if (slashIndex > 0 && slashIndex < normalized.length - 1) {
34299
+ return {
34300
+ model: normalized.slice(slashIndex + 1),
34301
+ provider: normalized.slice(0, slashIndex)
34302
+ };
34303
+ }
34304
+ return {
34305
+ model: normalized
34306
+ };
34307
+ }
34308
+ function sessionIdFromContext(ctx) {
34309
+ if (!isObject(ctx)) {
34310
+ return void 0;
34311
+ }
34312
+ const session = ctx["session"];
34313
+ if (!isObject(session)) {
34314
+ return void 0;
34315
+ }
34316
+ const id = session["id"];
34317
+ return typeof id === "string" ? id : void 0;
34318
+ }
34319
+ function toolMetadataFromTurn(turn) {
34320
+ const { model: _model, provider: _provider, ...metadata } = turn.metadata;
34321
+ return metadata;
34322
+ }
34323
+ function parentLineageFromContext(ctx) {
34324
+ if (!isObject(ctx)) {
34325
+ return void 0;
34326
+ }
34327
+ const session = ctx.session;
34328
+ if (!isObject(session)) {
34329
+ return void 0;
34330
+ }
34331
+ const parent = session["parent"];
34332
+ if (!isObject(parent)) {
34333
+ return void 0;
34334
+ }
34335
+ const callId = parent["callId"];
34336
+ const rootSessionId = parent["rootSessionId"];
34337
+ const sessionId = parent["sessionId"];
34338
+ if (typeof callId !== "string" || typeof rootSessionId !== "string" || typeof sessionId !== "string") {
34339
+ return void 0;
34340
+ }
34341
+ return { callId, rootSessionId, sessionId };
34342
+ }
34343
+ function isToolCallAction(action) {
34344
+ return isObject(action) && action["kind"] === "tool-call" && typeof action["callId"] === "string" && typeof action["toolName"] === "string" && isObject(action["input"]);
34345
+ }
34346
+ function isLocalSubagentCallAction(action) {
34347
+ return isObject(action) && action["kind"] === "subagent-call" && typeof action["callId"] === "string" && isObject(action["input"]);
34348
+ }
34349
+ function isTraceableActionRequest(action) {
34350
+ return isToolCallAction(action) || isLocalSubagentCallAction(action);
34351
+ }
34352
+ function isToolResult(result) {
34353
+ return isObject(result) && result["kind"] === "tool-result" && typeof result["callId"] === "string" && typeof result["toolName"] === "string";
34354
+ }
34355
+ function isSubagentResult(result) {
34356
+ return isObject(result) && result["kind"] === "subagent-result" && typeof result["callId"] === "string" && typeof result["subagentName"] === "string";
34357
+ }
34358
+ function normalizedFinishReason(finishReason) {
34359
+ switch (finishReason) {
34360
+ case "content-filter":
34361
+ return "content_filter";
34362
+ case "tool-calls":
34363
+ return "tool_calls";
34364
+ default:
34365
+ return finishReason;
34366
+ }
34367
+ }
34368
+ function errorFromMessage(message, code, details) {
34369
+ const error = new Error(`${code}: ${message}`);
34370
+ if (details !== void 0) {
34371
+ error.cause = details;
34372
+ }
34373
+ return error;
34374
+ }
34375
+ function actionResultError(error, output) {
34376
+ if (error) {
34377
+ return errorFromMessage(error.message, error.code);
34378
+ }
34379
+ const result = new Error("Eve action failed");
34380
+ if (output !== void 0) {
34381
+ result.cause = output;
34382
+ }
34383
+ return result;
34384
+ }
34385
+ function eventTime2(event) {
34386
+ if (!event.meta?.at) {
34387
+ return void 0;
34388
+ }
34389
+ const timestamp = Date.parse(event.meta.at);
34390
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
34391
+ }
34392
+ function turnKey2(sessionId, turnId) {
34393
+ return `${sessionId}:${turnId}`;
34394
+ }
34395
+ function toolKey3(sessionId, callId) {
34396
+ return `${sessionId}:${callId}`;
34397
+ }
34398
+ async function rootSpanIdForSession(sessionId) {
34399
+ return deterministicEveId("eve:root", sessionId);
34400
+ }
34401
+ async function generateEveIds(kind, ...parts) {
34402
+ const [rowId, spanId] = await Promise.all([
34403
+ deterministicEveId(`eve:row:${kind}`, ...parts),
34404
+ deterministicEveId(`eve:${kind}`, ...parts)
34405
+ ]);
34406
+ return { rowId, spanId };
34407
+ }
34408
+ async function spanIdForSubagent(sessionId, callId) {
34409
+ return deterministicEveId("eve:subagent", sessionId, callId);
34410
+ }
34411
+ async function deterministicEveId(...parts) {
34412
+ const data = new TextEncoder().encode(
34413
+ parts.map((part) => `${part.length}:${part}`).join("\0")
34414
+ );
34415
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", data);
34416
+ const bytes = Array.from(new Uint8Array(digest, 0, 16));
34417
+ const hex = bytes.map((byte) => byte.toString(16).padStart(2, "0")).join("");
34418
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
34419
+ }
34420
+
32892
34421
  // src/typed-instrumentation-helpers.ts
32893
34422
  var TypedApplyProxy = Proxy;
32894
34423
 
@@ -33120,7 +34649,13 @@ var BraintrustObservabilityExporter = class {
33120
34649
  const args = {
33121
34650
  name: exported.name,
33122
34651
  spanAttributes: { type: spanTypeFor(exported.type) },
33123
- startTime: epochSeconds(exported.startTime)
34652
+ startTime: epochSeconds(exported.startTime),
34653
+ // Use the Mastra span id as the Braintrust row id so that
34654
+ // `logFeedback({ id: <mastra span id> })` (and Mastra's score events)
34655
+ // attach to the right row. Without this, `SpanImpl` auto-generates a
34656
+ // row id (`this._id = eventId ?? idGenerator.getSpanId()`) that no
34657
+ // external caller could know.
34658
+ event: { id: exported.id }
33124
34659
  };
33125
34660
  const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
33126
34661
  if (!this.capturedParent) {
@@ -39455,6 +40990,8 @@ export {
39455
40990
  addAzureBlobHeaders,
39456
40991
  agentAssertionScorer,
39457
40992
  braintrustAISDKTelemetry,
40993
+ braintrustEveHook,
40994
+ braintrustEveInstrumentation,
39458
40995
  braintrustFlueInstrumentation,
39459
40996
  braintrustFlueObserver,
39460
40997
  braintrustStreamChunkSchema,