braintrust 3.32.0 → 3.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +0 -43
  2. package/dev/dist/index.d.mts +31 -0
  3. package/dev/dist/index.d.ts +31 -0
  4. package/dev/dist/index.js +2275 -920
  5. package/dev/dist/index.mjs +1610 -255
  6. package/dist/apply-auto-instrumentation.js +263 -224
  7. package/dist/apply-auto-instrumentation.mjs +45 -6
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +78 -5
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +78 -5
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +78 -5
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +78 -5
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +78 -5
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +78 -5
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-AFND2U7E.mjs → chunk-T2DMPWFI.mjs} +75 -5
  20. package/dist/auto-instrumentations/{chunk-RI4Y55ZF.mjs → chunk-UHJ2DNYJ.mjs} +6 -1
  21. package/dist/auto-instrumentations/{chunk-QEEPRBIS.mjs → chunk-W5QNG3PV.mjs} +1 -1
  22. package/dist/auto-instrumentations/hook.mjs +86 -7
  23. package/dist/auto-instrumentations/index.cjs +76 -5
  24. package/dist/auto-instrumentations/index.d.mts +3 -1
  25. package/dist/auto-instrumentations/index.d.ts +3 -1
  26. package/dist/auto-instrumentations/index.mjs +3 -1
  27. package/dist/browser.d.mts +202 -342
  28. package/dist/browser.d.ts +202 -342
  29. package/dist/browser.js +2586 -623
  30. package/dist/browser.mjs +2586 -623
  31. package/dist/chunk-7P6ASYW6.mjs +9 -0
  32. package/dist/{chunk-BTRLPQG5.js → chunk-AXJTOUOC.js} +2250 -1172
  33. package/dist/{chunk-AW4QECG5.js → chunk-G3VHOHRC.js} +40 -9
  34. package/dist/chunk-MLKGABMK.js +9 -0
  35. package/dist/{chunk-4QSAHP7D.mjs → chunk-MZLBAFVJ.mjs} +1236 -158
  36. package/dist/{chunk-WV6QZI2W.mjs → chunk-TZVZN2JJ.mjs} +39 -8
  37. package/dist/cli.js +1695 -293
  38. package/dist/custom-views.d.mts +112 -0
  39. package/dist/custom-views.d.ts +112 -0
  40. package/dist/custom-views.js +13 -0
  41. package/dist/custom-views.mjs +13 -0
  42. package/dist/edge-light.d.mts +1 -1
  43. package/dist/edge-light.d.ts +1 -1
  44. package/dist/edge-light.js +2586 -623
  45. package/dist/edge-light.mjs +2586 -623
  46. package/dist/index.d.mts +202 -342
  47. package/dist/index.d.ts +202 -342
  48. package/dist/index.js +1842 -986
  49. package/dist/index.mjs +1310 -454
  50. package/dist/instrumentation/index.d.mts +5 -245
  51. package/dist/instrumentation/index.d.ts +5 -245
  52. package/dist/instrumentation/index.js +1694 -254
  53. package/dist/instrumentation/index.mjs +1694 -254
  54. package/dist/vitest-evals-reporter.js +17 -16
  55. package/dist/vitest-evals-reporter.mjs +3 -2
  56. package/dist/workerd.d.mts +1 -1
  57. package/dist/workerd.d.ts +1 -1
  58. package/dist/workerd.js +2586 -623
  59. package/dist/workerd.mjs +2586 -623
  60. package/package.json +10 -2
package/dist/browser.mjs CHANGED
@@ -5671,6 +5671,7 @@ var INSTRUMENTATION_NAMES = {
5671
5671
  LANGSMITH: "langsmith",
5672
5672
  MASTRA: "mastra",
5673
5673
  MISTRAL: "mistral",
5674
+ LANGGRAPH_SDK: "langgraph-sdk",
5674
5675
  OLLAMA: "ollama",
5675
5676
  OPENAI: "openai",
5676
5677
  OPENAI_AGENTS: "openai-agents",
@@ -5685,7 +5686,7 @@ var INSTRUMENTATION_NAMES = {
5685
5686
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5686
5687
  "braintrust.spanInstrumentationName"
5687
5688
  );
5688
- var SDK_VERSION = true ? "3.32.0" : "0.0.0";
5689
+ var SDK_VERSION = true ? "3.33.0" : "0.0.0";
5689
5690
  function withSpanInstrumentationName(args, instrumentationName) {
5690
5691
  return {
5691
5692
  ...args,
@@ -9476,6 +9477,38 @@ function getSpanParentObjectAndPropagatedState(options) {
9476
9477
  function getSpanParentObject(options) {
9477
9478
  return getSpanParentObjectAndPropagatedState(options).parentObject;
9478
9479
  }
9480
+ function _internalExportParentSynchronously(parent) {
9481
+ if ("toStr" in parent) {
9482
+ return parent.toStr();
9483
+ }
9484
+ if ("getParentInfo" in parent) {
9485
+ const parentInfo = parent.getParentInfo();
9486
+ if (!parentInfo) {
9487
+ return void 0;
9488
+ }
9489
+ const objectId = parentInfo.objectId.getSync().value;
9490
+ if (!objectId && !parentInfo.computeObjectMetadataArgs) {
9491
+ return void 0;
9492
+ }
9493
+ return new SpanComponentsV4({
9494
+ object_type: parentInfo.objectType,
9495
+ ...objectId ? { object_id: objectId } : {
9496
+ compute_object_metadata_args: parentInfo.computeObjectMetadataArgs ?? {}
9497
+ },
9498
+ row_id: parent.id,
9499
+ root_span_id: parent.rootSpanId,
9500
+ span_id: parent.spanId
9501
+ }).toStr();
9502
+ }
9503
+ const components = braintrustParentToComponents(parent._getOtelParent());
9504
+ if (!components) {
9505
+ return void 0;
9506
+ }
9507
+ return new SpanComponentsV4({
9508
+ object_type: components.objectType,
9509
+ ...components.objectId ? { object_id: components.objectId } : { compute_object_metadata_args: components.computeArgs ?? {} }
9510
+ }).toStr();
9511
+ }
9479
9512
  function currentBraintrustParent(state) {
9480
9513
  const resolvedState = state ?? _globalState;
9481
9514
  const experiment = currentExperiment({ state: resolvedState });
@@ -11087,10 +11120,16 @@ var SpanImpl = class _SpanImpl {
11087
11120
  inject(carrier) {
11088
11121
  const resolvedCarrier = carrier ?? {};
11089
11122
  try {
11123
+ const braintrustParent = this._getOtelParent() ?? this._propagatedState?.braintrustParent;
11124
+ if (!braintrustParent) {
11125
+ debugLogger.forState(this._state).warn(
11126
+ "Injecting trace context without braintrust.parent because the span's destination is not available yet. The receiver will start a new local trace instead of continuing this one."
11127
+ );
11128
+ }
11090
11129
  _injectIntoCarrier(resolvedCarrier, {
11091
11130
  traceId: this._rootSpanId,
11092
11131
  spanId: this._spanId,
11093
- braintrustParent: this._getOtelParent() ?? this._propagatedState?.braintrustParent,
11132
+ braintrustParent,
11094
11133
  propagatedState: this._propagatedState
11095
11134
  });
11096
11135
  } catch (e) {
@@ -13495,6 +13534,18 @@ function defineChannels(pkg, channels, options) {
13495
13534
  var openAIChannels = defineChannels(
13496
13535
  "openai",
13497
13536
  {
13537
+ agentsTraceStart: channel({
13538
+ channelName: "agents.trace.start",
13539
+ kind: "async"
13540
+ }),
13541
+ agentsTraceCapture: channel({
13542
+ channelName: "agents.trace.capture",
13543
+ kind: "async"
13544
+ }),
13545
+ agentsTraceFail: channel({
13546
+ channelName: "agents.trace.fail",
13547
+ kind: "async"
13548
+ }),
13498
13549
  filesCreateTraced: channel({
13499
13550
  channelName: "files.create-traced",
13500
13551
  kind: "async"
@@ -13863,6 +13914,23 @@ function getCachedMetricFromHeaders(headers) {
13863
13914
  return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
13864
13915
  }
13865
13916
 
13917
+ // src/instrumentation/plugins/openai-manual-instrumentation-utils.ts
13918
+ async function deterministicDigest(namespace, ...parts) {
13919
+ const encoded = new TextEncoder().encode(
13920
+ [namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
13921
+ );
13922
+ return new Uint8Array(
13923
+ await globalThis.crypto.subtle.digest("SHA-256", encoded)
13924
+ );
13925
+ }
13926
+ function digestHex(bytes, length) {
13927
+ return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
13928
+ }
13929
+ function digestUuid(bytes) {
13930
+ const hex = digestHex(bytes, 16);
13931
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13932
+ }
13933
+
13866
13934
  // src/instrumentation/plugins/openai-batch-instrumentation.ts
13867
13935
  var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
13868
13936
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
@@ -13903,21 +13971,6 @@ async function exportParent(parent) {
13903
13971
  }
13904
13972
  return void 0;
13905
13973
  }
13906
- async function deterministicDigest(namespace, ...parts) {
13907
- const encoded = new TextEncoder().encode(
13908
- [namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
13909
- );
13910
- return new Uint8Array(
13911
- await globalThis.crypto.subtle.digest("SHA-256", encoded)
13912
- );
13913
- }
13914
- function digestHex(bytes, length) {
13915
- return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
13916
- }
13917
- function digestUuid(bytes) {
13918
- const hex = digestHex(bytes, 16);
13919
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13920
- }
13921
13974
  async function batchSpanIds(inputFileId) {
13922
13975
  const [row, span, root] = await Promise.all([
13923
13976
  deterministicDigest("openai:batch:row", inputFileId),
@@ -14408,6 +14461,628 @@ var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resol
14408
14461
  return result;
14409
14462
  });
14410
14463
 
14464
+ // src/instrumentation/plugins/openai-agents-api-instrumentation.ts
14465
+ var TERMINAL_TURN_EVENTS = /* @__PURE__ */ new Set([
14466
+ "agent.session.turn.completed",
14467
+ "agent.session.turn.failed",
14468
+ "agent.session.turn.cancelled"
14469
+ ]);
14470
+ var TURN_LIFECYCLE_EVENTS = /* @__PURE__ */ new Set([
14471
+ "agent.session.turn.created",
14472
+ "agent.session.turn.in_progress",
14473
+ ...TERMINAL_TURN_EVENTS
14474
+ ]);
14475
+ var SESSION_EVENTS = /* @__PURE__ */ new Set([
14476
+ "agent.session.created",
14477
+ "agent.session.failed",
14478
+ "agent.session.idle",
14479
+ "agent.session.in_progress",
14480
+ "agent.session.requires_action"
14481
+ ]);
14482
+ var SUBAGENT_EVENTS = /* @__PURE__ */ new Set([
14483
+ "agent.session.subagent.active",
14484
+ "agent.session.subagent.closed",
14485
+ "agent.session.subagent.created"
14486
+ ]);
14487
+ function read2(value, key) {
14488
+ if (!isObject(value)) {
14489
+ return void 0;
14490
+ }
14491
+ try {
14492
+ return Reflect.get(value, key);
14493
+ } catch {
14494
+ return void 0;
14495
+ }
14496
+ }
14497
+ function stringValue(value) {
14498
+ return typeof value === "string" && value.length > 0 ? value : void 0;
14499
+ }
14500
+ function recordValue(record, key) {
14501
+ return Object.hasOwn(record, key) ? record[key] : void 0;
14502
+ }
14503
+ function setRecordValue(record, key, value) {
14504
+ Object.defineProperty(record, key, {
14505
+ configurable: true,
14506
+ enumerable: true,
14507
+ value,
14508
+ writable: true
14509
+ });
14510
+ }
14511
+ function loggedError(value, fallback2) {
14512
+ if (value instanceof Error) {
14513
+ return value;
14514
+ }
14515
+ const message = stringValue(read2(value, "message"));
14516
+ return new Error(message ?? (typeof value === "string" ? value : fallback2));
14517
+ }
14518
+ function logInstrumentationError(context, error) {
14519
+ debugLogger.debug(`OpenAI Agents API instrumentation ${context}:`, error);
14520
+ }
14521
+ async function childSpanIds2(rootKey, kind, providerId) {
14522
+ const [row, span] = await Promise.all([
14523
+ deterministicDigest("openai:agents:row", rootKey, kind, providerId),
14524
+ deterministicDigest("openai:agents:span", rootKey, kind, providerId)
14525
+ ]);
14526
+ return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
14527
+ }
14528
+ function traceMetadata(args) {
14529
+ const metadata = {};
14530
+ const suppliedMetadata = read2(args, "metadata");
14531
+ if (isObject(suppliedMetadata)) {
14532
+ try {
14533
+ for (const key of Object.keys(suppliedMetadata)) {
14534
+ metadata[key] = read2(suppliedMetadata, key);
14535
+ }
14536
+ } catch (error) {
14537
+ logInstrumentationError("could not read supplied metadata", error);
14538
+ }
14539
+ }
14540
+ const agent = read2(args, "agent");
14541
+ const agentId = stringValue(read2(agent, "id")) ?? stringValue(read2(args, "agent_id"));
14542
+ const agentName = stringValue(read2(agent, "name"));
14543
+ const model = stringValue(read2(agent, "model"));
14544
+ return {
14545
+ ...metadata,
14546
+ api: "agents",
14547
+ ...agentId ? { agent_id: agentId } : {},
14548
+ ...agentName ? { agent_name: agentName } : {},
14549
+ ...model ? { model } : {},
14550
+ provider: "openai"
14551
+ };
14552
+ }
14553
+ function copyState(state) {
14554
+ return {
14555
+ ...state,
14556
+ callItems: { ...state.callItems },
14557
+ eventIds: [...state.eventIds],
14558
+ openTools: { ...state.openTools },
14559
+ subagents: { ...state.subagents },
14560
+ turnSubagents: { ...state.turnSubagents }
14561
+ };
14562
+ }
14563
+ function startRootSpan(state) {
14564
+ const root = SpanComponentsV4.fromStr(state.root);
14565
+ const parent = SpanComponentsV4.fromStr(state.rootParent);
14566
+ const rowId = stringValue(root.data.row_id);
14567
+ const rootSpanId = stringValue(root.data.root_span_id);
14568
+ const spanId = stringValue(root.data.span_id);
14569
+ if (!rowId || !rootSpanId || !spanId) {
14570
+ throw new Error("OpenAI Agents trace root is invalid");
14571
+ }
14572
+ const hasParentSpan = Boolean(
14573
+ parent.data.row_id && parent.data.span_id && parent.data.root_span_id
14574
+ );
14575
+ return withCurrent(
14576
+ NOOP_SPAN,
14577
+ () => _internalStartSpanWithInitialMergeAndParentSpanIds(
14578
+ withSpanInstrumentationName(
14579
+ {
14580
+ name: "openai.agents.turn",
14581
+ type: "task" /* TASK */,
14582
+ parent: state.rootParent,
14583
+ ...!hasParentSpan ? {
14584
+ parentSpanIds: {
14585
+ parentSpanIds: [],
14586
+ rootSpanId
14587
+ }
14588
+ } : {},
14589
+ spanId,
14590
+ startTime: state.startTime,
14591
+ event: { id: rowId }
14592
+ },
14593
+ INSTRUMENTATION_NAMES.OPENAI
14594
+ )
14595
+ )
14596
+ );
14597
+ }
14598
+ async function startSubagentSpan(state, subagentId, input, metadata, visiting = /* @__PURE__ */ new Set()) {
14599
+ const subagent = recordValue(state.subagents, subagentId);
14600
+ let parent = state.root;
14601
+ if (subagent?.parentAgentId && subagent.parentAgentId !== subagentId && recordValue(state.subagents, subagent.parentAgentId) && !visiting.has(subagent.parentAgentId)) {
14602
+ visiting.add(subagentId);
14603
+ parent = await (await startSubagentSpan(
14604
+ state,
14605
+ subagent.parentAgentId,
14606
+ void 0,
14607
+ void 0,
14608
+ visiting
14609
+ )).export();
14610
+ }
14611
+ const ids = await childSpanIds2(state.rootKey, "subagent", subagentId);
14612
+ return withCurrent(
14613
+ NOOP_SPAN,
14614
+ () => _internalStartSpanWithInitialMerge(
14615
+ withSpanInstrumentationName(
14616
+ {
14617
+ name: "openai.agents.subagent",
14618
+ type: "task" /* TASK */,
14619
+ parent,
14620
+ spanId: ids.spanId,
14621
+ startTime: subagent?.openedAt,
14622
+ event: {
14623
+ id: ids.rowId,
14624
+ ...input !== void 0 ? { input } : {},
14625
+ metadata: {
14626
+ ...metadata,
14627
+ agent_id: subagentId,
14628
+ ...subagent?.parentAgentId ? { parent_agent_id: subagent.parentAgentId } : {},
14629
+ provider: "openai"
14630
+ }
14631
+ }
14632
+ },
14633
+ INSTRUMENTATION_NAMES.OPENAI
14634
+ )
14635
+ )
14636
+ );
14637
+ }
14638
+ async function parentForTurn(state, turnId) {
14639
+ const subagentId = turnId ? recordValue(state.turnSubagents, turnId) : void 0;
14640
+ if (!subagentId) {
14641
+ return state.root;
14642
+ }
14643
+ return await (await startSubagentSpan(state, subagentId)).export();
14644
+ }
14645
+ async function startToolSpan(state, tool, input) {
14646
+ const ids = await childSpanIds2(state.rootKey, "tool", tool.itemId);
14647
+ return withCurrent(
14648
+ NOOP_SPAN,
14649
+ async () => _internalStartSpanWithInitialMerge(
14650
+ withSpanInstrumentationName(
14651
+ {
14652
+ name: tool.name,
14653
+ type: "tool" /* TOOL */,
14654
+ parent: await parentForTurn(state, tool.turnId),
14655
+ spanId: ids.spanId,
14656
+ startTime: tool.startTime,
14657
+ event: {
14658
+ id: ids.rowId,
14659
+ ...input !== void 0 ? { input } : {},
14660
+ metadata: {
14661
+ item_id: tool.itemId,
14662
+ provider: "openai",
14663
+ tool_type: tool.toolType,
14664
+ ...tool.turnId ? { turn_id: tool.turnId } : {}
14665
+ }
14666
+ }
14667
+ },
14668
+ INSTRUMENTATION_NAMES.OPENAI
14669
+ )
14670
+ )
14671
+ );
14672
+ }
14673
+ function toolFromItem(item, observedAt) {
14674
+ const itemId = stringValue(read2(item, "id"));
14675
+ const toolType = stringValue(read2(item, "type"));
14676
+ if (!itemId || !toolType) {
14677
+ return void 0;
14678
+ }
14679
+ const turnId = stringValue(read2(item, "turn_id"));
14680
+ switch (toolType) {
14681
+ case "function_call":
14682
+ return {
14683
+ input: read2(item, "arguments"),
14684
+ tool: {
14685
+ itemId,
14686
+ name: stringValue(read2(item, "name")) ?? "Function call",
14687
+ startTime: observedAt,
14688
+ toolType,
14689
+ ...turnId ? { turnId } : {}
14690
+ }
14691
+ };
14692
+ case "mcp_call": {
14693
+ const name = stringValue(read2(item, "name")) ?? "MCP call";
14694
+ const server = stringValue(read2(item, "server_label"));
14695
+ return {
14696
+ input: read2(item, "arguments"),
14697
+ tool: {
14698
+ itemId,
14699
+ name: server ? `${server}.${name}` : name,
14700
+ startTime: observedAt,
14701
+ toolType,
14702
+ ...turnId ? { turnId } : {}
14703
+ }
14704
+ };
14705
+ }
14706
+ case "web_search_call":
14707
+ return {
14708
+ input: read2(item, "action"),
14709
+ tool: {
14710
+ itemId,
14711
+ name: "Web search",
14712
+ startTime: observedAt,
14713
+ toolType,
14714
+ ...turnId ? { turnId } : {}
14715
+ }
14716
+ };
14717
+ case "command_execution":
14718
+ return {
14719
+ input: {
14720
+ command: read2(item, "command"),
14721
+ cwd: read2(item, "cwd")
14722
+ },
14723
+ tool: {
14724
+ itemId,
14725
+ name: "Command execution",
14726
+ startTime: observedAt,
14727
+ toolType,
14728
+ ...turnId ? { turnId } : {}
14729
+ }
14730
+ };
14731
+ default:
14732
+ return void 0;
14733
+ }
14734
+ }
14735
+ function textFromContent(content) {
14736
+ if (!Array.isArray(content)) {
14737
+ return void 0;
14738
+ }
14739
+ const text = [];
14740
+ for (const part of content) {
14741
+ const partText = read2(part, "text");
14742
+ if (read2(part, "type") === "output_text" && typeof partText === "string") {
14743
+ text.push(partText);
14744
+ }
14745
+ }
14746
+ return text.length > 0 ? text.join("") : void 0;
14747
+ }
14748
+ function toolOutput(item, toolType) {
14749
+ switch (toolType) {
14750
+ case "function_call":
14751
+ return read2(item, "output");
14752
+ case "mcp_call":
14753
+ return read2(item, "output");
14754
+ case "web_search_call":
14755
+ return read2(item, "action");
14756
+ case "command_execution":
14757
+ return read2(item, "output");
14758
+ default:
14759
+ return void 0;
14760
+ }
14761
+ }
14762
+ function toolFailed(item, toolType) {
14763
+ const status = read2(item, "status");
14764
+ const explicitError = read2(item, "error");
14765
+ if (explicitError !== void 0 && explicitError !== null) {
14766
+ return loggedError(explicitError, `OpenAI ${toolType} failed`);
14767
+ }
14768
+ if (status === "failed" || status === "incomplete") {
14769
+ return new Error(`OpenAI ${toolType} ${status}`);
14770
+ }
14771
+ if (toolType === "command_execution" && typeof read2(item, "exit_code") === "number" && read2(item, "exit_code") !== 0) {
14772
+ return new Error(
14773
+ `OpenAI command exited with code ${read2(item, "exit_code")}`
14774
+ );
14775
+ }
14776
+ return void 0;
14777
+ }
14778
+ async function completeTool(state, tool, item, endTime) {
14779
+ const span = await startToolSpan(state, tool);
14780
+ const output = toolOutput(item, tool.toolType);
14781
+ const error = toolFailed(item, tool.toolType);
14782
+ span.log({
14783
+ ...output !== void 0 ? { output } : {},
14784
+ ...error ? { error } : {},
14785
+ metadata: {
14786
+ status: read2(item, "status"),
14787
+ ...tool.toolType === "command_execution" ? { exit_code: read2(item, "exit_code") } : {}
14788
+ }
14789
+ });
14790
+ span.end({ endTime });
14791
+ Reflect.deleteProperty(state.openTools, tool.itemId);
14792
+ }
14793
+ async function captureMessage(state, item) {
14794
+ if (read2(item, "type") !== "message" || read2(item, "role") !== "assistant" || read2(item, "phase") !== "final_answer") {
14795
+ return;
14796
+ }
14797
+ const output = textFromContent(read2(item, "content"));
14798
+ if (output === void 0) {
14799
+ return;
14800
+ }
14801
+ const turnId = stringValue(read2(item, "turn_id"));
14802
+ const subagentId = turnId ? recordValue(state.turnSubagents, turnId) : void 0;
14803
+ if (subagentId) {
14804
+ (await startSubagentSpan(state, subagentId)).log({ output });
14805
+ } else {
14806
+ startRootSpan(state).log({ output });
14807
+ }
14808
+ }
14809
+ async function captureItem(state, item, isDone, observedAt) {
14810
+ await captureMessage(state, item);
14811
+ const itemType = stringValue(read2(item, "type"));
14812
+ if (itemType === "function_call_output") {
14813
+ const callId = stringValue(read2(item, "call_id"));
14814
+ const itemId = callId ? recordValue(state.callItems, callId) : void 0;
14815
+ const tool2 = itemId ? recordValue(state.openTools, itemId) : void 0;
14816
+ if (tool2) {
14817
+ await completeTool(state, tool2, item, observedAt);
14818
+ }
14819
+ return;
14820
+ }
14821
+ const descriptor = toolFromItem(item, observedAt);
14822
+ if (!descriptor) {
14823
+ return;
14824
+ }
14825
+ const existing = recordValue(state.openTools, descriptor.tool.itemId);
14826
+ const tool = existing ?? descriptor.tool;
14827
+ setRecordValue(state.openTools, tool.itemId, tool);
14828
+ if (itemType === "function_call") {
14829
+ const callId = stringValue(read2(item, "call_id"));
14830
+ if (callId) {
14831
+ setRecordValue(state.callItems, callId, tool.itemId);
14832
+ }
14833
+ }
14834
+ await startToolSpan(state, tool, descriptor.input);
14835
+ const status = read2(item, "status");
14836
+ const terminalFunctionCall = itemType === "function_call" && (status === "failed" || status === "incomplete");
14837
+ if (itemType !== "function_call" && (isDone || status !== "in_progress") || terminalFunctionCall) {
14838
+ await completeTool(state, tool, item, observedAt);
14839
+ }
14840
+ }
14841
+ function updateSessionMetadata(state, session) {
14842
+ const sessionId = stringValue(read2(session, "id"));
14843
+ const agent = read2(session, "agent");
14844
+ startRootSpan(state).log({
14845
+ metadata: {
14846
+ ...sessionId ? { session_id: sessionId } : {},
14847
+ ...stringValue(read2(agent, "id")) ? { agent_id: read2(agent, "id") } : {},
14848
+ ...stringValue(read2(agent, "name")) ? { agent_name: read2(agent, "name") } : {},
14849
+ ...stringValue(read2(agent, "model")) ? { model: read2(agent, "model") } : {}
14850
+ }
14851
+ });
14852
+ }
14853
+ async function captureSubagent(state, eventType, subagent, observedAt) {
14854
+ const subagentId = stringValue(read2(subagent, "id"));
14855
+ if (!subagentId) {
14856
+ return;
14857
+ }
14858
+ const existing = recordValue(state.subagents, subagentId);
14859
+ const observedOpenedAt = read2(subagent, "opened_at");
14860
+ const openedAt = typeof observedOpenedAt === "number" && Number.isFinite(observedOpenedAt) && observedOpenedAt >= 0 ? observedOpenedAt : existing?.openedAt ?? observedAt;
14861
+ const observedClosedAt = read2(subagent, "closed_at");
14862
+ const closedAt = typeof observedClosedAt === "number" && Number.isFinite(observedClosedAt) && observedClosedAt >= 0 ? observedClosedAt : existing?.closedAt;
14863
+ const parentAgentId = stringValue(read2(subagent, "parent_agent_id")) ?? existing?.parentAgentId;
14864
+ setRecordValue(state.subagents, subagentId, {
14865
+ ...closedAt !== void 0 ? { closedAt } : {},
14866
+ openedAt,
14867
+ ...parentAgentId ? { parentAgentId } : {}
14868
+ });
14869
+ const span = await startSubagentSpan(
14870
+ state,
14871
+ subagentId,
14872
+ read2(subagent, "instructions"),
14873
+ {
14874
+ ...stringValue(read2(subagent, "name")) ? { agent_name: read2(subagent, "name") } : {},
14875
+ status: read2(subagent, "status")
14876
+ }
14877
+ );
14878
+ if (eventType === "agent.session.subagent.closed") {
14879
+ span.end({ endTime: closedAt ?? observedAt });
14880
+ }
14881
+ }
14882
+ async function closeTrace(state, endTime, error, usage) {
14883
+ if (state.ended) {
14884
+ return;
14885
+ }
14886
+ for (const tool of Object.values(state.openTools)) {
14887
+ const span = await startToolSpan(state, tool);
14888
+ span.log({
14889
+ error: error ?? new Error("OpenAI Agents turn ended before tool completion")
14890
+ });
14891
+ span.end({ endTime });
14892
+ }
14893
+ state.openTools = {};
14894
+ for (const subagentId of Object.keys(state.subagents)) {
14895
+ const subagent = state.subagents[subagentId];
14896
+ const span = await startSubagentSpan(state, subagentId);
14897
+ span.end({ endTime: subagent.closedAt ?? endTime });
14898
+ }
14899
+ const root = startRootSpan(state);
14900
+ root.log({
14901
+ ...error ? { error } : {},
14902
+ metrics: parseMetricsFromUsage(usage)
14903
+ });
14904
+ root.end({ endTime });
14905
+ state.ended = true;
14906
+ }
14907
+ async function captureTurnLifecycle(state, event, eventType, observedAt) {
14908
+ const turn = read2(event, "turn");
14909
+ const turnId = stringValue(read2(event, "turn_id")) ?? stringValue(read2(turn, "id"));
14910
+ const subagentId = stringValue(read2(turn, "subagent_id"));
14911
+ if (turnId && subagentId) {
14912
+ setRecordValue(state.turnSubagents, turnId, subagentId);
14913
+ if (!recordValue(state.subagents, subagentId)) {
14914
+ const createdAt = read2(turn, "created_at");
14915
+ setRecordValue(state.subagents, subagentId, {
14916
+ openedAt: typeof createdAt === "number" && Number.isFinite(createdAt) && createdAt >= 0 ? createdAt : observedAt
14917
+ });
14918
+ }
14919
+ await startSubagentSpan(state, subagentId);
14920
+ }
14921
+ const sessionId = stringValue(read2(event, "session_id"));
14922
+ if (sessionId) {
14923
+ startRootSpan(state).log({ metadata: { session_id: sessionId } });
14924
+ }
14925
+ if (!TERMINAL_TURN_EVENTS.has(eventType) || subagentId) {
14926
+ if (subagentId && eventType === "agent.session.turn.failed") {
14927
+ (await startSubagentSpan(state, subagentId)).log({
14928
+ error: loggedError(read2(turn, "error"), "OpenAI subagent turn failed")
14929
+ });
14930
+ }
14931
+ return;
14932
+ }
14933
+ const completedAt = read2(turn, "completed_at");
14934
+ const endTime = typeof completedAt === "number" && Number.isFinite(completedAt) && completedAt >= 0 ? completedAt : observedAt;
14935
+ const usage = read2(event, "usage") ?? read2(turn, "usage");
14936
+ const error = eventType === "agent.session.turn.completed" ? void 0 : loggedError(
14937
+ read2(turn, "error"),
14938
+ eventType === "agent.session.turn.cancelled" ? "OpenAI Agents turn cancelled" : "OpenAI Agents turn failed"
14939
+ );
14940
+ await closeTrace(state, endTime, error, usage);
14941
+ }
14942
+ async function captureEvent(state, event) {
14943
+ if (state.ended) {
14944
+ return state;
14945
+ }
14946
+ const eventType = stringValue(read2(event, "type"));
14947
+ const eventId = stringValue(read2(event, "event_id"));
14948
+ if (!eventType || eventId && state.eventIds.includes(eventId)) {
14949
+ return state;
14950
+ }
14951
+ const next = copyState(state);
14952
+ const observedAt = getCurrentUnixTimestamp();
14953
+ let handled = false;
14954
+ if (SESSION_EVENTS.has(eventType)) {
14955
+ const session = read2(event, "session");
14956
+ if (session) {
14957
+ updateSessionMetadata(next, session);
14958
+ }
14959
+ handled = true;
14960
+ }
14961
+ if (eventType === "agent.session.turn.item.added") {
14962
+ await captureItem(next, read2(event, "item"), false, observedAt);
14963
+ handled = true;
14964
+ } else if (eventType === "agent.session.turn.item.done") {
14965
+ await captureItem(next, read2(event, "item"), true, observedAt);
14966
+ handled = true;
14967
+ } else if (TURN_LIFECYCLE_EVENTS.has(eventType)) {
14968
+ await captureTurnLifecycle(next, event, eventType, observedAt);
14969
+ handled = true;
14970
+ } else if (SUBAGENT_EVENTS.has(eventType)) {
14971
+ await captureSubagent(next, eventType, read2(event, "subagent"), observedAt);
14972
+ handled = true;
14973
+ } else if (eventType === "agent.session.turn.output_text.delta" && next.firstTokenAt === void 0 && stringValue(read2(event, "delta"))) {
14974
+ next.firstTokenAt = observedAt;
14975
+ startRootSpan(next).log({
14976
+ metrics: { time_to_first_token: observedAt - next.startTime }
14977
+ });
14978
+ handled = true;
14979
+ } else if (eventType === "agent.session.failed") {
14980
+ const session = read2(event, "session");
14981
+ const lastActiveAt = read2(session, "last_active_at");
14982
+ const endTime = typeof lastActiveAt === "number" && Number.isFinite(lastActiveAt) && lastActiveAt >= 0 ? lastActiveAt : observedAt;
14983
+ await closeTrace(
14984
+ next,
14985
+ endTime,
14986
+ loggedError(read2(session, "error"), "OpenAI Agents session failed"),
14987
+ read2(session, "usage")
14988
+ );
14989
+ handled = true;
14990
+ } else if (eventType === "error") {
14991
+ await closeTrace(
14992
+ next,
14993
+ observedAt,
14994
+ loggedError(read2(event, "error"), "OpenAI Agents session failed")
14995
+ );
14996
+ handled = true;
14997
+ }
14998
+ if (!handled) {
14999
+ return state;
15000
+ }
15001
+ if (eventId) {
15002
+ next.eventIds.push(eventId);
15003
+ }
15004
+ return next;
15005
+ }
15006
+ var interceptOpenAIAgentsTraceStart = async (target, thisArg, args) => {
15007
+ const fallback2 = await Reflect.apply(target, thisArg, args);
15008
+ try {
15009
+ const state = args[0].state;
15010
+ const parent = state.rootParent;
15011
+ const traceArgs = args[0].args;
15012
+ const parentComponents = SpanComponentsV4.fromStr(parent);
15013
+ const hasParentSpan = Boolean(
15014
+ parentComponents.data.row_id && parentComponents.data.span_id && parentComponents.data.root_span_id
15015
+ );
15016
+ const rootComponents = SpanComponentsV4.fromStr(state.root);
15017
+ const rowId = stringValue(rootComponents.data.row_id);
15018
+ const rootSpanId = stringValue(rootComponents.data.root_span_id);
15019
+ const spanId = stringValue(rootComponents.data.span_id);
15020
+ if (!rowId || !rootSpanId || !spanId) {
15021
+ throw new Error("OpenAI Agents trace root is invalid");
15022
+ }
15023
+ withCurrent(
15024
+ NOOP_SPAN,
15025
+ () => _internalStartSpanWithInitialMergeAndParentSpanIds(
15026
+ withSpanInstrumentationName(
15027
+ {
15028
+ name: "openai.agents.turn",
15029
+ type: "task" /* TASK */,
15030
+ parent,
15031
+ ...!hasParentSpan ? {
15032
+ parentSpanIds: {
15033
+ parentSpanIds: [],
15034
+ rootSpanId
15035
+ }
15036
+ } : {},
15037
+ spanId,
15038
+ startTime: state.startTime,
15039
+ event: {
15040
+ id: rowId,
15041
+ input: read2(traceArgs, "input"),
15042
+ metadata: traceMetadata(traceArgs)
15043
+ }
15044
+ },
15045
+ INSTRUMENTATION_NAMES.OPENAI
15046
+ )
15047
+ )
15048
+ );
15049
+ return state;
15050
+ } catch (error) {
15051
+ logInstrumentationError("could not start trace", error);
15052
+ return fallback2;
15053
+ }
15054
+ };
15055
+ var interceptOpenAIAgentsTraceCapture = async (target, thisArg, args) => {
15056
+ const fallback2 = await Reflect.apply(target, thisArg, args);
15057
+ if (!args[0].state) {
15058
+ return fallback2;
15059
+ }
15060
+ try {
15061
+ return await captureEvent(args[0].state, args[0].event);
15062
+ } catch (error) {
15063
+ logInstrumentationError("could not capture event", error);
15064
+ return fallback2;
15065
+ }
15066
+ };
15067
+ var interceptOpenAIAgentsTraceFail = async (target, thisArg, args) => {
15068
+ const fallback2 = await Reflect.apply(target, thisArg, args);
15069
+ if (!args[0].state) {
15070
+ return fallback2;
15071
+ }
15072
+ try {
15073
+ const next = copyState(args[0].state);
15074
+ await closeTrace(
15075
+ next,
15076
+ getCurrentUnixTimestamp(),
15077
+ loggedError(args[0].error, "OpenAI Agents request failed")
15078
+ );
15079
+ return next;
15080
+ } catch (error) {
15081
+ logInstrumentationError("could not fail trace", error);
15082
+ return fallback2;
15083
+ }
15084
+ };
15085
+
14411
15086
  // src/instrumentation/plugins/openai-plugin.ts
14412
15087
  var OpenAIPlugin = class extends BasePlugin {
14413
15088
  constructor() {
@@ -14415,6 +15090,13 @@ var OpenAIPlugin = class extends BasePlugin {
14415
15090
  }
14416
15091
  onEnable() {
14417
15092
  this.unsubscribers.push(
15093
+ openAIChannels.agentsTraceStart.intercept(
15094
+ interceptOpenAIAgentsTraceStart
15095
+ ),
15096
+ openAIChannels.agentsTraceCapture.intercept(
15097
+ interceptOpenAIAgentsTraceCapture
15098
+ ),
15099
+ openAIChannels.agentsTraceFail.intercept(interceptOpenAIAgentsTraceFail),
14418
15100
  openAIChannels.filesCreateTraced.intercept(
14419
15101
  interceptOpenAIFilesCreateTraced
14420
15102
  ),
@@ -14975,7 +15657,7 @@ async function* patchCodexEventStream(events, state) {
14975
15657
  try {
14976
15658
  await handleCodexEvent(state, event);
14977
15659
  } catch (error) {
14978
- logInstrumentationError("OpenAI Codex stream event", error);
15660
+ logInstrumentationError2("OpenAI Codex stream event", error);
14979
15661
  }
14980
15662
  yield event;
14981
15663
  }
@@ -15475,10 +16157,10 @@ function safeLog(span, event) {
15475
16157
  try {
15476
16158
  span.log(event);
15477
16159
  } catch (error) {
15478
- logInstrumentationError("OpenAI Codex span log", error);
16160
+ logInstrumentationError2("OpenAI Codex span log", error);
15479
16161
  }
15480
16162
  }
15481
- function logInstrumentationError(context, error) {
16163
+ function logInstrumentationError2(context, error) {
15482
16164
  debugLogger.error(`Error processing ${context}:`, error);
15483
16165
  }
15484
16166
 
@@ -16873,27 +17555,8 @@ function continuationParentFromCreateSessionParams(params) {
16873
17555
  }
16874
17556
  return context.parent;
16875
17557
  }
16876
- function exportSpanSynchronously(span) {
16877
- const parentInfo = span.getParentInfo();
16878
- if (!parentInfo) {
16879
- return void 0;
16880
- }
16881
- const objectId = parentInfo.objectId.getSync().value;
16882
- if (!objectId && !parentInfo.computeObjectMetadataArgs) {
16883
- return void 0;
16884
- }
16885
- return new SpanComponentsV4({
16886
- object_type: parentInfo.objectType,
16887
- ...objectId ? { object_id: objectId } : {
16888
- compute_object_metadata_args: parentInfo.computeObjectMetadataArgs ?? {}
16889
- },
16890
- row_id: span.id,
16891
- root_span_id: span.rootSpanId,
16892
- span_id: span.spanId
16893
- }).toStr();
16894
- }
16895
17558
  function exportedParent(parent) {
16896
- return typeof parent === "string" ? parent : exportSpanSynchronously(parent);
17559
+ return typeof parent === "string" ? parent : _internalExportParentSynchronously(parent);
16897
17560
  }
16898
17561
  function addSerializedContext(args) {
16899
17562
  if (!isObject(args.continuation) || args.sessionId === void 0) {
@@ -17650,16 +18313,16 @@ function braintrustAISDKTelemetry() {
17650
18313
  if (!toolCallId || !state) {
17651
18314
  return;
17652
18315
  }
17653
- const toolOutput = event.toolOutput;
18316
+ const toolOutput2 = event.toolOutput;
17654
18317
  const workflowToolError = event.success === false && "error" in event ? event.error : void 0;
17655
- if (toolOutput?.type === "tool-error" || workflowToolError !== void 0) {
17656
- const error = toolOutput?.error ?? workflowToolError;
18318
+ if (toolOutput2?.type === "tool-error" || workflowToolError !== void 0) {
18319
+ const error = toolOutput2?.error ?? workflowToolError;
17657
18320
  state.span.log({
17658
18321
  error: error instanceof Error ? error.message : String(error),
17659
18322
  metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
17660
18323
  });
17661
18324
  } else {
17662
- const output = toolOutput && "output" in toolOutput ? toolOutput.output : event.output;
18325
+ const output = toolOutput2 && "output" in toolOutput2 ? toolOutput2.output : event.output;
17663
18326
  state.span.log({
17664
18327
  ...shouldRecordOutputs(event) ? { output } : {},
17665
18328
  metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
@@ -20118,9 +20781,9 @@ function patchAISDKStreamingResult(args) {
20118
20781
  }
20119
20782
  finalize({ metrics, output });
20120
20783
  } catch (error) {
20121
- const loggedError = toLoggedError(error);
20784
+ const loggedError2 = toLoggedError(error);
20122
20785
  try {
20123
- span.log({ error: loggedError });
20786
+ span.log({ error: loggedError2 });
20124
20787
  } catch (loggingError) {
20125
20788
  debugLogger.error(
20126
20789
  "Error logging AI SDK streaming failure:",
@@ -20128,7 +20791,7 @@ function patchAISDKStreamingResult(args) {
20128
20791
  );
20129
20792
  }
20130
20793
  finalize({
20131
- error: error instanceof Error ? error : new Error(String(loggedError))
20794
+ error: error instanceof Error ? error : new Error(String(loggedError2))
20132
20795
  });
20133
20796
  }
20134
20797
  };
@@ -20241,9 +20904,9 @@ function patchAISDKStreamingResult(args) {
20241
20904
  }
20242
20905
  controller.enqueue(value);
20243
20906
  } catch (error) {
20244
- const loggedError = toLoggedError(error);
20907
+ const loggedError2 = toLoggedError(error);
20245
20908
  try {
20246
- span.log({ error: loggedError });
20909
+ span.log({ error: loggedError2 });
20247
20910
  } catch (loggingError) {
20248
20911
  debugLogger.error(
20249
20912
  "Error logging AI SDK base stream failure:",
@@ -20251,7 +20914,7 @@ function patchAISDKStreamingResult(args) {
20251
20914
  );
20252
20915
  }
20253
20916
  finalize({
20254
- error: error instanceof Error ? error : new Error(String(loggedError))
20917
+ error: error instanceof Error ? error : new Error(String(loggedError2))
20255
20918
  });
20256
20919
  controller.error(error);
20257
20920
  }
@@ -23145,7 +23808,7 @@ function wrapSendOptionsCallbacks(options, state) {
23145
23808
  try {
23146
23809
  await handleInteractionUpdate(state, args.update);
23147
23810
  } catch (error) {
23148
- logInstrumentationError2("Cursor SDK onDelta", error);
23811
+ logInstrumentationError3("Cursor SDK onDelta", error);
23149
23812
  }
23150
23813
  if (originalOnDelta) {
23151
23814
  return originalOnDelta(args);
@@ -23155,7 +23818,7 @@ function wrapSendOptionsCallbacks(options, state) {
23155
23818
  try {
23156
23819
  handleStepUpdate(state, args.step);
23157
23820
  } catch (error) {
23158
- logInstrumentationError2("Cursor SDK onStep", error);
23821
+ logInstrumentationError3("Cursor SDK onStep", error);
23159
23822
  }
23160
23823
  if (originalOnStep) {
23161
23824
  return originalOnStep(args);
@@ -23237,7 +23900,7 @@ async function* patchCursorStream(stream, state) {
23237
23900
  try {
23238
23901
  await handleStreamMessage2(state, message);
23239
23902
  } catch (error) {
23240
- logInstrumentationError2("Cursor SDK stream", error);
23903
+ logInstrumentationError3("Cursor SDK stream", error);
23241
23904
  }
23242
23905
  yield message;
23243
23906
  }
@@ -23301,7 +23964,7 @@ async function handleToolUpdate(state, update) {
23301
23964
  if (!state.activeToolSpans.has(callId)) {
23302
23965
  state.activeToolSpans.set(
23303
23966
  callId,
23304
- await startToolSpan(state, {
23967
+ await startToolSpan2(state, {
23305
23968
  args,
23306
23969
  callId,
23307
23970
  name,
@@ -23312,7 +23975,7 @@ async function handleToolUpdate(state, update) {
23312
23975
  }
23313
23976
  return;
23314
23977
  }
23315
- const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan(state, {
23978
+ const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan2(state, {
23316
23979
  args,
23317
23980
  callId,
23318
23981
  name,
@@ -23349,7 +24012,7 @@ async function handleStreamMessage2(state, message) {
23349
24012
  } else if (block?.type === "tool_use" && block.id) {
23350
24013
  state.activeToolSpans.set(
23351
24014
  block.id,
23352
- await startToolSpan(state, {
24015
+ await startToolSpan2(state, {
23353
24016
  args: block.input,
23354
24017
  callId: block.id,
23355
24018
  name: block.name,
@@ -23384,7 +24047,7 @@ async function handleToolMessage(state, message) {
23384
24047
  if (!state.activeToolSpans.has(callId)) {
23385
24048
  state.activeToolSpans.set(
23386
24049
  callId,
23387
- await startToolSpan(state, {
24050
+ await startToolSpan2(state, {
23388
24051
  args: message.args,
23389
24052
  callId,
23390
24053
  name: message.name,
@@ -23395,7 +24058,7 @@ async function handleToolMessage(state, message) {
23395
24058
  }
23396
24059
  return;
23397
24060
  }
23398
- const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan(state, {
24061
+ const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan2(state, {
23399
24062
  args: message.args,
23400
24063
  callId,
23401
24064
  name: message.name,
@@ -23422,7 +24085,7 @@ async function handleConversation(state, turns) {
23422
24085
  const command = turn.turn?.shellCommand?.command;
23423
24086
  if (command) {
23424
24087
  const callId = `shell:${state.activeToolSpans.size}:${command}`;
23425
- const toolState = await startToolSpan(state, {
24088
+ const toolState = await startToolSpan2(state, {
23426
24089
  args: turn.turn?.shellCommand,
23427
24090
  callId,
23428
24091
  name: "shell",
@@ -23446,7 +24109,7 @@ async function handleConversationStep(state, step) {
23446
24109
  }
23447
24110
  const toolCall = step.message;
23448
24111
  const callId = typeof toolCall?.callId === "string" ? toolCall.callId : `conversation-tool:${state.activeToolSpans.size}`;
23449
- const toolState = await startToolSpan(state, {
24112
+ const toolState = await startToolSpan2(state, {
23450
24113
  args: extractToolArgs(toolCall),
23451
24114
  callId,
23452
24115
  name: extractToolName(toolCall),
@@ -23477,7 +24140,7 @@ function handleStepUpdate(state, step) {
23477
24140
  state.stepText.push(step.message.text);
23478
24141
  }
23479
24142
  }
23480
- async function startToolSpan(state, args) {
24143
+ async function startToolSpan2(state, args) {
23481
24144
  const name = args.name || "unknown";
23482
24145
  const metadata = {
23483
24146
  "cursor_sdk.tool.status": args.status,
@@ -23764,10 +24427,10 @@ function safeLog2(span, event) {
23764
24427
  try {
23765
24428
  span.log(event);
23766
24429
  } catch (error) {
23767
- logInstrumentationError2("Cursor SDK span log", error);
24430
+ logInstrumentationError3("Cursor SDK span log", error);
23768
24431
  }
23769
24432
  }
23770
- function logInstrumentationError2(context, error) {
24433
+ function logInstrumentationError3(context, error) {
23771
24434
  debugLogger.error(`Error processing ${context}:`, error);
23772
24435
  }
23773
24436
  function cleanMetrics2(metrics) {
@@ -24605,6 +25268,10 @@ var googleGenAIChannels = defineChannels(
24605
25268
  channelName: "models.embedContent",
24606
25269
  kind: "async"
24607
25270
  }),
25271
+ httpResponseJson: channel({
25272
+ channelName: "httpResponse.json",
25273
+ kind: "async"
25274
+ }),
24608
25275
  interactionsCreate: channel({
24609
25276
  channelName: "interactions.create",
24610
25277
  kind: "async"
@@ -24753,13 +25420,45 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24753
25420
  subscribeToEmbedContentChannel() {
24754
25421
  const tracingChannel = googleGenAIChannels.embedContent.tracingChannel();
24755
25422
  const states = /* @__PURE__ */ new WeakMap();
25423
+ const embeddingSpans = /* @__PURE__ */ new WeakSet();
25424
+ this.unsubscribers.push(
25425
+ googleGenAIChannels.httpResponseJson.intercept(
25426
+ (target, thisArg, args) => {
25427
+ const span = currentSpan();
25428
+ const result = Reflect.apply(target, thisArg, args);
25429
+ if (embeddingSpans.has(span)) {
25430
+ void Promise.resolve(result).then(
25431
+ (response) => {
25432
+ try {
25433
+ const metrics = cleanMetrics3(
25434
+ extractEmbedContentMetrics(response)
25435
+ );
25436
+ if (embeddingSpans.has(span) && Object.keys(metrics).length > 0) {
25437
+ span.log({ metrics });
25438
+ }
25439
+ } catch (error) {
25440
+ debugLogger.error(
25441
+ "Error reading Google GenAI embedding usage:",
25442
+ error
25443
+ );
25444
+ }
25445
+ },
25446
+ () => {
25447
+ }
25448
+ // The embedding channel handles the original rejection.
25449
+ );
25450
+ }
25451
+ return result;
25452
+ }
25453
+ )
25454
+ );
24756
25455
  const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
24757
25456
  tracingChannel,
24758
25457
  states,
24759
25458
  (event) => {
24760
25459
  const params = event.arguments[0];
24761
25460
  const input = serializeEmbedContentInput(params);
24762
- const metadata = extractEmbedContentMetadata(params);
25461
+ const metadata = { provider: "google", model: params.model };
24763
25462
  const span = startSpan(
24764
25463
  withSpanInstrumentationName(
24765
25464
  {
@@ -24772,6 +25471,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24772
25471
  INSTRUMENTATION_NAMES.GOOGLE_GENAI
24773
25472
  )
24774
25473
  );
25474
+ embeddingSpans.add(span);
24775
25475
  return {
24776
25476
  span,
24777
25477
  startTime: getCurrentUnixTimestamp()
@@ -24783,7 +25483,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24783
25483
  ensureSpanState(states, event, () => {
24784
25484
  const params = event.arguments[0];
24785
25485
  const input = serializeEmbedContentInput(params);
24786
- const metadata = extractEmbedContentMetadata(params);
25486
+ const metadata = { provider: "google", model: params.model };
24787
25487
  const span = startSpan(
24788
25488
  withSpanInstrumentationName(
24789
25489
  {
@@ -24796,6 +25496,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24796
25496
  INSTRUMENTATION_NAMES.GOOGLE_GENAI
24797
25497
  )
24798
25498
  );
25499
+ embeddingSpans.add(span);
24799
25500
  return {
24800
25501
  span,
24801
25502
  startTime: getCurrentUnixTimestamp()
@@ -24808,20 +25509,28 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24808
25509
  return;
24809
25510
  }
24810
25511
  try {
24811
- const output = summarizeEmbedContentOutput(event.result);
24812
25512
  spanState.span.log({
24813
- ...output ? { output } : {},
25513
+ output: summarizeEmbedContentOutput(event.result),
24814
25514
  metrics: cleanMetrics3(
24815
25515
  extractEmbedContentMetrics(event.result, spanState.startTime)
24816
25516
  )
24817
25517
  });
24818
25518
  } finally {
25519
+ embeddingSpans.delete(spanState.span);
24819
25520
  spanState.span.end();
24820
25521
  states.delete(event);
24821
25522
  }
24822
25523
  },
24823
25524
  error: (event) => {
24824
- logErrorAndEndSpan(states, event);
25525
+ const spanState = states.get(event);
25526
+ if (!spanState) return;
25527
+ try {
25528
+ spanState.span.log({ error: event.error, output: { count: 0 } });
25529
+ } finally {
25530
+ embeddingSpans.delete(spanState.span);
25531
+ spanState.span.end();
25532
+ states.delete(event);
25533
+ }
24825
25534
  }
24826
25535
  };
24827
25536
  tracingChannel.subscribe(handlers);
@@ -25056,15 +25765,53 @@ function serializeGenerateContentInput(params) {
25056
25765
  return input;
25057
25766
  }
25058
25767
  function serializeEmbedContentInput(params) {
25768
+ let contents = Array.isArray(params.contents) ? params.contents : [params.contents];
25769
+ if (params.model.includes("gemini-embedding-2") && contents.length > 0 && contents.every(
25770
+ (content) => typeof content === "string" || !Array.isArray(content) && !("parts" in content)
25771
+ )) {
25772
+ contents = [contents];
25773
+ }
25059
25774
  const input = {
25060
- model: params.model,
25061
- contents: serializeContentCollection(params.contents)
25775
+ inputs: contents.map((content) => {
25776
+ const parts = typeof content === "string" ? [content] : Array.isArray(content) ? content : "parts" in content ? content.parts : [content];
25777
+ const normalized = parts.flatMap((part) => {
25778
+ if (typeof part === "string") return [{ type: "text", text: part }];
25779
+ if (part.text !== void 0) return [{ type: "text", text: part.text }];
25780
+ const media = part.inlineData ?? part.fileData;
25781
+ if (!media) return [];
25782
+ const data = "data" in media ? `data:${media.mimeType};base64,${typeof media.data === "string" ? media.data : uint8ArrayToBase64(media.data)}` : media.fileUri;
25783
+ return media.mimeType?.startsWith("image/") ? [{ type: "image_url", image_url: { url: data } }] : [
25784
+ {
25785
+ type: "file",
25786
+ file: {
25787
+ file_data: data,
25788
+ ..."displayName" in media && media.displayName ? { filename: media.displayName } : {}
25789
+ }
25790
+ }
25791
+ ];
25792
+ });
25793
+ return {
25794
+ content: normalized.length === 1 && normalized[0].type === "text" ? normalized[0].text : normalized
25795
+ };
25796
+ }),
25797
+ ...params.config?.outputDimensionality !== void 0 ? { output_dimensions: params.config.outputDimensionality } : {}
25062
25798
  };
25063
- const config = params.config ? tryToDict(params.config) : null;
25064
- if (config) {
25065
- input.config = config;
25799
+ try {
25800
+ const processed = processInputAttachments(input);
25801
+ const hasInlineMedia = processed.inputs.some(
25802
+ ({ content }) => Array.isArray(content) && content.some((part) => {
25803
+ const data = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
25804
+ return typeof data === "string" && data.startsWith("data:");
25805
+ })
25806
+ );
25807
+ return hasInlineMedia ? input : processed;
25808
+ } catch (error) {
25809
+ debugLogger.error(
25810
+ "Error processing Google GenAI embedding attachments:",
25811
+ error
25812
+ );
25813
+ return input;
25066
25814
  }
25067
- return input;
25068
25815
  }
25069
25816
  function serializeInteractionInput(params) {
25070
25817
  const input = {
@@ -25252,19 +25999,6 @@ function extractGenerateContentMetadata(params) {
25252
25999
  }
25253
26000
  return metadata;
25254
26001
  }
25255
- function extractEmbedContentMetadata(params) {
25256
- const metadata = {};
25257
- if (params.model) {
25258
- metadata.model = params.model;
25259
- }
25260
- const config = params.config ? tryToDict(params.config) : null;
25261
- if (config) {
25262
- Object.keys(config).forEach((key) => {
25263
- metadata[key] = config[key];
25264
- });
25265
- }
25266
- return metadata;
25267
- }
25268
26002
  function extractGenerateContentMetrics(response, startTime) {
25269
26003
  const metrics = {};
25270
26004
  if (startTime !== void 0) {
@@ -25284,15 +26018,23 @@ function extractEmbedContentMetrics(response, startTime) {
25284
26018
  const end = getCurrentUnixTimestamp();
25285
26019
  metrics.start = startTime;
25286
26020
  metrics.end = end;
25287
- metrics.duration = end - startTime;
25288
- }
25289
- if (response?.usageMetadata) {
25290
- populateUsageMetrics(metrics, response.usageMetadata);
25291
26021
  }
25292
26022
  const embeddingTokenCount = extractEmbedPromptTokenCount(response);
25293
26023
  if (embeddingTokenCount !== void 0) {
25294
26024
  metrics.prompt_tokens = embeddingTokenCount;
25295
- metrics.tokens = embeddingTokenCount;
26025
+ }
26026
+ const totalTokens = response?.usageMetadata?.totalTokenCount ?? embeddingTokenCount;
26027
+ if (totalTokens !== void 0) {
26028
+ metrics.tokens = totalTokens;
26029
+ }
26030
+ const audioTokens = (response?.usageMetadata?.promptTokenDetails ?? response?.usageMetadata?.promptTokensDetails)?.filter(
26031
+ (detail) => detail.modality === "AUDIO" && detail.tokenCount !== void 0
26032
+ );
26033
+ if (audioTokens?.length) {
26034
+ metrics.prompt_audio_tokens = audioTokens.reduce(
26035
+ (sum, detail) => sum + (detail.tokenCount ?? 0),
26036
+ 0
26037
+ );
25296
26038
  }
25297
26039
  return metrics;
25298
26040
  }
@@ -25331,41 +26073,25 @@ function extractEmbedPromptTokenCount(response) {
25331
26073
  if (typeof usagePromptTokens === "number" && Number.isFinite(usagePromptTokens)) {
25332
26074
  return usagePromptTokens;
25333
26075
  }
25334
- const usageTotalTokens = response.usageMetadata?.totalTokenCount;
25335
- if (typeof usageTotalTokens === "number" && Number.isFinite(usageTotalTokens)) {
25336
- return usageTotalTokens;
25337
- }
25338
26076
  const embeddings = Array.isArray(response.embeddings) ? response.embeddings : response.embedding ? [response.embedding] : [];
25339
26077
  if (embeddings.length === 0) {
25340
26078
  return void 0;
25341
26079
  }
25342
26080
  let total = 0;
25343
- let sawAny = false;
25344
26081
  for (const embedding of embeddings) {
25345
26082
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
25346
26083
  const tokenCount2 = embeddingStats?.tokenCount;
25347
26084
  if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
25348
26085
  total += tokenCount2;
25349
- sawAny = true;
26086
+ } else {
26087
+ return void 0;
25350
26088
  }
25351
26089
  }
25352
- return sawAny ? total : void 0;
26090
+ return total;
25353
26091
  }
25354
26092
  function summarizeEmbedContentOutput(response) {
25355
- if (!response) {
25356
- return void 0;
25357
- }
25358
- const embeddings = Array.isArray(response.embeddings) ? response.embeddings : response.embedding ? [response.embedding] : [];
25359
- if (embeddings.length === 0) {
25360
- return void 0;
25361
- }
25362
- const firstValues = embeddings[0]?.values;
25363
- if (!Array.isArray(firstValues)) {
25364
- return void 0;
25365
- }
25366
26093
  return {
25367
- embedding_count: embeddings.length,
25368
- embedding_length: firstValues.length
26094
+ count: Array.isArray(response?.embeddings) ? response.embeddings.length : response?.embedding ? 1 : 0
25369
26095
  };
25370
26096
  }
25371
26097
  function populateUsageMetrics(metrics, usage) {
@@ -28992,6 +29718,379 @@ function aggregateMistralStreamChunks(chunks) {
28992
29718
  };
28993
29719
  }
28994
29720
 
29721
+ // src/instrumentation/plugins/langgraph-sdk-channels.ts
29722
+ var langGraphSDKChannels = defineChannels(
29723
+ "@langchain/langgraph-sdk",
29724
+ {
29725
+ wait: channel({
29726
+ channelName: "runs.wait",
29727
+ kind: "async"
29728
+ }),
29729
+ stream: channel({
29730
+ channelName: "runs.stream",
29731
+ kind: "sync-stream"
29732
+ })
29733
+ },
29734
+ { instrumentationName: INSTRUMENTATION_NAMES.LANGGRAPH_SDK }
29735
+ );
29736
+
29737
+ // src/instrumentation/plugins/langgraph-sdk-plugin.ts
29738
+ var LangGraphSDKPlugin = class extends BasePlugin {
29739
+ onEnable() {
29740
+ this.unsubscribers.push(
29741
+ langGraphSDKChannels.wait.intercept(
29742
+ (target, self, args) => instrumentRun("wait", args, () => Reflect.apply(target, self, args))
29743
+ ),
29744
+ langGraphSDKChannels.stream.intercept(
29745
+ (target, self, args) => instrumentRun("stream", args, () => Reflect.apply(target, self, args))
29746
+ )
29747
+ );
29748
+ }
29749
+ onDisable() {
29750
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
29751
+ }
29752
+ };
29753
+ function normalizeMessage(value) {
29754
+ if (!isObject(value)) return value;
29755
+ const role = value.role ?? (value.type === "human" ? "user" : value.type === "ai" || value.type === "AIMessageChunk" ? "assistant" : value.type === "system" || value.type === "tool" || value.type === "function" ? value.type : void 0);
29756
+ if (typeof role !== "string") return value;
29757
+ const message = {
29758
+ role,
29759
+ content: value.content ?? ""
29760
+ };
29761
+ for (const key of ["name", "tool_call_id", "refusal"]) {
29762
+ if (value[key] !== void 0) message[key] = value[key];
29763
+ }
29764
+ const additional = isObject(value.additional_kwargs) ? value.additional_kwargs : {};
29765
+ const toolCalls2 = Array.isArray(value.tool_calls) && value.tool_calls.length ? value.tool_calls : additional.tool_calls;
29766
+ if (Array.isArray(toolCalls2) && toolCalls2.length > 0) {
29767
+ message.tool_calls = toolCalls2.map((call) => {
29768
+ if (!isObject(call)) return call;
29769
+ if (isObject(call.function)) return call;
29770
+ return {
29771
+ id: call.id,
29772
+ type: "function",
29773
+ function: {
29774
+ name: call.name,
29775
+ arguments: typeof call.args === "string" ? call.args : JSON.stringify(call.args ?? {})
29776
+ }
29777
+ };
29778
+ });
29779
+ }
29780
+ if (Array.isArray(value.invalid_tool_calls) && value.invalid_tool_calls.length > 0)
29781
+ message.invalid_tool_calls = value.invalid_tool_calls;
29782
+ if (message.refusal === void 0 && additional.refusal !== void 0)
29783
+ message.refusal = additional.refusal;
29784
+ return message;
29785
+ }
29786
+ function normalizeRunError(value) {
29787
+ let name;
29788
+ let message;
29789
+ if (value instanceof Error) {
29790
+ name = value.name;
29791
+ message = value.message;
29792
+ } else if (isObject(value) && typeof value.error === "string" && typeof value.message === "string") {
29793
+ name = value.error;
29794
+ message = value.message;
29795
+ } else {
29796
+ return value;
29797
+ }
29798
+ for (let depth = 0; depth < 3; depth++) {
29799
+ try {
29800
+ const nested = JSON.parse(
29801
+ message.startsWith(`${name}: `) ? message.slice(name.length + 2) : message
29802
+ );
29803
+ if (!isObject(nested) || typeof nested.error !== "string" || typeof nested.message !== "string")
29804
+ break;
29805
+ name = nested.error;
29806
+ message = nested.message;
29807
+ } catch {
29808
+ break;
29809
+ }
29810
+ }
29811
+ if (value instanceof Error && name === value.name && message === value.message)
29812
+ return value;
29813
+ return Object.assign(new Error(message), { name });
29814
+ }
29815
+ function normalizeState(value) {
29816
+ if (!isObject(value)) return value;
29817
+ return Object.fromEntries(
29818
+ Object.entries(value).map(([key, field]) => {
29819
+ if (key === "messages" && Array.isArray(field))
29820
+ return [key, field.map(normalizeMessage)];
29821
+ if (key === "__error__") {
29822
+ const error = normalizeRunError(field);
29823
+ if (error instanceof Error)
29824
+ return [key, { error: error.name, message: error.message }];
29825
+ }
29826
+ return [key, field];
29827
+ })
29828
+ );
29829
+ }
29830
+ function normalizeRunOutput(value, input) {
29831
+ if (!isObject(value)) return value;
29832
+ if (Array.isArray(value.messages)) {
29833
+ if (value.__interrupt__ !== void 0 || value.__error__ !== void 0)
29834
+ return void 0;
29835
+ const inputMessages = isObject(input) && Array.isArray(input.messages) ? input.messages : [];
29836
+ let inputPrefixLength = 0;
29837
+ while (inputPrefixLength < inputMessages.length) {
29838
+ const previous = inputMessages[inputPrefixLength];
29839
+ const message = value.messages[inputPrefixLength];
29840
+ if (isObject(previous) && isObject(message) && previous.id !== void 0 && message.id !== void 0 && previous.id !== message.id || JSON.stringify(normalizeMessage(previous)) !== JSON.stringify(normalizeMessage(message)))
29841
+ break;
29842
+ inputPrefixLength++;
29843
+ }
29844
+ for (let index = value.messages.length - 1; index >= inputPrefixLength; index--) {
29845
+ const message = value.messages[index];
29846
+ const normalized = normalizeMessage(message);
29847
+ if (!isObject(normalized)) continue;
29848
+ if (normalized.role === "user") return void 0;
29849
+ if (normalized.role !== "assistant") continue;
29850
+ if (inputMessages.some((previous) => {
29851
+ if (!isObject(previous) || !isObject(message)) return false;
29852
+ return previous.id !== void 0 && previous.id === message.id && JSON.stringify(normalizeMessage(previous)) === JSON.stringify(normalized);
29853
+ }))
29854
+ continue;
29855
+ return normalized;
29856
+ }
29857
+ return void 0;
29858
+ }
29859
+ const result = Object.fromEntries(
29860
+ Object.entries(value).filter(
29861
+ ([key]) => key !== "__interrupt__" && key !== "__error__"
29862
+ )
29863
+ );
29864
+ return !Object.keys(result).length && (value.__interrupt__ !== void 0 || value.__error__ !== void 0) ? void 0 : result;
29865
+ }
29866
+ function instrumentRun(operation, [threadId, assistantId, options], invoke2) {
29867
+ if (isAutoInstrumentationSuppressed()) return invoke2();
29868
+ const start = getCurrentUnixTimestamp();
29869
+ let span;
29870
+ try {
29871
+ const metadata = {
29872
+ "langgraph.thread_id": threadId,
29873
+ "langgraph.assistant_id": assistantId
29874
+ };
29875
+ for (const key of [
29876
+ "streamMode",
29877
+ "streamSubgraphs",
29878
+ "interruptBefore",
29879
+ "interruptAfter",
29880
+ "multitaskStrategy",
29881
+ "durability"
29882
+ ]) {
29883
+ if (options?.[key] !== void 0) metadata[key] = options[key];
29884
+ }
29885
+ span = startSpan(
29886
+ withSpanInstrumentationName(
29887
+ {
29888
+ name: `langgraph.runs.${operation}`,
29889
+ spanAttributes: { type: "task" /* TASK */ },
29890
+ event: {
29891
+ input: options?.command === void 0 ? normalizeState(options?.input) : {
29892
+ input: normalizeState(options.input),
29893
+ command: options.command
29894
+ },
29895
+ metadata
29896
+ }
29897
+ },
29898
+ INSTRUMENTATION_NAMES.LANGGRAPH_SDK
29899
+ )
29900
+ );
29901
+ } catch (error) {
29902
+ debugLogger.error("Error starting LangGraph SDK span:", error);
29903
+ return invoke2();
29904
+ }
29905
+ let ended = false;
29906
+ let output;
29907
+ let streamError;
29908
+ let firstToken;
29909
+ const updates = [];
29910
+ const usageByMessage = /* @__PURE__ */ new Map();
29911
+ const captureUsage = (id, usage) => {
29912
+ if (!isObject(usage)) return;
29913
+ const metrics = {};
29914
+ for (const [source, destination] of [
29915
+ ["input_tokens", "prompt_tokens"],
29916
+ ["output_tokens", "completion_tokens"],
29917
+ ["total_tokens", "tokens"]
29918
+ ]) {
29919
+ const value = usage[source];
29920
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0)
29921
+ metrics[destination] = value;
29922
+ }
29923
+ if (metrics.tokens === void 0 && metrics.prompt_tokens !== void 0 && metrics.completion_tokens !== void 0)
29924
+ metrics.tokens = metrics.prompt_tokens + metrics.completion_tokens;
29925
+ usageByMessage.set(id, { ...usageByMessage.get(id), ...metrics });
29926
+ };
29927
+ const messages = /* @__PURE__ */ new Map();
29928
+ const messageSnapshots = /* @__PURE__ */ new Map();
29929
+ const finish = (error) => {
29930
+ if (ended) return;
29931
+ ended = true;
29932
+ try {
29933
+ const metrics = {};
29934
+ for (const usage of usageByMessage.values()) {
29935
+ for (const [key, value] of Object.entries(usage))
29936
+ metrics[key] = (metrics[key] ?? 0) + value;
29937
+ }
29938
+ if (firstToken !== void 0)
29939
+ metrics.time_to_first_token = firstToken - start;
29940
+ const finalMessages = [
29941
+ ...new Map([...messages, ...messageSnapshots]).values()
29942
+ ];
29943
+ let loggedOutput = normalizeRunOutput(output, options?.input);
29944
+ if (loggedOutput === void 0 && finalMessages.length)
29945
+ loggedOutput = normalizeRunOutput(
29946
+ { messages: finalMessages },
29947
+ void 0
29948
+ );
29949
+ if (output === void 0 && !finalMessages.length && updates.length) {
29950
+ const results = updates.map((update) => normalizeRunOutput(update, options?.input)).filter((update) => update !== void 0);
29951
+ if (results.length) loggedOutput = { updates: results };
29952
+ }
29953
+ const interrupted = [output, ...updates].find(
29954
+ (state) => isObject(state) && state.__interrupt__ !== void 0
29955
+ );
29956
+ span.log({
29957
+ ...loggedOutput !== void 0 ? { output: loggedOutput } : {},
29958
+ ...isObject(interrupted) ? { metadata: { "langgraph.interrupts": interrupted.__interrupt__ } } : {},
29959
+ ...error !== void 0 || streamError !== void 0 ? { error: normalizeRunError(error ?? streamError) } : {},
29960
+ metrics
29961
+ });
29962
+ } catch (error2) {
29963
+ debugLogger.error("Error logging LangGraph SDK span:", error2);
29964
+ }
29965
+ try {
29966
+ span.end();
29967
+ } catch (error2) {
29968
+ debugLogger.error("Error ending LangGraph SDK span:", error2);
29969
+ }
29970
+ };
29971
+ const observeMessages = (value, streaming) => {
29972
+ if (!isObject(value) || !Array.isArray(value.messages)) return;
29973
+ const inputMessages = isObject(options?.input) && Array.isArray(options.input.messages) ? options.input.messages : [];
29974
+ for (const message of value.messages) {
29975
+ if (!isObject(message) || message.type !== "ai" && message.role !== "assistant")
29976
+ continue;
29977
+ if (message.id !== void 0 && inputMessages.some(
29978
+ (input) => isObject(input) && input.id === message.id
29979
+ ))
29980
+ continue;
29981
+ captureUsage(
29982
+ typeof message.id === "string" ? message.id : "message",
29983
+ message.usage_metadata
29984
+ );
29985
+ if (streaming && (typeof message.content === "string" ? message.content.length > 0 : Array.isArray(message.content) && message.content.some(
29986
+ (part) => isObject(part) && typeof part.text === "string" && part.text.length > 0
29987
+ )))
29988
+ firstToken ??= getCurrentUnixTimestamp();
29989
+ }
29990
+ };
29991
+ const onChunk = ({ event, data }) => {
29992
+ if (ended) return;
29993
+ if (event === "metadata" && isObject(data)) {
29994
+ if (typeof data.run_id === "string")
29995
+ span.log({ metadata: { "langgraph.run_id": data.run_id } });
29996
+ } else if (event === "error") {
29997
+ streamError = normalizeRunError(data);
29998
+ } else if (event === "values") {
29999
+ output = data;
30000
+ observeMessages(data, true);
30001
+ } else if (event === "updates") {
30002
+ if (isObject(data)) {
30003
+ const stateUpdates = [];
30004
+ for (const [node, update] of Object.entries(data)) {
30005
+ observeMessages(update, true);
30006
+ if (isObject(update) && Array.isArray(update.messages)) {
30007
+ for (const message of update.messages) {
30008
+ if (isObject(message))
30009
+ messageSnapshots.set(
30010
+ typeof message.id === "string" ? message.id : `update-${messageSnapshots.size}`,
30011
+ message
30012
+ );
30013
+ }
30014
+ const state = Object.fromEntries(
30015
+ Object.entries(update).filter(([key]) => key !== "messages")
30016
+ );
30017
+ if (Object.keys(state).length) stateUpdates.push([node, state]);
30018
+ } else {
30019
+ stateUpdates.push([node, update]);
30020
+ }
30021
+ }
30022
+ if (stateUpdates.length) updates.push(Object.fromEntries(stateUpdates));
30023
+ } else {
30024
+ updates.push(data);
30025
+ }
30026
+ } else if ((event === "messages" || event === "messages/partial" || event === "messages/complete") && Array.isArray(data)) {
30027
+ const parts = event === "messages" ? [data[0]] : data;
30028
+ for (const part of parts) {
30029
+ if (!isObject(part)) continue;
30030
+ const id = typeof part.id === "string" ? part.id : "message";
30031
+ captureUsage(id, part.usage_metadata);
30032
+ const previous = messages.get(id);
30033
+ messages.set(
30034
+ id,
30035
+ event === "messages" && previous && typeof part.content === "string" && typeof previous.content === "string" ? { ...part, content: previous.content + part.content } : part
30036
+ );
30037
+ if (typeof part.content === "string" && part.content.length > 0)
30038
+ firstToken ??= getCurrentUnixTimestamp();
30039
+ }
30040
+ }
30041
+ };
30042
+ let result;
30043
+ try {
30044
+ result = withCurrent(
30045
+ span,
30046
+ () => runWithAutoInstrumentationSuppressed(invoke2)
30047
+ );
30048
+ } catch (error) {
30049
+ finish(error);
30050
+ throw error;
30051
+ }
30052
+ if (operation === "stream") {
30053
+ try {
30054
+ patchStreamIfNeeded(result, {
30055
+ shouldCollect: (chunk) => {
30056
+ try {
30057
+ onChunk(chunk);
30058
+ } catch (error) {
30059
+ debugLogger.error(
30060
+ "Error processing LangGraph stream event:",
30061
+ error
30062
+ );
30063
+ }
30064
+ return false;
30065
+ },
30066
+ aroundNext: (next) => withCurrent(span, () => runWithAutoInstrumentationSuppressed(next)),
30067
+ onComplete: () => finish(),
30068
+ onCancel: () => finish(),
30069
+ onError: (error) => finish(error)
30070
+ });
30071
+ } catch (error) {
30072
+ debugLogger.error("Error observing LangGraph stream:", error);
30073
+ finish();
30074
+ }
30075
+ } else {
30076
+ void Promise.resolve(result).then(
30077
+ (value) => {
30078
+ try {
30079
+ output = value;
30080
+ observeMessages(value, false);
30081
+ if (isObject(value) && isObject(value.__error__))
30082
+ streamError = normalizeRunError(value.__error__);
30083
+ finish();
30084
+ } catch (error) {
30085
+ finish(error);
30086
+ }
30087
+ },
30088
+ (error) => finish(error)
30089
+ );
30090
+ }
30091
+ return result;
30092
+ }
30093
+
28995
30094
  // src/instrumentation/plugins/ollama-channels.ts
28996
30095
  var ollamaChannels = defineChannels(
28997
30096
  "ollama",
@@ -29201,7 +30300,7 @@ function normalizeTextAndImages(content, images) {
29201
30300
  ...unrecognizedImages.length > 0 ? { unrecognizedImages } : {}
29202
30301
  };
29203
30302
  }
29204
- function normalizeMessage(message, toolCallId, syntheticToolCallIdOffset = 0) {
30303
+ function normalizeMessage2(message, toolCallId, syntheticToolCallIdOffset = 0) {
29205
30304
  if (typeof message.role !== "string") {
29206
30305
  return void 0;
29207
30306
  }
@@ -29247,7 +30346,7 @@ function normalizeMessages(messages) {
29247
30346
  toolCallId = pendingToolCallIds.get(toolName)?.shift();
29248
30347
  }
29249
30348
  }
29250
- const normalized = normalizeMessage(
30349
+ const normalized = normalizeMessage2(
29251
30350
  ollamaMessage,
29252
30351
  toolCallId,
29253
30352
  syntheticToolCallIdOffset
@@ -29366,7 +30465,7 @@ function extractOllamaChatOutput(result, syntheticToolCallIdOffset = 0) {
29366
30465
  if (!isObject(result) || !isObject(result.message)) {
29367
30466
  return void 0;
29368
30467
  }
29369
- const message = normalizeMessage(
30468
+ const message = normalizeMessage2(
29370
30469
  result.message,
29371
30470
  void 0,
29372
30471
  syntheticToolCallIdOffset
@@ -32086,14 +33185,14 @@ function extractActionSpanMetadata(args) {
32086
33185
  const options = extractRunInNewSpanOptions(args);
32087
33186
  const labels = isObject(options?.labels) ? options.labels : void 0;
32088
33187
  const metadata = isObject(options?.metadata) ? options.metadata : void 0;
32089
- const actionType = stringValue(labels?.["genkit:metadata:subtype"]);
32090
- const name = stringValue(metadata?.name);
33188
+ const actionType = stringValue2(labels?.["genkit:metadata:subtype"]);
33189
+ const name = stringValue2(metadata?.name);
32091
33190
  if (!actionType || !name) {
32092
33191
  return void 0;
32093
33192
  }
32094
33193
  return {
32095
33194
  actionType,
32096
- key: stringValue(labels?.["genkit:key"]),
33195
+ key: stringValue2(labels?.["genkit:key"]),
32097
33196
  name
32098
33197
  };
32099
33198
  }
@@ -32203,7 +33302,7 @@ function pickNumberMetrics(values) {
32203
33302
  })
32204
33303
  );
32205
33304
  }
32206
- function stringValue(value) {
33305
+ function stringValue2(value) {
32207
33306
  return typeof value === "string" ? value : void 0;
32208
33307
  }
32209
33308
 
@@ -32888,7 +33987,7 @@ function subscribeToFlueContext(value, state) {
32888
33987
  try {
32889
33988
  unsubscribe?.();
32890
33989
  } catch (error) {
32891
- logInstrumentationError3("Flue context unsubscribe", error);
33990
+ logInstrumentationError4("Flue context unsubscribe", error);
32892
33991
  }
32893
33992
  };
32894
33993
  try {
@@ -32904,7 +34003,7 @@ function subscribeToFlueContext(value, state) {
32904
34003
  });
32905
34004
  state.contexts.add(value);
32906
34005
  } catch (error) {
32907
- logInstrumentationError3("Flue context subscription", error);
34006
+ logInstrumentationError4("Flue context subscription", error);
32908
34007
  }
32909
34008
  }
32910
34009
  function isAutoContextTerminalEvent(event, ctx) {
@@ -32960,7 +34059,7 @@ var FlueObserveBridge = class {
32960
34059
  try {
32961
34060
  this.handleEvent(event, flueContextFromUnknown(ctx));
32962
34061
  } catch (error) {
32963
- logInstrumentationError3("Flue observe", error);
34062
+ logInstrumentationError4("Flue observe", error);
32964
34063
  }
32965
34064
  }
32966
34065
  reset() {
@@ -32977,7 +34076,7 @@ var FlueObserveBridge = class {
32977
34076
  try {
32978
34077
  span = this.spanForExecutionOperation(operation, executionContext);
32979
34078
  } catch (error) {
32980
- logInstrumentationError3("Flue execution interceptor", error);
34079
+ logInstrumentationError4("Flue execution interceptor", error);
32981
34080
  }
32982
34081
  return span ? runWithCurrentSpanStore(span, next) : next();
32983
34082
  }
@@ -33183,7 +34282,7 @@ var FlueObserveBridge = class {
33183
34282
  this.runsById.delete(event.runId);
33184
34283
  }
33185
34284
  void flush().catch((error) => {
33186
- logInstrumentationError3("Flue flush", error);
34285
+ logInstrumentationError4("Flue flush", error);
33187
34286
  });
33188
34287
  }
33189
34288
  handleOperationStart(event) {
@@ -33958,17 +35057,17 @@ function safeLog3(span, event) {
33958
35057
  try {
33959
35058
  span.log(event);
33960
35059
  } catch (error) {
33961
- logInstrumentationError3("Flue span log", error);
35060
+ logInstrumentationError4("Flue span log", error);
33962
35061
  }
33963
35062
  }
33964
35063
  function safeEnd(span, endTime) {
33965
35064
  try {
33966
35065
  span.end(endTime === void 0 ? void 0 : { endTime });
33967
35066
  } catch (error) {
33968
- logInstrumentationError3("Flue span end", error);
35067
+ logInstrumentationError4("Flue span end", error);
33969
35068
  }
33970
35069
  }
33971
- function logInstrumentationError3(label, error) {
35070
+ function logInstrumentationError4(label, error) {
33972
35071
  debugLogger.debug(`Error in ${label} instrumentation:`, error);
33973
35072
  }
33974
35073
 
@@ -34536,10 +35635,10 @@ var LangSmithPlugin = class extends BasePlugin {
34536
35635
  const creates = ownValue(batch, "runCreates");
34537
35636
  if (Array.isArray(creates)) {
34538
35637
  const parentFirst = [...creates].sort((left, right) => {
34539
- const leftId = stringValue2(ownValue(left, "id"));
34540
- const rightId = stringValue2(ownValue(right, "id"));
34541
- const leftParent = stringValue2(ownValue(left, "parent_run_id"));
34542
- const rightParent = stringValue2(ownValue(right, "parent_run_id"));
35638
+ const leftId = stringValue3(ownValue(left, "id"));
35639
+ const rightId = stringValue3(ownValue(right, "id"));
35640
+ const leftParent = stringValue3(ownValue(left, "parent_run_id"));
35641
+ const rightParent = stringValue3(ownValue(right, "parent_run_id"));
34543
35642
  if (leftParent && leftParent === rightId) {
34544
35643
  return 1;
34545
35644
  }
@@ -34558,13 +35657,13 @@ var LangSmithPlugin = class extends BasePlugin {
34558
35657
  if (Array.isArray(updates)) {
34559
35658
  for (const run of updates) {
34560
35659
  this.containLifecycleFailure("batchIngestRuns update", () => {
34561
- this.processUpdate(stringValue2(ownValue(run, "id")) ?? "", run);
35660
+ this.processUpdate(stringValue3(ownValue(run, "id")) ?? "", run);
34562
35661
  });
34563
35662
  }
34564
35663
  }
34565
35664
  }
34566
35665
  processCreate(run) {
34567
- const id = stringValue2(ownValue(run, "id"));
35666
+ const id = stringValue3(ownValue(run, "id"));
34568
35667
  if (!id || this.completedRuns.get(id)) {
34569
35668
  return;
34570
35669
  }
@@ -34597,7 +35696,7 @@ var LangSmithPlugin = class extends BasePlugin {
34597
35696
  this.endIfComplete(id, activeRun, run);
34598
35697
  }
34599
35698
  processUpdate(explicitId, run) {
34600
- const id = stringValue2(explicitId) ?? stringValue2(ownValue(run, "id"));
35699
+ const id = stringValue3(explicitId) ?? stringValue3(ownValue(run, "id"));
34601
35700
  if (!id || this.completedRuns.get(id)) {
34602
35701
  return;
34603
35702
  }
@@ -34620,13 +35719,13 @@ var LangSmithPlugin = class extends BasePlugin {
34620
35719
  this.endIfComplete(id, active, active.run);
34621
35720
  }
34622
35721
  startRunSpan(id, run) {
34623
- const traceId = stringValue2(ownValue(run, "trace_id")) ?? id;
34624
- const parentId = stringValue2(ownValue(run, "parent_run_id")) ?? stringValue2(ownValue(ownValue(run, "parent_run"), "id"));
35722
+ const traceId = stringValue3(ownValue(run, "trace_id")) ?? id;
35723
+ const parentId = stringValue3(ownValue(run, "parent_run_id")) ?? stringValue3(ownValue(ownValue(run, "parent_run"), "id"));
34625
35724
  const startTime = timestampSeconds(ownValue(run, "start_time"));
34626
35725
  return startSpan(
34627
35726
  withSpanInstrumentationName(
34628
35727
  {
34629
- name: stringValue2(ownValue(run, "name")) ?? "LangSmith run",
35728
+ name: stringValue3(ownValue(run, "name")) ?? "LangSmith run",
34630
35729
  spanId: id,
34631
35730
  parentSpanIds: {
34632
35731
  parentSpanIds: parentId ? [parentId] : [],
@@ -34718,7 +35817,7 @@ function mergeRuns(previous, current) {
34718
35817
  function isRecord2(value) {
34719
35818
  return typeof value === "object" && value !== null && !Array.isArray(value);
34720
35819
  }
34721
- function stringValue2(value) {
35820
+ function stringValue3(value) {
34722
35821
  return typeof value === "string" && value.length > 0 ? value : void 0;
34723
35822
  }
34724
35823
  function timestampSeconds(value) {
@@ -34736,7 +35835,7 @@ function timestampSeconds(value) {
34736
35835
  return void 0;
34737
35836
  }
34738
35837
  function dottedOrderDepth(run) {
34739
- const dottedOrder = stringValue2(ownValue(run, "dotted_order"));
35838
+ const dottedOrder = stringValue3(ownValue(run, "dotted_order"));
34740
35839
  return dottedOrder ? dottedOrder.split(".").length : Number.MAX_SAFE_INTEGER;
34741
35840
  }
34742
35841
  function mapRunType(runType) {
@@ -34941,7 +36040,7 @@ var PiCodingAgentPlugin = class extends BasePlugin {
34941
36040
  }
34942
36041
  );
34943
36042
  } catch (error) {
34944
- logInstrumentationError4("Pi Coding Agent prompt start", error);
36043
+ logInstrumentationError5("Pi Coding Agent prompt start", error);
34945
36044
  }
34946
36045
  if (!state) {
34947
36046
  return runWithAutoInstrumentationSuppressed(invokeTarget);
@@ -35074,12 +36173,12 @@ function installPiAgentInstrumentation(agent) {
35074
36173
  () => handlePiAgentEvent(state, event)
35075
36174
  );
35076
36175
  } catch (error) {
35077
- logInstrumentationError4("Pi Coding Agent event", error);
36176
+ logInstrumentationError5("Pi Coding Agent event", error);
35078
36177
  }
35079
36178
  });
35080
36179
  piAgentEventSubscriptions.add(agent);
35081
36180
  } catch (error) {
35082
- logInstrumentationError4("Pi Coding Agent event subscription", error);
36181
+ logInstrumentationError5("Pi Coding Agent event subscription", error);
35083
36182
  }
35084
36183
  }
35085
36184
  function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
@@ -35129,7 +36228,7 @@ function wrapPiToolExecutors(tools) {
35129
36228
  });
35130
36229
  tool.execute = wrappedExecute;
35131
36230
  } catch (error) {
35132
- logInstrumentationError4("Pi Coding Agent tool wrapping", error);
36231
+ logInstrumentationError5("Pi Coding Agent tool wrapping", error);
35133
36232
  }
35134
36233
  }
35135
36234
  }
@@ -35208,7 +36307,7 @@ function patchAssistantMessageStream(stream, promptState, llmState) {
35208
36307
  try {
35209
36308
  await iterator.return();
35210
36309
  } catch (cleanupError) {
35211
- logInstrumentationError4(
36310
+ logInstrumentationError5(
35212
36311
  "Pi Coding Agent stream cleanup",
35213
36312
  cleanupError
35214
36313
  );
@@ -35373,7 +36472,7 @@ function finishPiPromptRun(state, error) {
35373
36472
  try {
35374
36473
  state.span.end();
35375
36474
  } catch (endError) {
35376
- logInstrumentationError4("Pi Coding Agent prompt end", endError);
36475
+ logInstrumentationError5("Pi Coding Agent prompt end", endError);
35377
36476
  }
35378
36477
  }
35379
36478
  }
@@ -35705,10 +36804,10 @@ function safeLog4(span, event) {
35705
36804
  try {
35706
36805
  span.log(event);
35707
36806
  } catch (error) {
35708
- logInstrumentationError4("Pi Coding Agent span log", error);
36807
+ logInstrumentationError5("Pi Coding Agent span log", error);
35709
36808
  }
35710
36809
  }
35711
- function logInstrumentationError4(context, error) {
36810
+ function logInstrumentationError5(context, error) {
35712
36811
  debugLogger.debug(`${context}:`, error);
35713
36812
  }
35714
36813
 
@@ -35946,7 +37045,7 @@ function handleAgentStreamEvent(state, event) {
35946
37045
  finalizeModelSpan(state, event);
35947
37046
  break;
35948
37047
  case "beforeToolCallEvent":
35949
- startToolSpan2(state, event);
37048
+ startToolSpan3(state, event);
35950
37049
  break;
35951
37050
  case "afterToolCallEvent":
35952
37051
  finalizeToolSpan(state, event);
@@ -35971,7 +37070,7 @@ function handleAgentStreamEvent(state, event) {
35971
37070
  break;
35972
37071
  }
35973
37072
  } catch (error) {
35974
- logInstrumentationError5("Strands Agent SDK event", error);
37073
+ logInstrumentationError6("Strands Agent SDK event", error);
35975
37074
  }
35976
37075
  }
35977
37076
  function handleMultiAgentStreamEvent(state, event, activeChildParents) {
@@ -36007,7 +37106,7 @@ function handleMultiAgentStreamEvent(state, event, activeChildParents) {
36007
37106
  break;
36008
37107
  }
36009
37108
  } catch (error) {
36010
- logInstrumentationError5("Strands Agent SDK multi-agent event", error);
37109
+ logInstrumentationError6("Strands Agent SDK multi-agent event", error);
36011
37110
  }
36012
37111
  }
36013
37112
  function buildModelSpanInput(event, attachmentCache) {
@@ -36086,7 +37185,7 @@ function finalizeModelSpan(state, event) {
36086
37185
  });
36087
37186
  modelState.span.end();
36088
37187
  }
36089
- function startToolSpan2(state, event) {
37188
+ function startToolSpan3(state, event) {
36090
37189
  const toolUse = event.toolUse;
36091
37190
  const key = toolKey2(toolUse);
36092
37191
  if (state.activeTools.has(key)) {
@@ -36366,7 +37465,7 @@ function getModelConfig(model) {
36366
37465
  try {
36367
37466
  return model.getConfig();
36368
37467
  } catch (error) {
36369
- logInstrumentationError5("Strands Agent SDK model config", error);
37468
+ logInstrumentationError6("Strands Agent SDK model config", error);
36370
37469
  return void 0;
36371
37470
  }
36372
37471
  }
@@ -36449,7 +37548,7 @@ function processStrandsInputAttachments(input, cache = createStrandsAttachmentCa
36449
37548
  try {
36450
37549
  return processStrandsInputNode(input, cache);
36451
37550
  } catch (error) {
36452
- logInstrumentationError5("Strands Agent SDK input attachments", error);
37551
+ logInstrumentationError6("Strands Agent SDK input attachments", error);
36453
37552
  return input;
36454
37553
  }
36455
37554
  }
@@ -36669,10 +37768,10 @@ function safeLog5(span, event) {
36669
37768
  try {
36670
37769
  span.log(event);
36671
37770
  } catch (error) {
36672
- logInstrumentationError5("Strands Agent SDK span log", error);
37771
+ logInstrumentationError6("Strands Agent SDK span log", error);
36673
37772
  }
36674
37773
  }
36675
- function logInstrumentationError5(context, error) {
37774
+ function logInstrumentationError6(context, error) {
36676
37775
  debugLogger.debug(`${context}:`, error);
36677
37776
  }
36678
37777
 
@@ -37075,10 +38174,10 @@ function observeAudioStream(value, observe, complete, cancel, span) {
37075
38174
  const getReader = value.getReader;
37076
38175
  value.getReader = function(...args) {
37077
38176
  const reader = Reflect.apply(getReader, this, args);
37078
- const read3 = reader.read;
38177
+ const read4 = reader.read;
37079
38178
  reader.read = function(...readArgs) {
37080
38179
  return Promise.resolve(
37081
- withCurrent(span, () => Reflect.apply(read3, this, readArgs))
38180
+ withCurrent(span, () => Reflect.apply(read4, this, readArgs))
37082
38181
  ).then(
37083
38182
  (result) => {
37084
38183
  if (result.value) safeObserve(result.value);
@@ -37595,14 +38694,14 @@ var CloudflareAIChatPlugin = class extends BasePlugin {
37595
38694
  const result = event.arguments[0];
37596
38695
  state = agent ? this.findResponseState(
37597
38696
  agent,
37598
- stringValue3(ownValue2(result, "requestId"))
38697
+ stringValue4(ownValue2(result, "requestId"))
37599
38698
  ) : void 0;
37600
38699
  if (!state) {
37601
38700
  return;
37602
38701
  }
37603
38702
  state.responseObserved = true;
37604
38703
  const output = serializeMessage(ownValue2(result, "message"));
37605
- const status = stringValue3(ownValue2(result, "status"));
38704
+ const status = stringValue4(ownValue2(result, "status"));
37606
38705
  const error = ownValue2(result, "error");
37607
38706
  const input = ownValue2(result, "continuation") === true ? state.input : serializeMessages(readProperty(agent, "messages"))?.filter(
37608
38707
  (message) => typeof output?.id !== "string" || message.id !== output.id
@@ -37649,7 +38748,7 @@ var CloudflareAIChatPlugin = class extends BasePlugin {
37649
38748
  }
37650
38749
  try {
37651
38750
  const agent = asObject(event.self);
37652
- const requestId = stringValue3(event.arguments[0]);
38751
+ const requestId = stringValue4(event.arguments[0]);
37653
38752
  const key = requestId ?? /* @__PURE__ */ Symbol("cloudflare-ai-chat-turn");
37654
38753
  const activeForAgent = agent ? this.getActiveTurns(agent) : void 0;
37655
38754
  const existing = activeForAgent?.get(key);
@@ -37818,7 +38917,7 @@ function ownValue2(value, key) {
37818
38917
  const descriptor = Object.getOwnPropertyDescriptor(object, key);
37819
38918
  return descriptor && "value" in descriptor ? descriptor.value : void 0;
37820
38919
  }
37821
- function stringValue3(value) {
38920
+ function stringValue4(value) {
37822
38921
  return typeof value === "string" ? value : void 0;
37823
38922
  }
37824
38923
  function serializeMessages(value) {
@@ -37936,7 +39035,7 @@ var CloudflareAgentsPlugin = class extends BasePlugin {
37936
39035
  );
37937
39036
  spans.set(event, span);
37938
39037
  } catch (error) {
37939
- logInstrumentationError6("start", error);
39038
+ logInstrumentationError7("start", error);
37940
39039
  }
37941
39040
  },
37942
39041
  asyncEnd: (event) => {
@@ -37956,7 +39055,7 @@ var CloudflareAgentsPlugin = class extends BasePlugin {
37956
39055
  }
37957
39056
  }
37958
39057
  } catch (error) {
37959
- logInstrumentationError6("completion", error);
39058
+ logInstrumentationError7("completion", error);
37960
39059
  } finally {
37961
39060
  safelyEndSpan(span);
37962
39061
  }
@@ -37970,7 +39069,7 @@ var CloudflareAgentsPlugin = class extends BasePlugin {
37970
39069
  try {
37971
39070
  span.log({ error: event.error });
37972
39071
  } catch (error) {
37973
- logInstrumentationError6("rejection", error);
39072
+ logInstrumentationError7("rejection", error);
37974
39073
  } finally {
37975
39074
  safelyEndSpan(span);
37976
39075
  }
@@ -38000,10 +39099,10 @@ function safelyEndSpan(span) {
38000
39099
  try {
38001
39100
  span.end();
38002
39101
  } catch (error) {
38003
- logInstrumentationError6("span end", error);
39102
+ logInstrumentationError7("span end", error);
38004
39103
  }
38005
39104
  }
38006
- function logInstrumentationError6(operation, error) {
39105
+ function logInstrumentationError7(operation, error) {
38007
39106
  debugLogger.error(
38008
39107
  `Failed to process Cloudflare Agents ${operation} instrumentation:`,
38009
39108
  error
@@ -38028,6 +39127,7 @@ var BraintrustPlugin = class extends BasePlugin {
38028
39127
  openRouterPlugin = null;
38029
39128
  openRouterAgentPlugin = null;
38030
39129
  mistralPlugin = null;
39130
+ langGraphSDKPlugin = null;
38031
39131
  ollamaPlugin = null;
38032
39132
  googleADKPlugin = null;
38033
39133
  coherePlugin = null;
@@ -38108,6 +39208,10 @@ var BraintrustPlugin = class extends BasePlugin {
38108
39208
  this.mistralPlugin = new MistralPlugin();
38109
39209
  this.mistralPlugin.enable();
38110
39210
  }
39211
+ if (integrations.langgraphSDK !== false) {
39212
+ this.langGraphSDKPlugin = new LangGraphSDKPlugin();
39213
+ this.langGraphSDKPlugin.enable();
39214
+ }
38111
39215
  if (integrations.ollama !== false) {
38112
39216
  this.ollamaPlugin = new OllamaPlugin();
38113
39217
  this.ollamaPlugin.enable();
@@ -38236,6 +39340,10 @@ var BraintrustPlugin = class extends BasePlugin {
38236
39340
  this.mistralPlugin.disable();
38237
39341
  this.mistralPlugin = null;
38238
39342
  }
39343
+ if (this.langGraphSDKPlugin) {
39344
+ this.langGraphSDKPlugin.disable();
39345
+ this.langGraphSDKPlugin = null;
39346
+ }
38239
39347
  if (this.ollamaPlugin) {
38240
39348
  this.ollamaPlugin.disable();
38241
39349
  this.ollamaPlugin = null;
@@ -38377,6 +39485,9 @@ var envIntegrationAliases = {
38377
39485
  "langchain-js": "langchain",
38378
39486
  "@langchain": "langchain",
38379
39487
  langgraph: "langgraph",
39488
+ langgraphsdk: "langgraphSDK",
39489
+ "langgraph-sdk": "langgraphSDK",
39490
+ "@langchain/langgraph-sdk": "langgraphSDK",
38380
39491
  langsmith: "langsmith",
38381
39492
  voyage: "voyageai",
38382
39493
  "voyage-ai": "voyageai",
@@ -38417,6 +39528,7 @@ function getDefaultInstrumentationIntegrations() {
38417
39528
  gitHubCopilot: true,
38418
39529
  langchain: true,
38419
39530
  langgraph: true,
39531
+ langgraphSDK: true,
38420
39532
  langsmith: true,
38421
39533
  voyageai: true,
38422
39534
  elevenlabs: true,
@@ -38585,8 +39697,6 @@ __export(exports_exports, {
38585
39697
  BRAINTRUST_PARENT_KEY: () => BRAINTRUST_PARENT_KEY,
38586
39698
  BaseAttachment: () => BaseAttachment,
38587
39699
  BaseExperiment: () => BaseExperiment,
38588
- BatchScorer: () => BatchScorer,
38589
- BatchTask: () => BatchTask,
38590
39700
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
38591
39701
  BraintrustMiddleware: () => BraintrustMiddleware,
38592
39702
  BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
@@ -38600,8 +39710,6 @@ __export(exports_exports, {
38600
39710
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
38601
39711
  Dataset: () => Dataset2,
38602
39712
  DatasetPipeline: () => DatasetPipeline,
38603
- DurableEvalMemoryStore: () => DurableEvalMemoryStore,
38604
- DurableEvalRedisStore: () => DurableEvalRedisStore,
38605
39713
  ERR_PERMALINK: () => ERR_PERMALINK,
38606
39714
  Eval: () => Eval,
38607
39715
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -38636,6 +39744,10 @@ __export(exports_exports, {
38636
39744
  TestBackgroundLogger: () => TestBackgroundLogger,
38637
39745
  ToolBuilder: () => ToolBuilder,
38638
39746
  UUIDGenerator: () => UUIDGenerator,
39747
+ WorkflowEvalMemoryStore: () => WorkflowEvalMemoryStore,
39748
+ WorkflowEvalRedisStore: () => WorkflowEvalRedisStore,
39749
+ WorkflowScorer: () => WorkflowScorer,
39750
+ WorkflowTask: () => WorkflowTask,
38639
39751
  X_CACHED_HEADER: () => X_CACHED_HEADER,
38640
39752
  _exportsForTestingOnly: () => _exportsForTestingOnly,
38641
39753
  _internalGetGlobalState: () => _internalGetGlobalState,
@@ -38660,12 +39772,13 @@ __export(exports_exports, {
38660
39772
  currentSpan: () => currentSpan,
38661
39773
  deepCopyEvent: () => deepCopyEvent,
38662
39774
  defaultErrorScoreHandler: () => defaultErrorScoreHandler,
38663
- defineDurableEval: () => defineDurableEval,
39775
+ defineWorkflowEval: () => defineWorkflowEval,
38664
39776
  deserializePlainStringAsJSON: () => deserializePlainStringAsJSON,
38665
39777
  devNullWritableStream: () => devNullWritableStream,
38666
39778
  evaluatorDefinitionSchema: () => evaluatorDefinitionSchema,
38667
39779
  evaluatorDefinitionsSchema: () => evaluatorDefinitionsSchema,
38668
39780
  extractTraceContextFromHeaders: () => extractTraceContextFromHeaders,
39781
+ failOpenAIAgentsTrace: () => failOpenAIAgentsTrace,
38669
39782
  flush: () => flush,
38670
39783
  getContextManager: () => getContextManager,
38671
39784
  getIdGenerator: () => getIdGenerator,
@@ -38712,12 +39825,14 @@ __export(exports_exports, {
38712
39825
  setFetch: () => setFetch,
38713
39826
  setMaskingFunction: () => setMaskingFunction,
38714
39827
  spanComponentsToObjectId: () => spanComponentsToObjectId,
39828
+ startOpenAIAgentsTrace: () => startOpenAIAgentsTrace,
38715
39829
  startSpan: () => startSpan,
38716
39830
  summarize: () => summarize,
38717
39831
  templateRegistry: () => templateRegistry,
38718
39832
  toolFunctionDefinitionSchema: () => ToolFunctionDefinition,
38719
39833
  traceable: () => traceable,
38720
39834
  traced: () => traced,
39835
+ updateOpenAIAgentsTrace: () => updateOpenAIAgentsTrace,
38721
39836
  updateSpan: () => updateSpan,
38722
39837
  uploadLogs3OverflowPayload: () => uploadLogs3OverflowPayload,
38723
39838
  utf8ByteLength: () => utf8ByteLength2,
@@ -38746,6 +39861,7 @@ __export(exports_exports, {
38746
39861
  wrapGroq: () => wrapGroq,
38747
39862
  wrapHuggingFace: () => wrapHuggingFace,
38748
39863
  wrapHuggingFaceTransformers: () => wrapHuggingFaceTransformers,
39864
+ wrapLangGraphSDK: () => wrapLangGraphSDK,
38749
39865
  wrapLangSmithClient: () => wrapLangSmithClient,
38750
39866
  wrapLangSmithRunTrees: () => wrapLangSmithRunTrees,
38751
39867
  wrapLangSmithTraceable: () => wrapLangSmithTraceable,
@@ -38945,7 +40061,7 @@ function createLazyAPIPromise(ensureExecuted, ensureResponse, getAPIPromise) {
38945
40061
  }
38946
40062
 
38947
40063
  // src/openai-batch.ts
38948
- function read2(value, key) {
40064
+ function read3(value, key) {
38949
40065
  if (value === null || typeof value !== "object" && typeof value !== "function") {
38950
40066
  return void 0;
38951
40067
  }
@@ -38956,7 +40072,7 @@ function read2(value, key) {
38956
40072
  }
38957
40073
  }
38958
40074
  function isAsyncIterable5(value) {
38959
- return typeof read2(value, Symbol.asyncIterator) === "function";
40075
+ return typeof read3(value, Symbol.asyncIterator) === "function";
38960
40076
  }
38961
40077
  function teeAsyncIterable(source) {
38962
40078
  const iterator = source[Symbol.asyncIterator]();
@@ -38999,7 +40115,7 @@ function teeAsyncIterable(source) {
38999
40115
  }
39000
40116
  }
39001
40117
  };
39002
- const path = read2(source, "path");
40118
+ const path = read3(source, "path");
39003
40119
  if (typeof path === "string") {
39004
40120
  Object.defineProperty(upload, "path", { value: path });
39005
40121
  }
@@ -39020,8 +40136,8 @@ function teeUpload(upload) {
39020
40136
  function openaiFilesCreateTraced(files) {
39021
40137
  return (params, options) => {
39022
40138
  const parent = getSpanParentObject();
39023
- const purpose = read2(params, "purpose");
39024
- const file = read2(params, "file");
40139
+ const purpose = read3(params, "purpose");
40140
+ const file = read3(params, "file");
39025
40141
  if (purpose !== "batch") {
39026
40142
  return files.create(params, options);
39027
40143
  }
@@ -39112,6 +40228,143 @@ async function completeOpenAIBatchTrace(args) {
39112
40228
  );
39113
40229
  }
39114
40230
 
40231
+ // src/openai-agents-api.ts
40232
+ function isRecord3(value) {
40233
+ return typeof value === "object" && value !== null && !Array.isArray(value);
40234
+ }
40235
+ function validateStartArgs(value) {
40236
+ if (!isRecord3(value)) {
40237
+ throw new TypeError(
40238
+ "startOpenAIAgentsTrace expected an OpenAI Agents parameters object"
40239
+ );
40240
+ }
40241
+ const agent = value.agent;
40242
+ if (agent !== void 0 && agent !== null && !isRecord3(agent)) {
40243
+ throw new TypeError(
40244
+ "startOpenAIAgentsTrace expected agent to be an object or null"
40245
+ );
40246
+ }
40247
+ if (isRecord3(agent) && (agent.id !== void 0 && typeof agent.id !== "string" || agent.model !== void 0 && typeof agent.model !== "string" || agent.name !== void 0 && agent.name !== null && typeof agent.name !== "string")) {
40248
+ throw new TypeError(
40249
+ "startOpenAIAgentsTrace received invalid agent identity fields"
40250
+ );
40251
+ }
40252
+ if (value.agent_id !== void 0 && typeof value.agent_id !== "string") {
40253
+ throw new TypeError(
40254
+ "startOpenAIAgentsTrace expected agent_id to be a string"
40255
+ );
40256
+ }
40257
+ if (value.metadata !== void 0 && value.metadata !== null && !isRecord3(value.metadata)) {
40258
+ throw new TypeError(
40259
+ "startOpenAIAgentsTrace expected metadata to be an object or null"
40260
+ );
40261
+ }
40262
+ return value;
40263
+ }
40264
+ function validateEvent(event) {
40265
+ if (!isRecord3(event) || typeof event.type !== "string" || event.type.length === 0) {
40266
+ throw new TypeError(
40267
+ "updateOpenAIAgentsTrace expected an OpenAI Agents event object"
40268
+ );
40269
+ }
40270
+ return event;
40271
+ }
40272
+ function createTraceState() {
40273
+ const parent = _internalExportParentSynchronously(getSpanParentObject());
40274
+ if (!parent) {
40275
+ return null;
40276
+ }
40277
+ const parentComponents = SpanComponentsV4.fromStr(parent);
40278
+ const rowId = newId();
40279
+ const useLegacyIds = resolveUseLegacyUuidIds();
40280
+ const spanId = useLegacyIds ? newId() : newId().replaceAll("-", "").slice(0, 16);
40281
+ const rootSpanId = useLegacyIds ? spanId : newId().replaceAll("-", "");
40282
+ const root = new SpanComponentsV4({
40283
+ object_type: parentComponents.data.object_type,
40284
+ ...parentComponents.data.object_id ? { object_id: parentComponents.data.object_id } : {
40285
+ compute_object_metadata_args: parentComponents.data.compute_object_metadata_args ?? {}
40286
+ },
40287
+ propagated_event: parentComponents.data.propagated_event,
40288
+ root_span_id: rootSpanId,
40289
+ row_id: rowId,
40290
+ span_id: spanId
40291
+ }).toStr();
40292
+ return {
40293
+ callItems: {},
40294
+ ended: false,
40295
+ eventIds: [],
40296
+ openTools: {},
40297
+ root,
40298
+ rootKey: spanId,
40299
+ rootParent: parent,
40300
+ startTime: getCurrentUnixTimestamp(),
40301
+ subagents: {},
40302
+ turnSubagents: {},
40303
+ version: 1
40304
+ };
40305
+ }
40306
+ function startOpenAIAgentsTrace(args) {
40307
+ const validatedArgs = validateStartArgs(args);
40308
+ const state = createTraceState();
40309
+ if (!state) {
40310
+ return null;
40311
+ }
40312
+ try {
40313
+ void openAIChannels.agentsTraceStart.invoke(
40314
+ async () => state,
40315
+ void 0,
40316
+ [{ args: validatedArgs, state }],
40317
+ {}
40318
+ ).catch((error) => {
40319
+ debugLogger.debug(
40320
+ "OpenAI Agents API instrumentation could not start:",
40321
+ error
40322
+ );
40323
+ });
40324
+ } catch (error) {
40325
+ debugLogger.debug(
40326
+ "OpenAI Agents API instrumentation could not start:",
40327
+ error
40328
+ );
40329
+ }
40330
+ return state;
40331
+ }
40332
+ async function updateOpenAIAgentsTrace(token, event) {
40333
+ const state = token;
40334
+ const validatedEvent = validateEvent(event);
40335
+ try {
40336
+ return await openAIChannels.agentsTraceCapture.invoke(
40337
+ async () => state,
40338
+ void 0,
40339
+ [{ state, event: validatedEvent }],
40340
+ {}
40341
+ );
40342
+ } catch (error) {
40343
+ debugLogger.debug(
40344
+ "OpenAI Agents API instrumentation could not update:",
40345
+ error
40346
+ );
40347
+ return token;
40348
+ }
40349
+ }
40350
+ async function failOpenAIAgentsTrace(token, error) {
40351
+ const state = token;
40352
+ try {
40353
+ return await openAIChannels.agentsTraceFail.invoke(
40354
+ async () => state,
40355
+ void 0,
40356
+ [{ state, error }],
40357
+ {}
40358
+ );
40359
+ } catch (instrumentationError) {
40360
+ debugLogger.debug(
40361
+ "OpenAI Agents API instrumentation could not record failure:",
40362
+ instrumentationError
40363
+ );
40364
+ return token;
40365
+ }
40366
+ }
40367
+
39115
40368
  // src/functions/invoke.ts
39116
40369
  async function invoke(args) {
39117
40370
  const {
@@ -40561,7 +41814,31 @@ var MAX_STORED_LLM_INPUTS = 100;
40561
41814
  var MAX_STORED_REASONING_BLOCKS = 100;
40562
41815
  var MAX_STORED_SPAN_REFERENCES = 1e4;
40563
41816
  var MAX_STORED_STEP_STARTS = 1e4;
41817
+ var EVE_HANDLED_EVENT_TYPES = /* @__PURE__ */ new Set([
41818
+ "action.result",
41819
+ "actions.requested",
41820
+ "message.completed",
41821
+ "message.received",
41822
+ "reasoning.completed",
41823
+ "result.completed",
41824
+ "session.completed",
41825
+ "session.failed",
41826
+ "session.started",
41827
+ "step.completed",
41828
+ "step.failed",
41829
+ "step.started",
41830
+ "subagent.called",
41831
+ "subagent.completed",
41832
+ "turn.completed",
41833
+ "turn.failed",
41834
+ "turn.started"
41835
+ ]);
40564
41836
  function braintrustEveHook(options) {
41837
+ if (!options || typeof options.defineState !== "function") {
41838
+ throw new TypeError(
41839
+ "braintrustEveHook requires Eve's defineState function"
41840
+ );
41841
+ }
40565
41842
  const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
40566
41843
  const bridge = new EveBridge(state);
40567
41844
  return {
@@ -40573,15 +41850,27 @@ function braintrustEveHook(options) {
40573
41850
  };
40574
41851
  }
40575
41852
  function createLegacyEveInstrumentation(options) {
41853
+ if (!options || typeof options.defineState !== "function") {
41854
+ throw new TypeError(
41855
+ "braintrustEveInstrumentation requires Eve's defineState function"
41856
+ );
41857
+ }
40576
41858
  const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
40577
41859
  return {
40578
41860
  events: {
40579
41861
  "step.started": (input) => {
40580
41862
  try {
41863
+ if (!isEveInstrumentationStepStartedEventInput(input)) {
41864
+ debugLogger.warn(
41865
+ "Ignoring malformed Eve instrumentation step.started event"
41866
+ );
41867
+ return void 0;
41868
+ }
40581
41869
  captureEveModelInput(state, input);
40582
41870
  } catch (error) {
40583
41871
  debugLogger.warn("Error in Eve LLM input capture:", error);
40584
41872
  }
41873
+ return void 0;
40585
41874
  }
40586
41875
  },
40587
41876
  recordInputs: false,
@@ -40590,7 +41879,77 @@ function createLegacyEveInstrumentation(options) {
40590
41879
  };
40591
41880
  }
40592
41881
  function isEveHandleMessageStreamEvent(event) {
40593
- return isObject(event) && typeof event["type"] === "string";
41882
+ if (!isObject(event) || typeof event["type"] !== "string") {
41883
+ return false;
41884
+ }
41885
+ const type = event["type"];
41886
+ if (type === "session.completed") {
41887
+ return true;
41888
+ }
41889
+ if (!isObject(event["data"])) {
41890
+ return false;
41891
+ }
41892
+ const data = event["data"];
41893
+ if (type === "session.started") {
41894
+ return true;
41895
+ }
41896
+ if (type === "session.failed") {
41897
+ return typeof data["sessionId"] === "string" && typeof data["code"] === "string" && typeof data["message"] === "string";
41898
+ }
41899
+ if (type === "session.waiting") {
41900
+ return data["wait"] === "next-user-message";
41901
+ }
41902
+ if (typeof data["turnId"] !== "string" || typeof data["sequence"] !== "number" || !Number.isFinite(data["sequence"])) {
41903
+ return false;
41904
+ }
41905
+ if (type === "turn.started" || type === "turn.completed" || type === "subagent.called" || type === "subagent.completed") {
41906
+ if (type === "subagent.called") {
41907
+ return typeof data["callId"] === "string" && typeof data["childSessionId"] === "string" && typeof data["name"] === "string";
41908
+ }
41909
+ if (type === "subagent.completed") {
41910
+ return typeof data["callId"] === "string" && typeof data["subagentName"] === "string";
41911
+ }
41912
+ return true;
41913
+ }
41914
+ if (type === "turn.failed") {
41915
+ return typeof data["code"] === "string" && typeof data["message"] === "string";
41916
+ }
41917
+ if (type === "message.received") {
41918
+ return typeof data["message"] === "string";
41919
+ }
41920
+ if (typeof data["stepIndex"] !== "number" || !Number.isFinite(data["stepIndex"]) || data["stepIndex"] < 0) {
41921
+ return false;
41922
+ }
41923
+ switch (type) {
41924
+ case "step.started":
41925
+ return true;
41926
+ case "message.completed":
41927
+ return typeof data["finishReason"] === "string" && (typeof data["message"] === "string" || data["message"] === null);
41928
+ case "reasoning.completed":
41929
+ return typeof data["reasoning"] === "string";
41930
+ case "result.completed":
41931
+ return true;
41932
+ case "step.completed":
41933
+ return typeof data["finishReason"] === "string";
41934
+ case "step.failed":
41935
+ return typeof data["code"] === "string" && typeof data["message"] === "string";
41936
+ case "actions.requested":
41937
+ return Array.isArray(data["actions"]);
41938
+ case "action.result":
41939
+ return isObject(data["result"]) && (data["status"] === "completed" || data["status"] === "failed" || data["status"] === "rejected");
41940
+ default:
41941
+ return false;
41942
+ }
41943
+ }
41944
+ function isEveInstrumentationStepStartedEventInput(input) {
41945
+ if (!isObject(input)) {
41946
+ return false;
41947
+ }
41948
+ const modelInput = input["modelInput"];
41949
+ const session = input["session"];
41950
+ const step = input["step"];
41951
+ const turn = input["turn"];
41952
+ return isObject(modelInput) && Array.isArray(modelInput["messages"]) && isObject(session) && typeof session["id"] === "string" && isObject(step) && typeof step["index"] === "number" && Number.isFinite(step["index"]) && step["index"] >= 0 && isObject(turn) && typeof turn["id"] === "string" && typeof turn["sequence"] === "number" && Number.isFinite(turn["sequence"]);
40594
41953
  }
40595
41954
  var ResumedEveSpan = class {
40596
41955
  constructor(reference) {
@@ -40759,7 +42118,17 @@ var EveBridge = class {
40759
42118
  });
40760
42119
  }
40761
42120
  async handle(event, ctx, hookMetadata) {
42121
+ try {
42122
+ await this.handleUnchecked(event, ctx, hookMetadata);
42123
+ } catch (error) {
42124
+ debugLogger.warn("Error in Eve hook instrumentation:", error);
42125
+ }
42126
+ }
42127
+ async handleUnchecked(event, ctx, hookMetadata) {
40762
42128
  if (!isEveHandleMessageStreamEvent(event)) {
42129
+ if (isObject(event) && typeof event["type"] === "string" && EVE_HANDLED_EVENT_TYPES.has(event["type"])) {
42130
+ debugLogger.warn(`Ignoring malformed Eve hook ${event["type"]} event`);
42131
+ }
40763
42132
  return;
40764
42133
  }
40765
42134
  const run = async () => {
@@ -41085,9 +42454,14 @@ var EveBridge = class {
41085
42454
  }
41086
42455
  for (const action of traceActions) {
41087
42456
  const name = action.kind === "tool-call" ? action.toolName : action.subagentName ?? action.name ?? "agent";
42457
+ let args = "null";
42458
+ try {
42459
+ args = JSON.stringify(action.input) ?? "null";
42460
+ } catch {
42461
+ }
41088
42462
  toolCallsById.set(action.callId, {
41089
42463
  function: {
41090
- arguments: JSON.stringify(action.input),
42464
+ arguments: args,
41091
42465
  name
41092
42466
  },
41093
42467
  id: action.callId,
@@ -41956,17 +43330,33 @@ function consumeCapturedEveModelInput(state, sessionId, turnId, stepIndex) {
41956
43330
  }
41957
43331
  }
41958
43332
  function capturedModelInput(modelInput) {
41959
- const { instructions, messages } = modelInput;
41960
- const value = [];
41961
- if (typeof instructions === "string") {
41962
- value.push({ content: instructions, role: "system" });
41963
- } else if (Array.isArray(instructions)) {
41964
- value.push(...instructions.map(capturedEveModelMessage));
41965
- } else if (instructions) {
41966
- value.push(capturedEveModelMessage(instructions));
41967
- }
41968
- value.push(...messages.map(capturedEveModelMessage));
41969
43333
  try {
43334
+ if (!isObject(modelInput) || !Array.isArray(modelInput["messages"])) {
43335
+ return void 0;
43336
+ }
43337
+ const value = [];
43338
+ const instructions = modelInput["instructions"];
43339
+ if (typeof instructions === "string") {
43340
+ value.push({ content: instructions, role: "system" });
43341
+ } else if (Array.isArray(instructions)) {
43342
+ for (const instruction of instructions) {
43343
+ const captured = capturedEveModelMessage(instruction);
43344
+ if (captured?.role === "system") {
43345
+ value.push(captured);
43346
+ }
43347
+ }
43348
+ } else {
43349
+ const captured = capturedEveModelMessage(instructions);
43350
+ if (captured?.role === "system") {
43351
+ value.push(captured);
43352
+ }
43353
+ }
43354
+ for (const message of modelInput["messages"]) {
43355
+ const captured = capturedEveModelMessage(message);
43356
+ if (captured) {
43357
+ value.push(captured);
43358
+ }
43359
+ }
41970
43360
  const cloned = JSON.parse(JSON.stringify(value));
41971
43361
  if (!Array.isArray(cloned)) {
41972
43362
  return void 0;
@@ -41977,116 +43367,202 @@ function capturedModelInput(modelInput) {
41977
43367
  }
41978
43368
  }
41979
43369
  function capturedEveModelMessage(message) {
41980
- const { content, role } = message;
43370
+ if (!isObject(message)) {
43371
+ return void 0;
43372
+ }
43373
+ const role = message["role"];
43374
+ if (role !== "system" && role !== "user" && role !== "assistant" && role !== "tool") {
43375
+ return void 0;
43376
+ }
43377
+ const content = message["content"];
41981
43378
  if (typeof content === "string") {
41982
43379
  return { content, role };
41983
43380
  }
41984
- return { content: content.map(capturedEveModelContentPart), role };
43381
+ if (!Array.isArray(content)) {
43382
+ return void 0;
43383
+ }
43384
+ const capturedContent = [];
43385
+ for (const part of content) {
43386
+ const captured = capturedEveModelContentPart(part);
43387
+ if (captured) {
43388
+ capturedContent.push(captured);
43389
+ }
43390
+ }
43391
+ return { content: capturedContent, role };
41985
43392
  }
41986
43393
  function capturedEveModelContentPart(part) {
41987
- switch (part.type) {
43394
+ if (!isObject(part) || typeof part["type"] !== "string") {
43395
+ return void 0;
43396
+ }
43397
+ switch (part["type"]) {
41988
43398
  case "text":
41989
- case "reasoning":
41990
- return { text: part.text, type: part.type };
43399
+ case "reasoning": {
43400
+ const text = part["text"];
43401
+ return typeof text === "string" ? { text, type: part["type"] } : void 0;
43402
+ }
41991
43403
  case "image":
43404
+ if (!Object.hasOwn(part, "image")) {
43405
+ return void 0;
43406
+ }
41992
43407
  return {
41993
- image: part.image,
41994
- ...part.mediaType !== void 0 ? { mediaType: part.mediaType } : {},
43408
+ image: part["image"],
43409
+ ...typeof part["mediaType"] === "string" ? { mediaType: part["mediaType"] } : {},
41995
43410
  type: "image"
41996
43411
  };
41997
43412
  case "file":
41998
- case "reasoning-file":
43413
+ case "reasoning-file": {
43414
+ if (!Object.hasOwn(part, "data") || typeof part["mediaType"] !== "string") {
43415
+ return void 0;
43416
+ }
41999
43417
  return {
42000
- data: part.data,
42001
- ...part.type === "file" && part.filename !== void 0 ? { filename: part.filename } : {},
42002
- mediaType: part.mediaType,
42003
- type: part.type
43418
+ data: part["data"],
43419
+ ...part["type"] === "file" && typeof part["filename"] === "string" ? { filename: part["filename"] } : {},
43420
+ mediaType: part["mediaType"],
43421
+ type: part["type"]
42004
43422
  };
43423
+ }
42005
43424
  case "custom":
42006
43425
  return {
42007
- ..."kind" in part ? { kind: part.kind } : {},
43426
+ ...typeof part["kind"] === "string" ? { kind: part["kind"] } : {},
42008
43427
  type: "custom"
42009
43428
  };
42010
- case "tool-call":
43429
+ case "tool-call": {
43430
+ if (typeof part["toolCallId"] !== "string" || typeof part["toolName"] !== "string") {
43431
+ return void 0;
43432
+ }
42011
43433
  return {
42012
- input: part.input,
42013
- ...part.providerExecuted !== void 0 ? { providerExecuted: part.providerExecuted } : {},
42014
- toolCallId: part.toolCallId,
42015
- toolName: part.toolName,
43434
+ input: part["input"],
43435
+ ...typeof part["providerExecuted"] === "boolean" ? { providerExecuted: part["providerExecuted"] } : {},
43436
+ toolCallId: part["toolCallId"],
43437
+ toolName: part["toolName"],
42016
43438
  type: "tool-call"
42017
43439
  };
43440
+ }
42018
43441
  case "tool-result": {
42019
- const output = part.output;
43442
+ const output = part["output"];
43443
+ if (typeof part["toolCallId"] !== "string" || typeof part["toolName"] !== "string" || !isObject(output) || typeof output["type"] !== "string") {
43444
+ return void 0;
43445
+ }
42020
43446
  let capturedOutput;
42021
- switch (output.type) {
43447
+ switch (output["type"]) {
42022
43448
  case "text":
42023
- case "error-text":
42024
- capturedOutput = { type: output.type, value: output.value };
43449
+ case "error-text": {
43450
+ if (typeof output["value"] !== "string") {
43451
+ return void 0;
43452
+ }
43453
+ capturedOutput = {
43454
+ type: output["type"],
43455
+ value: output["value"]
43456
+ };
42025
43457
  break;
43458
+ }
42026
43459
  case "json":
42027
43460
  case "error-json":
42028
- capturedOutput = { type: output.type, value: output.value };
43461
+ capturedOutput = {
43462
+ type: output["type"],
43463
+ value: output["value"]
43464
+ };
42029
43465
  break;
42030
43466
  case "execution-denied":
42031
43467
  capturedOutput = {
42032
- ...output.reason !== void 0 ? { reason: output.reason } : {},
43468
+ ...typeof output["reason"] === "string" ? { reason: output["reason"] } : {},
42033
43469
  type: "execution-denied"
42034
43470
  };
42035
43471
  break;
42036
- case "content":
43472
+ case "content": {
43473
+ if (!Array.isArray(output["value"])) {
43474
+ return void 0;
43475
+ }
43476
+ const value = [];
43477
+ for (const outputPart of output["value"]) {
43478
+ const captured = capturedEveModelContentPart(outputPart);
43479
+ if (captured) {
43480
+ value.push(captured);
43481
+ }
43482
+ }
42037
43483
  capturedOutput = {
42038
43484
  type: "content",
42039
- value: output.value.map(capturedEveModelContentPart)
43485
+ value
42040
43486
  };
42041
43487
  break;
43488
+ }
43489
+ default:
43490
+ return void 0;
42042
43491
  }
42043
43492
  return {
42044
43493
  output: capturedOutput,
42045
- toolCallId: part.toolCallId,
42046
- toolName: part.toolName,
43494
+ toolCallId: part["toolCallId"],
43495
+ toolName: part["toolName"],
42047
43496
  type: "tool-result"
42048
43497
  };
42049
43498
  }
42050
- case "tool-approval-request":
43499
+ case "tool-approval-request": {
43500
+ if (typeof part["approvalId"] !== "string" || typeof part["toolCallId"] !== "string") {
43501
+ return void 0;
43502
+ }
42051
43503
  return {
42052
- approvalId: part.approvalId,
42053
- ...part.isAutomatic !== void 0 ? { isAutomatic: part.isAutomatic } : {},
42054
- ...part.signature !== void 0 ? { signature: part.signature } : {},
42055
- toolCallId: part.toolCallId,
43504
+ approvalId: part["approvalId"],
43505
+ ...typeof part["isAutomatic"] === "boolean" ? { isAutomatic: part["isAutomatic"] } : {},
43506
+ ...typeof part["signature"] === "string" ? { signature: part["signature"] } : {},
43507
+ toolCallId: part["toolCallId"],
42056
43508
  type: "tool-approval-request"
42057
43509
  };
42058
- case "tool-approval-response":
43510
+ }
43511
+ case "tool-approval-response": {
43512
+ if (typeof part["approvalId"] !== "string" || typeof part["approved"] !== "boolean") {
43513
+ return void 0;
43514
+ }
42059
43515
  return {
42060
- approvalId: part.approvalId,
42061
- approved: part.approved,
42062
- ...part.providerExecuted !== void 0 ? { providerExecuted: part.providerExecuted } : {},
42063
- ...part.reason !== void 0 ? { reason: part.reason } : {},
43516
+ approvalId: part["approvalId"],
43517
+ approved: part["approved"],
43518
+ ...typeof part["providerExecuted"] === "boolean" ? { providerExecuted: part["providerExecuted"] } : {},
43519
+ ...typeof part["reason"] === "string" ? { reason: part["reason"] } : {},
42064
43520
  type: "tool-approval-response"
42065
43521
  };
43522
+ }
42066
43523
  case "file-data":
42067
- case "image-data":
43524
+ case "image-data": {
43525
+ if (typeof part["data"] !== "string" || typeof part["mediaType"] !== "string") {
43526
+ return void 0;
43527
+ }
42068
43528
  return {
42069
- data: part.data,
42070
- ...part.type === "file-data" && part.filename !== void 0 ? { filename: part.filename } : {},
42071
- mediaType: part.mediaType,
42072
- type: part.type
43529
+ data: part["data"],
43530
+ ...part["type"] === "file-data" && typeof part["filename"] === "string" ? { filename: part["filename"] } : {},
43531
+ mediaType: part["mediaType"],
43532
+ type: part["type"]
42073
43533
  };
43534
+ }
42074
43535
  case "file-url":
42075
- case "image-url":
43536
+ case "image-url": {
43537
+ if (typeof part["url"] !== "string") {
43538
+ return void 0;
43539
+ }
42076
43540
  return {
42077
- ...part.type === "file-url" && part.mediaType !== void 0 ? { mediaType: part.mediaType } : {},
42078
- type: part.type,
42079
- url: part.url
43541
+ ...part["type"] === "file-url" && typeof part["mediaType"] === "string" ? { mediaType: part["mediaType"] } : {},
43542
+ type: part["type"],
43543
+ url: part["url"]
42080
43544
  };
43545
+ }
42081
43546
  case "file-id":
42082
- case "image-file-id":
42083
- return { fileId: part.fileId, type: part.type };
43547
+ case "image-file-id": {
43548
+ const fileId = part["fileId"];
43549
+ if (typeof fileId !== "string" && !isObject(fileId)) {
43550
+ return void 0;
43551
+ }
43552
+ return { fileId, type: part["type"] };
43553
+ }
42084
43554
  case "file-reference":
42085
- case "image-file-reference":
43555
+ case "image-file-reference": {
43556
+ if (!isObject(part["providerReference"])) {
43557
+ return void 0;
43558
+ }
42086
43559
  return {
42087
- providerReference: part.providerReference,
42088
- type: part.type
43560
+ providerReference: part["providerReference"],
43561
+ type: part["type"]
42089
43562
  };
43563
+ }
43564
+ default:
43565
+ return void 0;
42090
43566
  }
42091
43567
  }
42092
43568
  function isCapturedModelInput(input) {
@@ -42222,18 +43698,54 @@ function createEveInstrumentationProvider(options = {}) {
42222
43698
  recordOutputs: true
42223
43699
  }),
42224
43700
  events: {
42225
- "action.completed": (event, context) => bridge.handleActionTerminal(event, context),
42226
- "action.failed": (event, context) => bridge.handleActionTerminal(event, context),
42227
- "action.started": (event, context) => bridge.handleActionStarted(event, context),
42228
- "model.call.completed": (event, context) => bridge.handleModelTerminal(event, context),
42229
- "model.call.failed": (event, context) => bridge.handleModelTerminal(event, context),
42230
- "model.call.started": (event, context) => bridge.handleModelStarted(event, context),
42231
- "step.attempt.completed": (event) => bridge.handleStepAttemptTerminal(event),
42232
- "step.attempt.failed": (event) => bridge.handleStepAttemptTerminal(event),
42233
- "turn.cancelled": (event, context) => bridge.handleTurnTerminal(event, context),
42234
- "turn.completed": (event, context) => bridge.handleTurnTerminal(event, context),
42235
- "turn.failed": (event, context) => bridge.handleTurnTerminal(event, context),
42236
- "turn.started": (event, context) => bridge.handleTurnStarted(event, context)
43701
+ "action.completed": providerHandler(
43702
+ "action.completed",
43703
+ bridge.handleActionTerminal.bind(bridge)
43704
+ ),
43705
+ "action.failed": providerHandler(
43706
+ "action.failed",
43707
+ bridge.handleActionTerminal.bind(bridge)
43708
+ ),
43709
+ "action.started": providerHandler(
43710
+ "action.started",
43711
+ bridge.handleActionStarted.bind(bridge)
43712
+ ),
43713
+ "model.call.completed": providerHandler(
43714
+ "model.call.completed",
43715
+ bridge.handleModelTerminal.bind(bridge)
43716
+ ),
43717
+ "model.call.failed": providerHandler(
43718
+ "model.call.failed",
43719
+ bridge.handleModelTerminal.bind(bridge)
43720
+ ),
43721
+ "model.call.started": providerHandler(
43722
+ "model.call.started",
43723
+ bridge.handleModelStarted.bind(bridge)
43724
+ ),
43725
+ "step.attempt.completed": providerHandler(
43726
+ "step.attempt.completed",
43727
+ (event) => bridge.handleStepAttemptTerminal(event)
43728
+ ),
43729
+ "step.attempt.failed": providerHandler(
43730
+ "step.attempt.failed",
43731
+ (event) => bridge.handleStepAttemptTerminal(event)
43732
+ ),
43733
+ "turn.cancelled": providerHandler(
43734
+ "turn.cancelled",
43735
+ bridge.handleTurnTerminal.bind(bridge)
43736
+ ),
43737
+ "turn.completed": providerHandler(
43738
+ "turn.completed",
43739
+ bridge.handleTurnTerminal.bind(bridge)
43740
+ ),
43741
+ "turn.failed": providerHandler(
43742
+ "turn.failed",
43743
+ bridge.handleTurnTerminal.bind(bridge)
43744
+ ),
43745
+ "turn.started": providerHandler(
43746
+ "turn.started",
43747
+ bridge.handleTurnStarted.bind(bridge)
43748
+ )
42237
43749
  },
42238
43750
  flush,
42239
43751
  setup: options.setup
@@ -42589,17 +44101,20 @@ function modelOutput(event) {
42589
44101
  const reasoning = [];
42590
44102
  const toolCalls2 = [];
42591
44103
  for (const part of content) {
42592
- if (part.type === "text") {
42593
- text += part.text;
42594
- } else if (part.type === "reasoning" && part.text.trim().length > 0) {
42595
- reasoning.push({ content: part.text });
42596
- } else if (part.type === "tool-call") {
44104
+ if (!isObject(part)) {
44105
+ continue;
44106
+ }
44107
+ if (part["type"] === "text" && typeof part["text"] === "string") {
44108
+ text += part["text"];
44109
+ } else if (part["type"] === "reasoning" && typeof part["text"] === "string" && part["text"].trim().length > 0) {
44110
+ reasoning.push({ content: part["text"] });
44111
+ } else if (part["type"] === "tool-call" && typeof part["toolName"] === "string" && typeof part["callId"] === "string") {
42597
44112
  toolCalls2.push({
42598
44113
  function: {
42599
- arguments: safeJsonStringify(part.input),
42600
- name: part.toolName
44114
+ arguments: safeJsonStringify(part["input"]),
44115
+ name: part["toolName"]
42601
44116
  },
42602
- id: part.callId,
44117
+ id: part["callId"],
42603
44118
  type: "function"
42604
44119
  });
42605
44120
  }
@@ -42618,13 +44133,13 @@ function modelOutput(event) {
42618
44133
  ];
42619
44134
  }
42620
44135
  function usageMetrics(usage) {
42621
- const promptTokens = nonNegativeNumber(usage.inputTokens);
42622
- const completionTokens = nonNegativeNumber(usage.outputTokens);
44136
+ const promptTokens = nonNegativeNumber(usage?.inputTokens);
44137
+ const completionTokens = nonNegativeNumber(usage?.outputTokens);
42623
44138
  const cachedTokens = nonNegativeNumber(
42624
- usage.inputTokenDetails?.cacheReadTokens
44139
+ usage?.inputTokenDetails?.cacheReadTokens
42625
44140
  );
42626
44141
  const cacheCreationTokens = nonNegativeNumber(
42627
- usage.inputTokenDetails?.cacheWriteTokens
44142
+ usage?.inputTokenDetails?.cacheWriteTokens
42628
44143
  );
42629
44144
  return {
42630
44145
  ...promptTokens !== void 0 ? { prompt_tokens: promptTokens } : {},
@@ -42661,10 +44176,76 @@ function turnIdempotencyKey(sessionId, turnId) {
42661
44176
  function actionIdempotencyKey(sessionId, turnId, callId) {
42662
44177
  return `action:${sessionId}:${turnId}:${callId}`;
42663
44178
  }
44179
+ function providerHandler(type, handler) {
44180
+ return async (event, context) => {
44181
+ try {
44182
+ if (!isEveProviderEvent(event, type) || !isEveProviderContext(context)) {
44183
+ debugLogger.warn(`Ignoring malformed Eve provider ${type} event`);
44184
+ return;
44185
+ }
44186
+ await handler(event, context);
44187
+ } catch (error) {
44188
+ debugLogger.warn(`Error in Eve provider ${type}:`, error);
44189
+ }
44190
+ };
44191
+ }
44192
+ function isEveProviderEvent(event, type) {
44193
+ if (!isObject(event) || event["type"] !== type || typeof event["idempotencyKey"] !== "string" || event["idempotencyKey"].length === 0) {
44194
+ return false;
44195
+ }
44196
+ if (type === "turn.started") {
44197
+ const parentLineage = event["parentLineage"];
44198
+ return typeof event["rootSessionId"] === "string" && typeof event["sessionId"] === "string" && typeof event["turnId"] === "string" && typeof event["sequence"] === "number" && Number.isFinite(event["sequence"]) && (parentLineage === void 0 || isEveProviderParentLineage(parentLineage));
44199
+ }
44200
+ if (type === "turn.cancelled" || type === "turn.completed" || type === "turn.failed") {
44201
+ return typeof event["sessionId"] === "string" && typeof event["turnId"] === "string";
44202
+ }
44203
+ if (!isEveProviderScope(event["scope"])) {
44204
+ return false;
44205
+ }
44206
+ if (type === "model.call.started") {
44207
+ const model = event["model"];
44208
+ return isObject(model) && typeof model["modelId"] === "string" && typeof model["provider"] === "string";
44209
+ }
44210
+ if (type === "model.call.completed") {
44211
+ return typeof event["finishReason"] === "string" && isObject(event["usage"]) && (event["content"] === void 0 || Array.isArray(event["content"]));
44212
+ }
44213
+ if (type === "model.call.failed") {
44214
+ return true;
44215
+ }
44216
+ if (type === "action.started") {
44217
+ return typeof event["callId"] === "string" && typeof event["name"] === "string" && (event["kind"] === "load-skill" || event["kind"] === "remote-agent-call" || event["kind"] === "subagent-call" || event["kind"] === "tool-call");
44218
+ }
44219
+ if (type === "action.completed") {
44220
+ const output = event["output"];
44221
+ return event["outcome"] === "completed" && isObject(output) && (output["type"] === "result" || output["type"] === "error");
44222
+ }
44223
+ if (type === "action.failed") {
44224
+ return event["outcome"] === "abandoned" || event["outcome"] === "cancelled" || event["outcome"] === "failed" || event["outcome"] === "rejected";
44225
+ }
44226
+ return type === "step.attempt.completed" || type === "step.attempt.failed";
44227
+ }
44228
+ function isEveProviderContext(value) {
44229
+ if (!isObject(value) || !isObject(value["state"])) {
44230
+ return false;
44231
+ }
44232
+ return typeof value["state"]["get"] === "function" && typeof value["state"]["set"] === "function";
44233
+ }
44234
+ function isEveProviderScope(value) {
44235
+ return isObject(value) && typeof value["attemptId"] === "string" && typeof value["attemptIndex"] === "number" && Number.isFinite(value["attemptIndex"]) && typeof value["sessionId"] === "string" && typeof value["stepIndex"] === "number" && Number.isFinite(value["stepIndex"]) && typeof value["turnId"] === "string" && (value["rootSessionId"] === void 0 || typeof value["rootSessionId"] === "string");
44236
+ }
44237
+ function isEveProviderParentLineage(value) {
44238
+ return isObject(value) && typeof value["callId"] === "string" && typeof value["sessionId"] === "string" && typeof value["turnId"] === "string";
44239
+ }
42664
44240
 
42665
44241
  // src/instrumentation/plugins/eve-instrumentation.ts
42666
44242
  var EVE_INSTRUMENTATION_PROVIDER = /* @__PURE__ */ Symbol.for("eve.instrumentation.provider");
42667
44243
  function braintrustEveInstrumentation(options) {
44244
+ if (!options || typeof options !== "object") {
44245
+ throw new TypeError(
44246
+ "braintrustEveInstrumentation requires an options object"
44247
+ );
44248
+ }
42668
44249
  const definition = "defineState" in options ? createLegacyEveInstrumentation(options) : createEveInstrumentationProvider(options);
42669
44250
  const declaration = {
42670
44251
  ...definition,
@@ -43901,6 +45482,7 @@ function wrapClient(client) {
43901
45482
  }
43902
45483
 
43903
45484
  // src/wrappers/google-genai.ts
45485
+ var patchedHttpResponses = /* @__PURE__ */ new WeakSet();
43904
45486
  function wrapGoogleGenAI(googleGenAI) {
43905
45487
  if (!googleGenAI || typeof googleGenAI !== "object") {
43906
45488
  console.warn("Invalid Google GenAI module. Not wrapping.");
@@ -43912,6 +45494,21 @@ function wrapGoogleGenAI(googleGenAI) {
43912
45494
  );
43913
45495
  return googleGenAI;
43914
45496
  }
45497
+ const httpResponse = googleGenAI.HttpResponse;
45498
+ if (typeof httpResponse === "function" && isObject(httpResponse.prototype) && typeof httpResponse.prototype.json === "function" && !patchedHttpResponses.has(httpResponse.prototype)) {
45499
+ const prototype = httpResponse.prototype;
45500
+ const originalJson = prototype.json;
45501
+ if (Reflect.set(prototype, "json", function() {
45502
+ return googleGenAIChannels.httpResponseJson.invoke(
45503
+ originalJson,
45504
+ this,
45505
+ [],
45506
+ {}
45507
+ );
45508
+ })) {
45509
+ patchedHttpResponses.add(prototype);
45510
+ }
45511
+ }
43915
45512
  return new Proxy(googleGenAI, {
43916
45513
  get(target, prop, receiver) {
43917
45514
  if (prop === "GoogleGenAI") {
@@ -44162,17 +45759,17 @@ function wrapGenkit(genkit) {
44162
45759
  console.warn("Unsupported Genkit object. Not wrapping.");
44163
45760
  return genkit;
44164
45761
  }
44165
- function isRecord3(value) {
45762
+ function isRecord4(value) {
44166
45763
  return typeof value === "object" && value !== null;
44167
45764
  }
44168
45765
  function isPropertyBag(value) {
44169
- return isRecord3(value) || typeof value === "function";
45766
+ return isRecord4(value) || typeof value === "function";
44170
45767
  }
44171
45768
  function hasFunction(value, methodName) {
44172
45769
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
44173
45770
  }
44174
45771
  function isGenkitInstance(value) {
44175
- return isRecord3(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
45772
+ return isRecord4(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
44176
45773
  }
44177
45774
  function isGenkitModule(value) {
44178
45775
  return hasFunction(value, "genkit");
@@ -44226,7 +45823,7 @@ function patchGenkitRegistry(instance) {
44226
45823
  patchGenkitRegistryConstructor(registry2);
44227
45824
  }
44228
45825
  function patchGenkitRegistryLookup(registry2) {
44229
- if (!isRecord3(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
45826
+ if (!isRecord4(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
44230
45827
  return;
44231
45828
  }
44232
45829
  const originalLookupAction = registry2.lookupAction;
@@ -44252,7 +45849,7 @@ function patchGenkitRegistryLookup(registry2) {
44252
45849
  }
44253
45850
  }
44254
45851
  function patchGenkitRegistryConstructor(registry2) {
44255
- if (!isRecord3(registry2)) {
45852
+ if (!isRecord4(registry2)) {
44256
45853
  return;
44257
45854
  }
44258
45855
  const constructor = registry2.constructor;
@@ -44268,7 +45865,7 @@ function patchGenkitRegistryConstructor(registry2) {
44268
45865
  configurable: true,
44269
45866
  value: (...args) => {
44270
45867
  const childRegistry = originalWithParent.apply(constructor, args);
44271
- if (args.some((arg) => isRecord3(arg) && hasRegistryPatchedFlag(arg))) {
45868
+ if (args.some((arg) => isRecord4(arg) && hasRegistryPatchedFlag(arg))) {
44272
45869
  patchGenkitRegistryLookup(childRegistry);
44273
45870
  patchGenkitRegistryConstructor(childRegistry);
44274
45871
  }
@@ -44367,7 +45964,7 @@ function hasRegistryConstructorPatchedFlag(value) {
44367
45964
  );
44368
45965
  }
44369
45966
  function isPromiseLike2(value) {
44370
- return isRecord3(value) && "then" in value && typeof value.then === "function";
45967
+ return isRecord4(value) && "then" in value && typeof value.then === "function";
44371
45968
  }
44372
45969
 
44373
45970
  // src/wrappers/huggingface.ts
@@ -44844,14 +46441,14 @@ function wrapMistral(mistral) {
44844
46441
  console.warn("Unsupported Mistral library. Not wrapping.");
44845
46442
  return mistral;
44846
46443
  }
44847
- function isRecord4(value) {
46444
+ function isRecord5(value) {
44848
46445
  return typeof value === "object" && value !== null;
44849
46446
  }
44850
46447
  function hasFunction3(value, methodName) {
44851
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
46448
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
44852
46449
  }
44853
46450
  function isSupportedMistralClient(value) {
44854
- if (!isRecord4(value)) {
46451
+ if (!isRecord5(value)) {
44855
46452
  return false;
44856
46453
  }
44857
46454
  return value.chat !== void 0 && hasChat(value.chat) || value.embeddings !== void 0 && hasEmbeddings(value.embeddings) || value.fim !== void 0 && hasFim(value.fim) || value.agents !== void 0 && hasAgents(value.agents) || value.classifiers !== void 0 && hasClassifiers(value.classifiers);
@@ -45026,6 +46623,42 @@ function wrapAgentsStream(stream) {
45026
46623
  });
45027
46624
  }
45028
46625
 
46626
+ // src/wrappers/langgraph-sdk.ts
46627
+ var clients = /* @__PURE__ */ new WeakMap();
46628
+ function wrapLangGraphSDK(client) {
46629
+ const runsClient = isObject(client) ? client.runs : void 0;
46630
+ if (!isObject(client) || !isObject(runsClient) || !["wait", "stream"].every((key) => typeof runsClient[key] === "function")) {
46631
+ debugLogger.warn("Unsupported LangGraph SDK client. Not wrapping.");
46632
+ return client;
46633
+ }
46634
+ const sdk = client;
46635
+ const cached = clients.get(sdk);
46636
+ if (cached) return cached;
46637
+ const runs = new Proxy(sdk.runs, {
46638
+ get(target, key) {
46639
+ switch (key) {
46640
+ case "wait":
46641
+ return (...args) => langGraphSDKChannels.wait.invoke(target.wait, target, args, {});
46642
+ case "stream":
46643
+ return (...args) => langGraphSDKChannels.stream.invoke(target.stream, target, args, {});
46644
+ default:
46645
+ const value = Reflect.get(target, key, target);
46646
+ return typeof value === "function" ? value.bind(target) : value;
46647
+ }
46648
+ }
46649
+ });
46650
+ const wrapped = new Proxy(sdk, {
46651
+ get(target, key) {
46652
+ if (key === "runs") return runs;
46653
+ const value = Reflect.get(target, key, target);
46654
+ return typeof value === "function" ? value.bind(target) : value;
46655
+ }
46656
+ });
46657
+ clients.set(sdk, wrapped);
46658
+ clients.set(wrapped, wrapped);
46659
+ return wrapped;
46660
+ }
46661
+
45029
46662
  // src/wrappers/ollama.ts
45030
46663
  function wrapOllama(ollama) {
45031
46664
  if (isSupportedOllamaClient(ollama)) {
@@ -45112,14 +46745,14 @@ function wrapCohere(cohere) {
45112
46745
  return cohere;
45113
46746
  }
45114
46747
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
45115
- function isRecord5(value) {
46748
+ function isRecord6(value) {
45116
46749
  return typeof value === "object" && value !== null;
45117
46750
  }
45118
46751
  function hasFunction4(value, methodName) {
45119
- return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
46752
+ return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
45120
46753
  }
45121
46754
  function isSupportedCohereClient(value) {
45122
- if (!isRecord5(value)) {
46755
+ if (!isRecord6(value)) {
45123
46756
  return false;
45124
46757
  }
45125
46758
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -45257,20 +46890,20 @@ function wrapGroq(groq) {
45257
46890
  console.warn("Unsupported Groq library. Not wrapping.");
45258
46891
  return groq;
45259
46892
  }
45260
- function isRecord6(value) {
46893
+ function isRecord7(value) {
45261
46894
  return typeof value === "object" && value !== null;
45262
46895
  }
45263
46896
  function hasFunction6(value, methodName) {
45264
- return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
46897
+ return isRecord7(value) && methodName in value && typeof value[methodName] === "function";
45265
46898
  }
45266
46899
  function hasChat2(value) {
45267
- return isRecord6(value) && isRecord6(value.completions) && hasFunction6(value.completions, "create");
46900
+ return isRecord7(value) && isRecord7(value.completions) && hasFunction6(value.completions, "create");
45268
46901
  }
45269
46902
  function hasEmbeddings2(value) {
45270
46903
  return hasFunction6(value, "create");
45271
46904
  }
45272
46905
  function isSupportedGroqClient(value) {
45273
- return isRecord6(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
46906
+ return isRecord7(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
45274
46907
  }
45275
46908
  function groqProxy(groq) {
45276
46909
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -45353,11 +46986,11 @@ var BEDROCK_RUNTIME_OPERATION_METHODS = /* @__PURE__ */ new Set([
45353
46986
  "invokeModelWithBidirectionalStream",
45354
46987
  "invokeModelWithResponseStream"
45355
46988
  ]);
45356
- function isRecord7(value) {
46989
+ function isRecord8(value) {
45357
46990
  return typeof value === "object" && value !== null;
45358
46991
  }
45359
46992
  function isSupportedBedrockRuntimeClient(value) {
45360
- return isRecord7(value) && typeof value.send === "function";
46993
+ return isRecord8(value) && typeof value.send === "function";
45361
46994
  }
45362
46995
  function bedrockRuntimeProxy(client) {
45363
46996
  const cached = bedrockRuntimeProxyCache.get(client);
@@ -47683,12 +49316,272 @@ function waterfall(tasks, callback) {
47683
49316
  }
47684
49317
  var waterfall$1 = awaitify(waterfall);
47685
49318
 
49319
+ // src/framework.ts
49320
+ import { v5 as uuidv5 } from "uuid";
49321
+
47686
49322
  // src/trace.ts
49323
+ var spanFilterFields = /* @__PURE__ */ new Set([
49324
+ "spanType",
49325
+ "name",
49326
+ "hasError",
49327
+ "metadata",
49328
+ "duration"
49329
+ ]);
49330
+ function isRecord9(value) {
49331
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
49332
+ return false;
49333
+ }
49334
+ const prototype = Object.getPrototypeOf(value);
49335
+ return prototype === Object.prototype || prototype === null;
49336
+ }
49337
+ function validateMetadataValue(value, ancestors) {
49338
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
49339
+ return;
49340
+ }
49341
+ if (typeof value === "number") {
49342
+ if (Number.isFinite(value)) {
49343
+ return;
49344
+ }
49345
+ throw new Error("filters.metadata numbers must be finite");
49346
+ }
49347
+ if (typeof value !== "object" || value === null) {
49348
+ throw new Error("filters.metadata values must be JSON-serializable");
49349
+ }
49350
+ if (!Array.isArray(value) && !isRecord9(value)) {
49351
+ throw new Error("filters.metadata values must be JSON-serializable");
49352
+ }
49353
+ if (ancestors.has(value)) {
49354
+ throw new Error("filters.metadata must not contain cycles");
49355
+ }
49356
+ ancestors.add(value);
49357
+ if (Array.isArray(value)) {
49358
+ for (let index = 0; index < value.length; index++) {
49359
+ validateMetadataValue(value[index], ancestors);
49360
+ }
49361
+ } else {
49362
+ if (Object.getOwnPropertySymbols(value).length > 0) {
49363
+ throw new Error("filters.metadata keys must be strings");
49364
+ }
49365
+ for (const nested of Object.values(value)) {
49366
+ validateMetadataValue(nested, ancestors);
49367
+ }
49368
+ }
49369
+ ancestors.delete(value);
49370
+ }
49371
+ function compileMetadataLeaves(metadata, path = [], ancestors = /* @__PURE__ */ new WeakSet()) {
49372
+ if (Object.getOwnPropertySymbols(metadata).length > 0) {
49373
+ throw new Error("filters.metadata keys must be strings");
49374
+ }
49375
+ if (ancestors.has(metadata)) {
49376
+ throw new Error("filters.metadata must not contain cycles");
49377
+ }
49378
+ ancestors.add(metadata);
49379
+ const leaves = [];
49380
+ for (const [key, value] of Object.entries(metadata)) {
49381
+ const childPath = [...path, key];
49382
+ if (isRecord9(value)) {
49383
+ leaves.push(...compileMetadataLeaves(value, childPath, ancestors));
49384
+ } else {
49385
+ validateMetadataValue(value, ancestors);
49386
+ leaves.push([childPath, value]);
49387
+ }
49388
+ }
49389
+ ancestors.delete(metadata);
49390
+ return leaves;
49391
+ }
49392
+ function normalizeSpanFilters(filters, spanType) {
49393
+ if (filters != null && !isRecord9(filters)) {
49394
+ throw new Error("filters must be an object");
49395
+ }
49396
+ const values = { ...filters ?? {} };
49397
+ if (spanType !== void 0) {
49398
+ if (!Array.isArray(spanType) || !spanType.every((item) => typeof item === "string")) {
49399
+ throw new Error("spanType must be an array of strings");
49400
+ }
49401
+ if (Object.hasOwn(values, "spanType")) {
49402
+ throw new Error(
49403
+ "spanType cannot be provided both directly and in filters"
49404
+ );
49405
+ }
49406
+ if (spanType.length > 0) {
49407
+ values.spanType = spanType;
49408
+ }
49409
+ }
49410
+ if (Object.keys(values).some((field) => !spanFilterFields.has(field))) {
49411
+ throw new Error("Unsupported span filter fields");
49412
+ }
49413
+ for (const field of ["spanType", "name"]) {
49414
+ if (Object.hasOwn(values, field)) {
49415
+ const items = values[field];
49416
+ if (!Array.isArray(items) || !items.every((item) => typeof item === "string")) {
49417
+ throw new Error(`filters.${field} must be an array of strings`);
49418
+ }
49419
+ }
49420
+ }
49421
+ if (Object.hasOwn(values, "hasError") && typeof values.hasError !== "boolean") {
49422
+ throw new Error("filters.hasError must be a boolean");
49423
+ }
49424
+ let compiledMetadataLeaves = [];
49425
+ if (Object.hasOwn(values, "metadata")) {
49426
+ if (!isRecord9(values.metadata)) {
49427
+ throw new Error("filters.metadata must be an object");
49428
+ }
49429
+ compiledMetadataLeaves = compileMetadataLeaves(values.metadata);
49430
+ }
49431
+ if (Object.hasOwn(values, "duration")) {
49432
+ if (!isRecord9(values.duration) || Object.keys(values.duration).some(
49433
+ (bound) => bound !== "min" && bound !== "max"
49434
+ )) {
49435
+ throw new Error("filters.duration must contain only min and/or max");
49436
+ }
49437
+ if (Object.values(values.duration).some(
49438
+ (bound) => typeof bound !== "number" || !Number.isFinite(bound)
49439
+ )) {
49440
+ throw new Error("filters.duration bounds must be finite numbers");
49441
+ }
49442
+ }
49443
+ const normalized = {};
49444
+ if (Array.isArray(values.spanType)) {
49445
+ normalized.spanType = values.spanType;
49446
+ }
49447
+ if (Array.isArray(values.name)) {
49448
+ normalized.name = values.name;
49449
+ }
49450
+ if (typeof values.hasError === "boolean") {
49451
+ normalized.hasError = values.hasError;
49452
+ }
49453
+ if (isRecord9(values.metadata)) {
49454
+ normalized.metadata = values.metadata;
49455
+ }
49456
+ if (isRecord9(values.duration)) {
49457
+ normalized.duration = {};
49458
+ if (typeof values.duration.min === "number") {
49459
+ normalized.duration.min = values.duration.min;
49460
+ }
49461
+ if (typeof values.duration.max === "number") {
49462
+ normalized.duration.max = values.duration.max;
49463
+ }
49464
+ }
49465
+ return { filters: normalized, metadataLeaves: compiledMetadataLeaves };
49466
+ }
49467
+ function metadataEqual(actual, expected) {
49468
+ if (expected === null) {
49469
+ return actual === null || actual === void 0;
49470
+ }
49471
+ if (Array.isArray(expected)) {
49472
+ return Array.isArray(actual) && actual.length === expected.length && expected.every((value, index) => metadataEqual(actual[index], value));
49473
+ }
49474
+ if (isRecord9(expected)) {
49475
+ if (!isRecord9(actual)) {
49476
+ return false;
49477
+ }
49478
+ const expectedKeys = Object.keys(expected);
49479
+ const actualKeys = Object.keys(actual);
49480
+ return actualKeys.length === expectedKeys.length && expectedKeys.every(
49481
+ (key) => Object.hasOwn(actual, key) && metadataEqual(actual[key], expected[key])
49482
+ );
49483
+ }
49484
+ return actual === expected;
49485
+ }
49486
+ function matchesSpanFilters(span, compiledFilters) {
49487
+ const { filters, metadataLeaves } = compiledFilters;
49488
+ if (filters.spanType !== void 0 && !filters.spanType.includes(span.span_attributes?.type ?? "")) {
49489
+ return false;
49490
+ }
49491
+ if (filters.name !== void 0 && !filters.name.includes(span.span_attributes?.name ?? "")) {
49492
+ return false;
49493
+ }
49494
+ if (filters.hasError !== void 0 && (span.error !== null && span.error !== void 0) !== filters.hasError) {
49495
+ return false;
49496
+ }
49497
+ for (const [path, expected] of metadataLeaves) {
49498
+ let actual = span.metadata;
49499
+ for (const key of path) {
49500
+ actual = isRecord9(actual) && Object.hasOwn(actual, key) ? actual[key] : void 0;
49501
+ }
49502
+ if (!metadataEqual(actual, expected)) {
49503
+ return false;
49504
+ }
49505
+ }
49506
+ if (filters.duration && Object.keys(filters.duration).length > 0) {
49507
+ const metrics = span.metrics;
49508
+ const start = isRecord9(metrics) ? metrics.start : void 0;
49509
+ const end = isRecord9(metrics) ? metrics.end : void 0;
49510
+ if (typeof start !== "number" || !Number.isFinite(start) || typeof end !== "number" || !Number.isFinite(end)) {
49511
+ return false;
49512
+ }
49513
+ const elapsed = end - start;
49514
+ if (filters.duration.min !== void 0 && elapsed < filters.duration.min) {
49515
+ return false;
49516
+ }
49517
+ if (filters.duration.max !== void 0 && elapsed > filters.duration.max) {
49518
+ return false;
49519
+ }
49520
+ }
49521
+ return true;
49522
+ }
49523
+ function btqlComparison(op, name, value) {
49524
+ return {
49525
+ op,
49526
+ left: { op: "ident", name },
49527
+ right: { op: "literal", value }
49528
+ };
49529
+ }
49530
+ function btqlNullCheck(op, name) {
49531
+ return { op, expr: { op: "ident", name } };
49532
+ }
49533
+ function spanFilterClauses(compiledFilters) {
49534
+ const { filters, metadataLeaves } = compiledFilters;
49535
+ const children = [];
49536
+ for (const [field, attribute] of [
49537
+ ["spanType", "type"],
49538
+ ["name", "name"]
49539
+ ]) {
49540
+ const values = filters[field];
49541
+ if (values !== void 0) {
49542
+ children.push(
49543
+ values.length > 0 ? btqlComparison("in", ["span_attributes", attribute], values) : { op: "literal", value: false }
49544
+ );
49545
+ }
49546
+ }
49547
+ if (filters.hasError !== void 0) {
49548
+ children.push(
49549
+ btqlNullCheck(filters.hasError ? "isnotnull" : "isnull", ["error"])
49550
+ );
49551
+ }
49552
+ for (const [path, value] of metadataLeaves) {
49553
+ const name = ["metadata", ...path];
49554
+ children.push(
49555
+ value === null ? btqlNullCheck("isnull", name) : btqlComparison("eq", name, value)
49556
+ );
49557
+ }
49558
+ const elapsed = {
49559
+ op: "sub",
49560
+ left: { op: "ident", name: ["metrics", "end"] },
49561
+ right: { op: "ident", name: ["metrics", "start"] }
49562
+ };
49563
+ if (filters.duration?.min !== void 0) {
49564
+ children.push({
49565
+ op: "ge",
49566
+ left: elapsed,
49567
+ right: { op: "literal", value: filters.duration.min }
49568
+ });
49569
+ }
49570
+ if (filters.duration?.max !== void 0) {
49571
+ children.push({
49572
+ op: "le",
49573
+ left: elapsed,
49574
+ right: { op: "literal", value: filters.duration.max }
49575
+ });
49576
+ }
49577
+ return children;
49578
+ }
47687
49579
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
47688
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false, brainstoreRealtime = true) {
49580
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false, brainstoreRealtime = true, filters) {
49581
+ const normalizedFilters = normalizeSpanFilters(filters, spanTypeFilter);
47689
49582
  const filterExpr = _SpanFetcher.buildFilter(
47690
49583
  rootSpanId,
47691
- spanTypeFilter,
49584
+ normalizedFilters,
47692
49585
  includeScorers
47693
49586
  );
47694
49587
  super(
@@ -47709,42 +49602,22 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
47709
49602
  rootSpanId;
47710
49603
  _state;
47711
49604
  spanTypeFilter;
47712
- static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
49605
+ static buildFilter(rootSpanId, filters, includeScorers = false) {
49606
+ const purpose = ["span_attributes", "purpose"];
47713
49607
  const children = [
47714
- // Base filter: root_span_id = 'value'
47715
- {
47716
- op: "eq",
47717
- left: { op: "ident", name: ["root_span_id"] },
47718
- right: { op: "literal", value: rootSpanId }
47719
- }
49608
+ btqlComparison("eq", ["root_span_id"], rootSpanId)
47720
49609
  ];
47721
49610
  if (!includeScorers) {
47722
49611
  children.push({
47723
49612
  op: "or",
47724
49613
  children: [
47725
- {
47726
- op: "isnull",
47727
- expr: { op: "ident", name: ["span_attributes", "purpose"] }
47728
- },
47729
- {
47730
- op: "ne",
47731
- left: { op: "ident", name: ["span_attributes", "purpose"] },
47732
- right: { op: "literal", value: "scorer" }
47733
- }
49614
+ btqlNullCheck("isnull", purpose),
49615
+ btqlComparison("ne", purpose, "scorer")
47734
49616
  ]
47735
49617
  });
47736
49618
  }
47737
- if (spanTypeFilter && spanTypeFilter.length > 0) {
47738
- children.push({
47739
- op: "in",
47740
- left: { op: "ident", name: ["span_attributes", "type"] },
47741
- right: { op: "literal", value: spanTypeFilter }
47742
- });
47743
- }
47744
- return {
47745
- op: "and",
47746
- children
47747
- };
49619
+ children.push(...spanFilterClauses(filters));
49620
+ return { op: "and", children };
47748
49621
  }
47749
49622
  get id() {
47750
49623
  return Promise.resolve(this._objectId);
@@ -47759,67 +49632,80 @@ var CachedSpanFetcher = class {
47759
49632
  fetchFn;
47760
49633
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState, brainstoreRealtime = true) {
47761
49634
  if (typeof objectTypeOrFetchFn === "function") {
47762
- this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
49635
+ this.fetchFn = async (filters) => (await objectTypeOrFetchFn(filters.filters.spanType)).filter(
49636
+ (span) => matchesSpanFilters(span, filters)
49637
+ );
47763
49638
  } else {
47764
49639
  const objectType = objectTypeOrFetchFn;
47765
- this.fetchFn = async (spanType, includeScorers) => {
49640
+ this.fetchFn = async (filters, includeScorers) => {
47766
49641
  const state = await getState();
47767
49642
  const fetcher = new SpanFetcher(
47768
49643
  objectType,
47769
49644
  objectId,
47770
49645
  rootSpanId,
47771
49646
  state,
47772
- spanType,
49647
+ void 0,
47773
49648
  includeScorers,
47774
- brainstoreRealtime
49649
+ brainstoreRealtime,
49650
+ filters.filters
47775
49651
  );
47776
- const rows = await fetcher.fetchedData();
47777
- return rows.map((row) => ({
47778
- input: row.input,
47779
- output: row.output,
47780
- expected: row.expected,
47781
- error: row.error,
47782
- scores: row.scores,
47783
- metrics: row.metrics,
47784
- metadata: row.metadata,
47785
- span_id: row.span_id,
47786
- span_parents: row.span_parents,
47787
- is_root: row.is_root,
47788
- span_attributes: row.span_attributes,
47789
- id: row.id,
47790
- _xact_id: row._xact_id,
47791
- _pagination_key: row._pagination_key,
47792
- root_span_id: row.root_span_id,
47793
- created: row.created,
47794
- tags: row.tags
47795
- }));
49652
+ let spans = (await fetcher.fetchedData()).map(
49653
+ (row) => ({ ...row })
49654
+ );
49655
+ if (filters.filters.metadata !== void 0) {
49656
+ spans = spans.filter((span) => matchesSpanFilters(span, filters));
49657
+ }
49658
+ return spans;
47796
49659
  };
47797
49660
  }
47798
49661
  }
47799
49662
  async getSpans({
47800
- spanType,
49663
+ spanType: requestedSpanType,
49664
+ filters,
47801
49665
  includeScorers = false
47802
49666
  } = {}) {
49667
+ const normalizedFilters = normalizeSpanFilters(filters, requestedSpanType);
49668
+ const spanType = normalizedFilters.filters.spanType;
49669
+ const hasAdvancedFilters = Object.keys(normalizedFilters.filters).some(
49670
+ (field) => field !== "spanType"
49671
+ );
49672
+ if (spanType?.length === 0) {
49673
+ return [];
49674
+ }
47803
49675
  if (includeScorers) {
47804
- return this.fetchFn(spanType, true);
49676
+ return this.fetchFn(normalizedFilters, true);
47805
49677
  }
47806
49678
  if (this.allFetched) {
47807
- return this.getFromCache(spanType);
49679
+ const spans = this.getFromCache(spanType);
49680
+ return hasAdvancedFilters ? spans.filter((span) => matchesSpanFilters(span, normalizedFilters)) : spans;
47808
49681
  }
47809
- if (!spanType || spanType.length === 0) {
49682
+ if (hasAdvancedFilters && spanType && spanType.every((type) => this.spanCache.has(type))) {
49683
+ return this.getFromCache(spanType).filter(
49684
+ (span) => matchesSpanFilters(span, normalizedFilters)
49685
+ );
49686
+ }
49687
+ if (hasAdvancedFilters) {
49688
+ return this.fetchFn(normalizedFilters, false);
49689
+ }
49690
+ if (!spanType) {
49691
+ this.spanCache.clear();
47810
49692
  await this.fetchSpans(void 0);
47811
- this.allFetched = true;
49693
+ if (this.spanCache.size > 0) {
49694
+ this.allFetched = true;
49695
+ }
47812
49696
  return this.getFromCache(void 0);
47813
49697
  }
47814
- const missingTypes = spanType.filter((t) => !this.spanCache.has(t));
47815
- if (missingTypes.length === 0) {
47816
- return this.getFromCache(spanType);
49698
+ const missingTypes = spanType.filter((type) => !this.spanCache.has(type));
49699
+ if (missingTypes.length > 0) {
49700
+ await this.fetchSpans(missingTypes);
47817
49701
  }
47818
- await this.fetchSpans(missingTypes);
47819
49702
  return this.getFromCache(spanType);
47820
49703
  }
47821
49704
  async fetchSpans(spanType) {
47822
- const spans = await this.fetchFn(spanType, false);
49705
+ const spans = await this.fetchFn(
49706
+ normalizeSpanFilters(spanType ? { spanType } : void 0),
49707
+ false
49708
+ );
47823
49709
  for (const span of spans) {
47824
49710
  const type = span.span_attributes?.type ?? "";
47825
49711
  const existing = this.spanCache.get(type) ?? [];
@@ -47899,34 +49785,20 @@ var LocalTrace = class {
47899
49785
  */
47900
49786
  async getSpans({
47901
49787
  spanType,
49788
+ filters,
47902
49789
  includeScorers = false
47903
49790
  } = {}) {
49791
+ const normalizedFilters = normalizeSpanFilters(filters, spanType);
47904
49792
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
47905
49793
  if (cachedSpans && cachedSpans.length > 0) {
47906
- let spans = includeScorers ? cachedSpans : cachedSpans.filter(
47907
- (span) => span.span_attributes?.purpose !== "scorer"
47908
- );
47909
- if (spanType && spanType.length > 0) {
47910
- spans = spans.filter(
47911
- (span) => spanType.includes(span.span_attributes?.type ?? "")
47912
- );
47913
- }
47914
- return spans.map((span) => ({
47915
- input: span.input,
47916
- output: span.output,
47917
- expected: span.expected,
47918
- error: span.error,
47919
- scores: span.scores,
47920
- metrics: span.metrics,
47921
- metadata: span.metadata,
47922
- span_id: span.span_id,
47923
- span_parents: span.span_parents,
47924
- is_root: span.is_root,
47925
- span_attributes: span.span_attributes,
47926
- tags: span.tags
47927
- }));
47928
- }
47929
- return this.cachedFetcher.getSpans({ spanType, includeScorers });
49794
+ return cachedSpans.filter(
49795
+ (span) => (includeScorers || span.span_attributes?.purpose !== "scorer") && matchesSpanFilters({ ...span }, normalizedFilters)
49796
+ ).map((span) => ({ ...span }));
49797
+ }
49798
+ return this.cachedFetcher.getSpans({
49799
+ filters: normalizedFilters.filters,
49800
+ includeScorers
49801
+ });
47930
49802
  }
47931
49803
  /**
47932
49804
  * Get the thread (preprocessed messages) for this trace.
@@ -48346,7 +50218,7 @@ async function Eval(name, evaluator, reporterOrOpts) {
48346
50218
  data,
48347
50219
  { disabled: Boolean(options.parent || options.noSendLogs) }
48348
50220
  );
48349
- if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
50221
+ if (experiment) {
48350
50222
  await experiment._waitForId();
48351
50223
  }
48352
50224
  if (experiment && options.onStart) {
@@ -48671,6 +50543,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
48671
50543
  } : void 0;
48672
50544
  const parsedDatumOrigin = ObjectReference.safeParse(datum.origin);
48673
50545
  const origin = inlineDatasetOrigin ?? (parsedDatumOrigin?.success ? parsedDatumOrigin.data : void 0);
50546
+ const upsertId = datum.upsert_id && trialIndex > 0 ? uuidv5(
50547
+ `braintrust:eval:${datum.upsert_id}:trial:${trialIndex}`,
50548
+ uuidv5.URL
50549
+ ) : datum.upsert_id;
48674
50550
  const baseEvent = {
48675
50551
  name: "eval",
48676
50552
  spanAttributes: {
@@ -48681,7 +50557,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
48681
50557
  expected: "expected" in datum ? datum.expected : void 0,
48682
50558
  tags: datum.tags,
48683
50559
  origin,
48684
- ...datum.upsert_id ? { id: datum.upsert_id } : {}
50560
+ ...upsertId ? { id: upsertId } : {}
48685
50561
  }
48686
50562
  };
48687
50563
  const callback = async (rootSpan) => {
@@ -49190,14 +51066,14 @@ var defaultReporter = {
49190
51066
  }
49191
51067
  };
49192
51068
 
49193
- // src/durable-eval.ts
51069
+ // src/workflow-eval.ts
49194
51070
  var encoder = new TextEncoder();
49195
51071
  var decoder = new TextDecoder();
49196
- var BATCH_TASK_KIND = "braintrust.durable.batch-task";
49197
- var BATCH_SCORER_KIND = "braintrust.durable.batch-scorer";
49198
- var DEFAULT_BATCH_SIZE = 1e3;
49199
- var DurableEvalMemoryStore = class {
51072
+ var WORKFLOW_TASK_KIND = "braintrust.workflow.task";
51073
+ var WORKFLOW_SCORER_KIND = "braintrust.workflow.scorer";
51074
+ var WorkflowEvalMemoryStore = class {
49200
51075
  values = /* @__PURE__ */ new Map();
51076
+ sets = /* @__PURE__ */ new Map();
49201
51077
  async read(key) {
49202
51078
  return this.values.get(key)?.slice();
49203
51079
  }
@@ -49210,8 +51086,16 @@ var DurableEvalMemoryStore = class {
49210
51086
  this.values.set(key, value.slice());
49211
51087
  return { value: value.slice(), created: true };
49212
51088
  }
51089
+ async addToSet(key, member) {
51090
+ let members = this.sets.get(key);
51091
+ if (!members) this.sets.set(key, members = /* @__PURE__ */ new Set());
51092
+ members.add(member);
51093
+ }
51094
+ async getSetSize(key) {
51095
+ return this.sets.get(key)?.size ?? 0;
51096
+ }
49213
51097
  };
49214
- var DurableEvalRedisStore = class {
51098
+ var WorkflowEvalRedisStore = class {
49215
51099
  client;
49216
51100
  keyPrefix;
49217
51101
  ttlMs;
@@ -49220,14 +51104,16 @@ var DurableEvalRedisStore = class {
49220
51104
  this.keyPrefix = options.keyPrefix ?? "braintrust-eval:";
49221
51105
  this.ttlMs = options.ttlMs ?? 1e3 * 60 * 60 * 24 * 7;
49222
51106
  if (!Number.isInteger(this.ttlMs) || this.ttlMs < 1) {
49223
- throw new Error("DurableEvalRedisStore ttlMs must be a positive integer");
51107
+ throw new Error(
51108
+ "WorkflowEvalRedisStore ttlMs must be a positive integer"
51109
+ );
49224
51110
  }
49225
51111
  }
49226
51112
  async read(key) {
49227
51113
  const value = await this.client.get(`${this.keyPrefix}${key}`);
49228
51114
  if (value == null) return void 0;
49229
51115
  if (typeof value !== "string") {
49230
- throw new Error("DurableEvalRedisStore expected GET to return a string");
51116
+ throw new Error("WorkflowEvalRedisStore expected GET to return a string");
49231
51117
  }
49232
51118
  return base64ToUint8Array(value);
49233
51119
  }
@@ -49244,7 +51130,7 @@ var DurableEvalRedisStore = class {
49244
51130
  await set.call(client, redisKey, encoded, { px: this.ttlMs });
49245
51131
  } else {
49246
51132
  throw new Error(
49247
- "DurableEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
51133
+ "WorkflowEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
49248
51134
  );
49249
51135
  }
49250
51136
  }
@@ -49262,49 +51148,73 @@ var DurableEvalRedisStore = class {
49262
51148
  setOptions = [{ px: this.ttlMs, nx: true, get: true }];
49263
51149
  } else {
49264
51150
  throw new Error(
49265
- "DurableEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
51151
+ "WorkflowEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
49266
51152
  );
49267
51153
  }
49268
51154
  const existing = await set.call(client, redisKey, encoded, ...setOptions);
49269
51155
  if (existing === null) return { value: value.slice(), created: true };
49270
51156
  if (typeof existing !== "string") {
49271
51157
  throw new Error(
49272
- "DurableEvalRedisStore expected atomic SET to return a string or null"
51158
+ "WorkflowEvalRedisStore expected atomic SET to return a string or null"
49273
51159
  );
49274
51160
  }
49275
51161
  return { value: base64ToUint8Array(existing), created: false };
49276
51162
  }
51163
+ async addToSet(key, member) {
51164
+ await this.evalSet(
51165
+ "redis.call('SADD', KEYS[1], ARGV[1]); redis.call('PEXPIRE', KEYS[1], ARGV[2]); return 1",
51166
+ key,
51167
+ [member, String(this.ttlMs)]
51168
+ );
51169
+ }
51170
+ async getSetSize(key) {
51171
+ return this.evalSet("return redis.call('SCARD', KEYS[1])", key, []);
51172
+ }
51173
+ async evalSet(script, key, args) {
51174
+ const client = this.client;
51175
+ const redisKey = `${this.keyPrefix}${key}`;
51176
+ const result = typeof client.defineCommand === "function" ? await client.eval(script, 1, redisKey, ...args) : typeof client.sendCommand === "function" ? await client.eval(script, { keys: [redisKey], arguments: args }) : await client.eval(script, [redisKey], args);
51177
+ if (typeof result !== "number") {
51178
+ throw new Error(
51179
+ "WorkflowEvalRedisStore expected EVAL to return a number"
51180
+ );
51181
+ }
51182
+ return result;
51183
+ }
49277
51184
  };
49278
- var BatchTask = class {
51185
+ var WorkflowTask = class {
49279
51186
  constructor(processor) {
49280
51187
  this.processor = processor;
49281
51188
  }
49282
51189
  processor;
49283
- kind = BATCH_TASK_KIND;
51190
+ kind = WORKFLOW_TASK_KIND;
49284
51191
  };
49285
- var BatchScorer = class {
51192
+ var WorkflowScorer = class {
49286
51193
  constructor(processor) {
49287
51194
  this.processor = processor;
49288
51195
  this.name = processor.name;
49289
51196
  }
49290
51197
  processor;
49291
- kind = BATCH_SCORER_KIND;
51198
+ kind = WORKFLOW_SCORER_KIND;
49292
51199
  name;
49293
51200
  };
49294
- function defineDurableEval(projectName, evaluator) {
51201
+ function defineWorkflowEval(projectName, evaluator) {
51202
+ if (evaluator.maxConcurrency !== void 0 && (!Number.isInteger(evaluator.maxConcurrency) || evaluator.maxConcurrency < 1)) {
51203
+ throw new Error("maxConcurrency must be a positive integer");
51204
+ }
49295
51205
  const definition = {
49296
51206
  projectName,
49297
51207
  evalName: evaluator.experimentName ?? projectName,
49298
51208
  evaluator
49299
51209
  };
49300
51210
  return {
49301
- start: (options = {}) => startDurableEval(definition, options),
49302
- status: (options) => getDurableEvalStatus(definition, options),
49303
- poll: (options) => pollDurableEval(definition, options),
49304
- processBatchResult: (result) => processDurableBatchResult(definition, result)
51211
+ start: (options = {}) => startWorkflowEval(definition, options),
51212
+ status: (options) => getWorkflowEvalStatus(definition, options),
51213
+ poll: (options) => pollWorkflowEval(definition, options),
51214
+ processSubmissionResult: (result) => processWorkflowSubmissionResult(definition, result)
49305
51215
  };
49306
51216
  }
49307
- async function startDurableEval(definition, options) {
51217
+ async function startWorkflowEval(definition, options) {
49308
51218
  const store = definition.evaluator.store;
49309
51219
  const runId = newId();
49310
51220
  const key = runKey(definition.projectName, definition.evalName, runId);
@@ -49324,7 +51234,7 @@ async function startDurableEval(definition, options) {
49324
51234
  update: true
49325
51235
  }
49326
51236
  );
49327
- if (!isBatchTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isBatchScorer)) {
51237
+ if (!isWorkflowTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isWorkflowScorer)) {
49328
51238
  const result = await runEvaluator(
49329
51239
  experiment,
49330
51240
  {
@@ -49351,67 +51261,91 @@ async function startDurableEval(definition, options) {
49351
51261
  parameters: assertJsonValue(parameters, "eval parameters"),
49352
51262
  status: "completed",
49353
51263
  summary: result.summary,
51264
+ caseCount: 0,
49354
51265
  cases: [],
49355
- batches: []
51266
+ submissions: []
49356
51267
  };
49357
51268
  await experiment?.flush();
49358
51269
  await writeRunRecord(store, key, state2);
49359
51270
  return currentStatus(definition, state2);
49360
51271
  }
51272
+ const cases = await materializeCases(definition, data, experiment);
49361
51273
  const state = {
49362
51274
  runId,
49363
51275
  experimentName,
49364
51276
  noSendLogs: options.noSendLogs ?? false,
49365
51277
  parameters: assertJsonValue(parameters, "eval parameters"),
49366
51278
  status: "running",
49367
- cases: await materializeCases(definition, data, experiment),
49368
- batches: []
51279
+ caseCount: cases.length,
51280
+ cases,
51281
+ submissions: []
49369
51282
  };
51283
+ await writeJson(
51284
+ store,
51285
+ `${key}/case-ids`,
51286
+ cases.map(({ id }) => id)
51287
+ );
49370
51288
  await writeCaseBaseRecords(store, key, state.cases);
49371
51289
  await writeRunRecord(store, key, state);
49372
- return advanceDurableEval(definition, state, store, key, experiment);
51290
+ return advanceWorkflowEval(definition, state, store, key, experiment);
49373
51291
  }
49374
- async function getDurableEvalStatus(definition, options) {
51292
+ async function getWorkflowEvalStatus(definition, options) {
49375
51293
  const store = definition.evaluator.store;
49376
- const state = await readRunState(
49377
- definition,
49378
- store,
49379
- runKey(definition.projectName, definition.evalName, options.runId)
51294
+ const key = runKey(
51295
+ definition.projectName,
51296
+ definition.evalName,
51297
+ options.runId
49380
51298
  );
49381
- if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
51299
+ const state = await readJson(store, key);
51300
+ if (!state) throw new Error(`Workflow eval run ${options.runId} is missing`);
49382
51301
  return currentStatus(definition, state);
49383
51302
  }
49384
- async function processDurableBatchResult(definition, result) {
49385
- if (!result.batchId && !result.externalId) {
49386
- throw new Error("Batch results require batchId or externalId");
51303
+ async function processWorkflowSubmissionResult(definition, result) {
51304
+ if (!result.submissionId && !result.externalId) {
51305
+ throw new Error("Submission results require submissionId or externalId");
49387
51306
  }
49388
51307
  const store = definition.evaluator.store;
49389
51308
  const key = runKey(definition.projectName, definition.evalName, result.runId);
49390
- const state = await readRunState(definition, store, key);
49391
- if (!state) throw new Error(`Durable eval run ${result.runId} is missing`);
49392
- const byBatch = result.batchId ? state.batches.find((candidate) => candidate.id === result.batchId) : void 0;
49393
- const byExternal = result.externalId ? state.batches.find(
49394
- (candidate) => candidate.externalId === result.externalId
51309
+ const run = await readJson(store, key);
51310
+ if (!run) throw new Error(`Workflow eval run ${result.runId} is missing`);
51311
+ const externalSubmissionId = result.externalId ? await readJson(
51312
+ store,
51313
+ `${key}/external/${encodedKeyPart(result.externalId)}`
51314
+ ) : void 0;
51315
+ if (result.submissionId && externalSubmissionId && result.submissionId !== externalSubmissionId) {
51316
+ throw new Error(
51317
+ "submissionId and externalId identify different submissions"
51318
+ );
51319
+ }
51320
+ const submissionId = result.submissionId ?? externalSubmissionId;
51321
+ const submission = submissionId ? await readJson(
51322
+ store,
51323
+ submissionRecordKey(key, submissionId)
49395
51324
  ) : void 0;
49396
- if (byBatch && byExternal && byBatch.id !== byExternal.id) {
49397
- throw new Error("batchId and externalId identify different batches");
49398
- }
49399
- const batch = byBatch ?? byExternal;
49400
- if (!batch) throw new Error("No submitted batch matches this result");
49401
- if (batch.status !== "complete") {
49402
- const records = await collectBatch(definition, state, batch);
49403
- batch.status = "complete";
49404
- await writeCaseRecords(store, key, records);
49405
- await writeBatchRecords(store, key, [batch]);
49406
- }
49407
- return advanceDurableEval(
51325
+ if (!submission) throw new Error("No submission matches this result");
51326
+ if (result.externalId && submission.externalId !== result.externalId) {
51327
+ throw new Error(
51328
+ "submissionId and externalId identify different submissions"
51329
+ );
51330
+ }
51331
+ if (run.status === "completed") return currentStatus(definition, run);
51332
+ const state = await readRunState(definition, store, key, [
51333
+ submission.itemId
51334
+ ]);
51335
+ if (submission.status !== "complete") {
51336
+ const record = await collectSubmission(definition, state, submission);
51337
+ await writeCaseRecords(store, key, [record]);
51338
+ submission.status = "complete";
51339
+ }
51340
+ await writeSubmissionRecords(store, key, [submission]);
51341
+ return advanceWorkflowEval(
49408
51342
  definition,
49409
- await readRunState(definition, store, key),
51343
+ await readRunState(definition, store, key, [submission.itemId]),
49410
51344
  store,
49411
51345
  key
49412
51346
  );
49413
51347
  }
49414
- async function pollDurableEval(definition, options) {
51348
+ async function pollWorkflowEval(definition, options) {
49415
51349
  const store = definition.evaluator.store;
49416
51350
  const key = runKey(
49417
51351
  definition.projectName,
@@ -49419,39 +51353,53 @@ async function pollDurableEval(definition, options) {
49419
51353
  options.runId
49420
51354
  );
49421
51355
  const state = await readRunState(definition, store, key);
49422
- if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
49423
- const batches = state.batches.filter((batch) => {
49424
- if (batch.status === "complete") return false;
49425
- return processorForStage(definition, batch.kind, batch.scorerName).completion.mode === "poll";
49426
- });
49427
- const results = await Promise.all(
49428
- batches.map(async (batch) => ({
49429
- batch,
49430
- result: await processorForStage(definition, batch.kind, batch.scorerName).completion.poll(batch.submissionData, {
49431
- runId: state.runId,
49432
- batchId: batch.id
49433
- })
49434
- }))
49435
- );
49436
- const changedCases = /* @__PURE__ */ new Map();
49437
- const changedBatches = [];
49438
- for (const { batch, result } of results) {
51356
+ if (!state) throw new Error(`Workflow eval run ${options.runId} is missing`);
51357
+ const submissions = state.submissions.filter((submission) => {
51358
+ if (submission.status === "complete") return false;
51359
+ return processorForStage(definition, submission.kind, submission.scorerName).completion.mode === "poll";
51360
+ });
51361
+ const workers = queue(async (submission) => {
51362
+ const completion = processorForStage(
51363
+ definition,
51364
+ submission.kind,
51365
+ submission.scorerName
51366
+ ).completion;
51367
+ if (completion.mode !== "poll") return;
51368
+ const result = await completion.poll(submission.submissionData, {
51369
+ runId: state.runId,
51370
+ submissionId: submission.id
51371
+ });
49439
51372
  if (result.status === "failed") throw asError(result.error);
49440
- if (result.status !== "complete") continue;
49441
- for (const record of await collectBatch(definition, state, batch)) {
49442
- changedCases.set(record.id, record);
49443
- }
49444
- batch.status = "complete";
49445
- changedBatches.push(batch);
49446
- }
49447
- if (changedBatches.length > 0) {
49448
- await writeCaseRecords(store, key, [...changedCases.values()]);
49449
- await writeBatchRecords(store, key, changedBatches);
51373
+ if (result.status === "complete") {
51374
+ const record = await collectSubmission(definition, state, submission);
51375
+ await writeCaseRecords(store, key, [record]);
51376
+ submission.status = "complete";
51377
+ await writeSubmissionRecords(store, key, [submission]);
51378
+ }
51379
+ }, definition.evaluator.maxConcurrency ?? 10);
51380
+ const results = await Promise.allSettled(
51381
+ submissions.map((submission) => workers.pushAsync(submission))
51382
+ );
51383
+ let status;
51384
+ const errors = results.flatMap(
51385
+ (result) => result.status === "rejected" ? [asError(result.reason)] : []
51386
+ );
51387
+ try {
51388
+ status = await advanceWorkflowEval(
51389
+ definition,
51390
+ await readRunState(definition, store, key),
51391
+ store,
51392
+ key
51393
+ );
51394
+ } catch (error) {
51395
+ errors.push(asError(error));
49450
51396
  }
49451
- const currentState = changedBatches.length > 0 ? await readRunState(definition, store, key) : state;
49452
- return advanceDurableEval(definition, currentState, store, key);
51397
+ if (errors.length === 1) throw errors[0];
51398
+ if (errors.length > 1)
51399
+ throw new AggregateError(errors, "Workflow submission callbacks failed");
51400
+ return status;
49453
51401
  }
49454
- async function openDurableExperiment(definition, state) {
51402
+ async function openWorkflowExperiment(definition, state) {
49455
51403
  const data = [];
49456
51404
  return await _internalInitEvaluatorExperiment(
49457
51405
  definition.projectName,
@@ -49464,45 +51412,49 @@ async function openDurableExperiment(definition, state) {
49464
51412
  }
49465
51413
  );
49466
51414
  }
49467
- async function advanceDurableEval(definition, state, store, key, existingExperiment) {
51415
+ async function advanceWorkflowEval(definition, state, store, key, existingExperiment) {
49468
51416
  if (state.status === "completed") return currentStatus(definition, state);
49469
- const experiment = existingExperiment === void 0 ? await openDurableExperiment(definition, state) : existingExperiment;
51417
+ const experiment = existingExperiment === void 0 ? await openWorkflowExperiment(definition, state) : existingExperiment;
51418
+ const caseIds = state.cases.map(({ id }) => id);
49470
51419
  await runTaskStage(definition, state, store, key, experiment);
49471
51420
  await logCompletedTasks(definition, state, store, key, experiment);
49472
- state = await readRunState(definition, store, key) ?? state;
49473
- if (state.cases.some((record) => !record.taskComplete || !record.taskLogged)) {
49474
- return currentStatus(definition, state);
49475
- }
51421
+ state = await readRunState(definition, store, key, caseIds) ?? state;
49476
51422
  await runScoreStages(definition, state, store, key, experiment);
49477
- state = await readRunState(definition, store, key) ?? state;
51423
+ state = await readRunState(definition, store, key, caseIds) ?? state;
49478
51424
  const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
49479
51425
  ({ name }) => name
49480
51426
  );
49481
51427
  const classifierNames = (definition.evaluator.classifiers ?? []).map(
49482
51428
  classifierName
49483
51429
  );
49484
- if (state.cases.some(
49485
- (record) => scorerNames.some(
49486
- (name) => !Object.hasOwn(record.scores, name) || !Object.hasOwn(record.loggedScores, name)
49487
- ) || classifierNames.some(
49488
- (name) => !Object.hasOwn(record.loggedClassifications, name)
49489
- )
49490
- )) {
51430
+ await Promise.all(
51431
+ state.cases.map(async (record) => {
51432
+ if (record.taskComplete && record.taskLogged && scorerNames.every(
51433
+ (name) => Object.hasOwn(record.scores, name) && Object.hasOwn(record.loggedScores, name)
51434
+ ) && classifierNames.every(
51435
+ (name) => Object.hasOwn(record.loggedClassifications, name)
51436
+ )) {
51437
+ await store.addToSet(`${key}/progress/cases`, record.id);
51438
+ }
51439
+ })
51440
+ );
51441
+ if (await store.getSetSize(`${key}/progress/cases`) !== state.caseCount) {
49491
51442
  return currentStatus(definition, state);
49492
51443
  }
49493
51444
  if (!await claimAction(store, key, "finish")) {
49494
- const latest = await readRunState(definition, store, key);
51445
+ const latest = await readJson(store, key);
49495
51446
  return currentStatus(definition, latest ?? state);
49496
51447
  }
51448
+ state = await readRunState(definition, store, key);
49497
51449
  state.summary = await finishExperiment(definition, state, experiment);
49498
51450
  state.status = "completed";
49499
51451
  await writeRunRecord(store, key, state);
49500
51452
  return currentStatus(definition, state);
49501
51453
  }
49502
- function currentStatus(definition, state) {
51454
+ async function currentStatus(definition, state) {
49503
51455
  if (state.status === "completed") {
49504
51456
  if (!state.summary) {
49505
- throw new Error(`Durable eval run ${state.runId} has no saved summary`);
51457
+ throw new Error(`Workflow eval run ${state.runId} has no saved summary`);
49506
51458
  }
49507
51459
  return {
49508
51460
  status: "completed",
@@ -49511,11 +51463,20 @@ function currentStatus(definition, state) {
49511
51463
  summary: state.summary
49512
51464
  };
49513
51465
  }
51466
+ const key = runKey(definition.projectName, definition.evalName, state.runId);
51467
+ const store = definition.evaluator.store;
49514
51468
  const pending = { poll: 0, webhook: 0 };
49515
- for (const batch of state.batches) {
49516
- if (batch.status === "complete") continue;
49517
- pending[processorForStage(definition, batch.kind, batch.scorerName).completion.mode]++;
49518
- }
51469
+ await Promise.all(
51470
+ ["poll", "webhook"].map(async (mode) => {
51471
+ const completed = await store.getSetSize(
51472
+ `${key}/progress/${mode}/complete`
51473
+ );
51474
+ const submitted = await store.getSetSize(
51475
+ `${key}/progress/${mode}/submitted`
51476
+ );
51477
+ pending[mode] = submitted - completed;
51478
+ })
51479
+ );
49519
51480
  return { status: "waiting", runId: state.runId, pending };
49520
51481
  }
49521
51482
  async function startCaseRoot(definition, state, record, experiment) {
@@ -49576,7 +51537,7 @@ async function logTaskResult(definition, state, record, experiment, task) {
49576
51537
  expected: "expected" in datum ? datum.expected : void 0,
49577
51538
  metadata: {
49578
51539
  ...record.metadata,
49579
- durable_eval: {
51540
+ workflow_eval: {
49580
51541
  run_id: state.runId,
49581
51542
  case_id: record.caseId,
49582
51543
  trial_index: record.trialIndex
@@ -49607,8 +51568,8 @@ async function logCompletedTasks(definition, state, store, key, experiment) {
49607
51568
  }
49608
51569
  }
49609
51570
  async function runTaskStage(definition, state, store, key, experiment) {
49610
- if (isBatchTask(definition.evaluator.task)) {
49611
- await ensureBatches(definition, state, store, key, "task");
51571
+ if (isWorkflowTask(definition.evaluator.task)) {
51572
+ await ensureSubmissions(definition, state, store, key, "task");
49612
51573
  return;
49613
51574
  }
49614
51575
  const task = definition.evaluator.task;
@@ -49634,8 +51595,9 @@ async function runScoreStages(definition, state, store, key, experiment) {
49634
51595
  changed.clear();
49635
51596
  };
49636
51597
  for (const { name, scorer } of scorers) {
49637
- if (isBatchScorer(scorer)) {
51598
+ if (isWorkflowScorer(scorer)) {
49638
51599
  for (const record of state.cases) {
51600
+ if (!record.taskComplete || !record.taskLogged) continue;
49639
51601
  if (Object.hasOwn(record.scores, name) && !Object.hasOwn(record.loggedScores, name)) {
49640
51602
  if (!await claimAction(store, key, "score-log", record.id, name)) {
49641
51603
  continue;
@@ -49651,10 +51613,11 @@ async function runScoreStages(definition, state, store, key, experiment) {
49651
51613
  }
49652
51614
  }
49653
51615
  await persistChangedCases();
49654
- await ensureBatches(definition, state, store, key, "score", name);
51616
+ await ensureSubmissions(definition, state, store, key, "score", name);
49655
51617
  continue;
49656
51618
  }
49657
51619
  for (const record of state.cases) {
51620
+ if (!record.taskComplete || !record.taskLogged) continue;
49658
51621
  if (Object.hasOwn(record.loggedScores, name)) continue;
49659
51622
  if (!await claimAction(store, key, "score", record.id, name)) continue;
49660
51623
  await evaluateAndLogScore(
@@ -49671,6 +51634,7 @@ async function runScoreStages(definition, state, store, key, experiment) {
49671
51634
  for (const [index, classifier] of (definition.evaluator.classifiers ?? []).entries()) {
49672
51635
  const name = classifierName(classifier, index);
49673
51636
  for (const record of state.cases) {
51637
+ if (!record.taskComplete || !record.taskLogged) continue;
49674
51638
  if (Object.hasOwn(record.loggedClassifications, name)) continue;
49675
51639
  if (!await claimAction(store, key, "classification", record.id, name)) {
49676
51640
  continue;
@@ -49693,13 +51657,14 @@ function scorerArgs(record) {
49693
51657
  return {
49694
51658
  ...datum,
49695
51659
  metadata: record.metadata,
51660
+ tags: record.tags,
49696
51661
  output: record.output
49697
51662
  };
49698
51663
  }
49699
51664
  function resumeCaseRoot(definition, record, experiment) {
49700
51665
  if (!experiment) return NOOP_SPAN;
49701
51666
  if (!record.rootSpan) {
49702
- throw new Error(`Durable eval case ${record.caseId} has no root span`);
51667
+ throw new Error(`Workflow eval case ${record.caseId} has no root span`);
49703
51668
  }
49704
51669
  return _internalResumeSpan({
49705
51670
  exported: record.rootSpan,
@@ -49787,117 +51752,110 @@ async function evaluateAndLogClassification(definition, state, record, name, cla
49787
51752
  root.end();
49788
51753
  }
49789
51754
  }
49790
- async function ensureBatches(definition, state, store, key, kind, scorerName2) {
51755
+ async function ensureSubmissions(definition, state, store, key, kind, scorerName2) {
49791
51756
  const processor = processorForStage(definition, kind, scorerName2);
49792
- const plans = plannedBatches(
51757
+ const plans = plannedSubmissions(
49793
51758
  definition,
49794
51759
  state.runId,
49795
51760
  state.cases.map(({ id }) => id)
49796
51761
  );
49797
51762
  const casesById = new Map(state.cases.map((record) => [record.id, record]));
49798
- for (const plan of plans) {
49799
- if (plan.kind !== kind || plan.scorerName !== scorerName2) continue;
49800
- if (state.batches.some(({ id }) => id === plan.id)) continue;
49801
- const records = plan.itemIds.map((id) => casesById.get(id));
49802
- const ready = records.every(
49803
- (record) => kind === "task" ? !record.taskComplete : !Object.hasOwn(record.scores, scorerName2)
49804
- );
49805
- if (!ready) continue;
49806
- const batchId = plan.id;
51763
+ const existingIds = new Set(state.submissions.map(({ id }) => id));
51764
+ const workers = queue(async (plan) => {
51765
+ if (plan.kind !== kind || plan.scorerName !== scorerName2) return;
51766
+ if (existingIds.has(plan.id)) return;
51767
+ const record = casesById.get(plan.itemId);
51768
+ const ready = kind === "task" ? !record.taskComplete : record.taskComplete && record.taskLogged && !Object.hasOwn(record.scores, scorerName2);
51769
+ if (!ready) return;
51770
+ const submissionId = plan.id;
49807
51771
  const claim = await store.getOrSet(
49808
- claimRecordKey(key, "batch", batchId),
49809
- encoder.encode(batchId)
49810
- );
49811
- if (!claim.created) continue;
49812
- const context = { runId: state.runId, batchId };
49813
- const items = records.map(
49814
- (record) => kind === "task" ? taskBatchItem(record, state.parameters) : scorerBatchItem(record)
51772
+ claimRecordKey(key, "submission", submissionId),
51773
+ encoder.encode(submissionId)
49815
51774
  );
51775
+ if (!claim.created) return;
51776
+ const context = { runId: state.runId, submissionId };
51777
+ const item = kind === "task" ? taskSubmissionItem(record, state.parameters) : scorerSubmissionItem(record);
49816
51778
  const submissionData = assertJsonValue(
49817
- await processor.submit(items, context),
49818
- `submission data for batch ${batchId}`
51779
+ await processor.submit(item, context),
51780
+ `submission data for submission ${submissionId}`
49819
51781
  );
49820
51782
  const externalId = processor.completion.mode === "webhook" ? processor.completion.getExternalId(submissionData, context) : void 0;
49821
51783
  if (externalId !== void 0 && !externalId.trim()) {
49822
- throw new Error(`Batch ${batchId} produced an empty externalId`);
51784
+ throw new Error(
51785
+ `Submission ${submissionId} produced an empty externalId`
51786
+ );
49823
51787
  }
49824
- const batch = {
49825
- id: batchId,
51788
+ const submission = {
51789
+ id: submissionId,
49826
51790
  kind,
49827
51791
  scorerName: scorerName2,
49828
- itemIds: records.map((record) => record.id),
51792
+ itemId: record.id,
49829
51793
  submissionData,
49830
51794
  externalId,
49831
- status: "submitted"
49832
- };
49833
- state.batches.push(batch);
49834
- await writeBatchRecords(store, key, [batch]);
49835
- }
51795
+ status: "submitted",
51796
+ completionMode: processor.completion.mode
51797
+ };
51798
+ state.submissions.push(submission);
51799
+ await writeSubmissionRecords(store, key, [submission]);
51800
+ }, definition.evaluator.maxConcurrency ?? 10);
51801
+ const results = await Promise.allSettled(
51802
+ plans.map((plan) => workers.pushAsync(plan))
51803
+ );
51804
+ const errors = results.flatMap(
51805
+ (result) => result.status === "rejected" ? [asError(result.reason)] : []
51806
+ );
51807
+ if (errors.length === 1) throw errors[0];
51808
+ if (errors.length > 1)
51809
+ throw new AggregateError(errors, "Workflow submissions failed");
49836
51810
  }
49837
- async function collectBatch(definition, state, batch) {
49838
- const processor = processorForStage(definition, batch.kind, batch.scorerName);
49839
- const context = { runId: state.runId, batchId: batch.id };
49840
- const results = await processor.collect(batch.submissionData, context);
49841
- if (!Array.isArray(results)) {
49842
- throw new Error(`collect for batch ${batch.id} must return an array`);
51811
+ async function collectSubmission(definition, state, submission) {
51812
+ const processor = processorForStage(
51813
+ definition,
51814
+ submission.kind,
51815
+ submission.scorerName
51816
+ );
51817
+ const context = { runId: state.runId, submissionId: submission.id };
51818
+ const result = await processor.collect(submission.submissionData, context);
51819
+ if (typeof result !== "object" || result === null || Array.isArray(result)) {
51820
+ throw new Error(
51821
+ `collect for submission ${submission.id} must return a result object`
51822
+ );
49843
51823
  }
49844
- const expectedIds = new Set(batch.itemIds);
49845
- const seen = /* @__PURE__ */ new Set();
49846
- const records = [];
49847
- for (const result of results) {
49848
- const id = resultItemId(result);
49849
- if (!expectedIds.has(id)) {
49850
- throw new Error(`Batch ${batch.id} returned unknown item ${id}`);
49851
- }
49852
- if (seen.has(id)) {
49853
- throw new Error(`Batch ${batch.id} returned item ${id} more than once`);
49854
- }
49855
- seen.add(id);
49856
- const record = state.cases.find((candidate) => candidate.id === id);
49857
- records.push(record);
49858
- if (batch.kind === "task") {
49859
- record.output = assertJsonValue(
49860
- result.output,
49861
- `task output for item ${id}`
49862
- );
49863
- if ("metadata" in result && result.metadata !== void 0) {
49864
- record.metadata = assertJsonValue(
49865
- {
49866
- ...record.metadata,
49867
- ...result.metadata
49868
- },
49869
- `metadata for ${id}`
49870
- );
49871
- }
49872
- if ("tags" in result && result.tags !== void 0)
49873
- record.tags = result.tags;
49874
- record.taskComplete = true;
49875
- } else {
49876
- record.scores[batch.scorerName] = assertJsonValue(
49877
- result.score,
49878
- `score output for item ${id}`
51824
+ const record = state.cases.find(
51825
+ (candidate) => candidate.id === submission.itemId
51826
+ );
51827
+ if (submission.kind === "task") {
51828
+ record.output = assertJsonValue(
51829
+ result.output,
51830
+ `task output for item ${record.id}`
51831
+ );
51832
+ if (result.metadata !== void 0) {
51833
+ record.metadata = assertJsonValue(
51834
+ { ...record.metadata, ...result.metadata },
51835
+ `metadata for ${record.id}`
49879
51836
  );
49880
51837
  }
49881
- }
49882
- const missing = batch.itemIds.filter((id) => !seen.has(id));
49883
- if (missing.length > 0) {
49884
- throw new Error(
49885
- `Batch ${batch.id} did not return results for: ${missing.join(", ")}`
51838
+ if (result.tags !== void 0) record.tags = result.tags;
51839
+ record.taskComplete = true;
51840
+ } else {
51841
+ record.scores[submission.scorerName] = assertJsonValue(
51842
+ result.score,
51843
+ `score output for item ${record.id}`
49886
51844
  );
49887
51845
  }
49888
- return records;
51846
+ return record;
49889
51847
  }
49890
51848
  function processorForStage(definition, kind, scorerName2) {
49891
51849
  if (kind === "task") {
49892
- if (!isBatchTask(definition.evaluator.task)) {
49893
- throw new Error("Definition no longer contains the batch task");
51850
+ if (!isWorkflowTask(definition.evaluator.task)) {
51851
+ throw new Error("Definition no longer contains the submission task");
49894
51852
  }
49895
51853
  return definition.evaluator.task.processor;
49896
51854
  }
49897
51855
  const scorer = resolveScorers(definition.evaluator.scores ?? []).find(
49898
51856
  ({ name }) => name === scorerName2
49899
51857
  )?.scorer;
49900
- if (!isBatchScorer(scorer)) {
51858
+ if (!isWorkflowScorer(scorer)) {
49901
51859
  throw new Error(`Definition no longer contains scorer ${scorerName2}`);
49902
51860
  }
49903
51861
  return scorer.processor;
@@ -49919,15 +51877,15 @@ async function materializeCases(definition, data, experiment) {
49919
51877
  const caseId = datum.id ?? datum.upsert_id ?? (evaluator.caseId ? await evaluator.caseId(datum) : void 0);
49920
51878
  if (!caseId) {
49921
51879
  throw new Error(
49922
- "Every durable eval case requires id, upsert_id, or caseId"
51880
+ "Every workflow eval case requires id, upsert_id, or caseId"
49923
51881
  );
49924
51882
  }
49925
51883
  if (seen.has(caseId))
49926
- throw new Error(`Duplicate durable eval case id: ${caseId}`);
51884
+ throw new Error(`Duplicate workflow eval case id: ${caseId}`);
49927
51885
  seen.add(caseId);
49928
51886
  const trialCount = datum.trialCount ?? evaluator.trialCount ?? 1;
49929
51887
  if (!Number.isInteger(trialCount) || trialCount < 1) {
49930
- throw new Error(`Invalid trialCount for durable eval case ${caseId}`);
51888
+ throw new Error(`Invalid trialCount for workflow eval case ${caseId}`);
49931
51889
  }
49932
51890
  for (let trialIndex = 0; trialIndex < trialCount; trialIndex++) {
49933
51891
  records.push({
@@ -49951,7 +51909,7 @@ async function materializeCases(definition, data, experiment) {
49951
51909
  }
49952
51910
  return records;
49953
51911
  }
49954
- function taskBatchItem(record, parameters) {
51912
+ function taskSubmissionItem(record, parameters) {
49955
51913
  const datum = record.datum;
49956
51914
  return {
49957
51915
  id: record.id,
@@ -49963,7 +51921,7 @@ function taskBatchItem(record, parameters) {
49963
51921
  trialIndex: record.trialIndex
49964
51922
  };
49965
51923
  }
49966
- function scorerBatchItem(record) {
51924
+ function scorerSubmissionItem(record) {
49967
51925
  const datum = record.datum;
49968
51926
  return {
49969
51927
  id: record.id,
@@ -50034,12 +51992,12 @@ async function finishExperiment(definition, state, experiment) {
50034
51992
  }
50035
51993
  function resolveScorers(scorers) {
50036
51994
  return scorers.map((scorer, index) => ({
50037
- name: isBatchScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
51995
+ name: isWorkflowScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
50038
51996
  scorer
50039
51997
  }));
50040
51998
  }
50041
51999
  function runKey(projectName, evalName, runId) {
50042
- return `durable-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
52000
+ return `workflow-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
50043
52001
  }
50044
52002
  function encodedKeyPart(value) {
50045
52003
  return uint8ArrayToBase64(encoder.encode(value)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
@@ -50048,8 +52006,8 @@ function caseRecordKey(key, caseId, kind, ...names) {
50048
52006
  const suffix = names.map(encodedKeyPart).join("/");
50049
52007
  return `${key}/cases/${encodedKeyPart(caseId)}/${kind}${suffix ? `/${suffix}` : ""}`;
50050
52008
  }
50051
- function batchRecordKey(key, batchId) {
50052
- return `${key}/batches/${encodedKeyPart(batchId)}`;
52009
+ function submissionRecordKey(key, submissionId) {
52010
+ return `${key}/submissions/${encodedKeyPart(submissionId)}`;
50053
52011
  }
50054
52012
  function claimRecordKey(key, kind, ...parts) {
50055
52013
  const identity = stableStringify([kind, parts]);
@@ -50061,33 +52019,24 @@ async function claimAction(store, key, kind, ...parts) {
50061
52019
  encoder.encode("claimed")
50062
52020
  )).created;
50063
52021
  }
50064
- function plannedBatches(definition, runId, caseIds) {
52022
+ function plannedSubmissions(definition, runId, caseIds) {
50065
52023
  const stages = [];
50066
- if (isBatchTask(definition.evaluator.task)) stages.push({ kind: "task" });
52024
+ if (isWorkflowTask(definition.evaluator.task)) stages.push({ kind: "task" });
50067
52025
  for (const { name, scorer } of resolveScorers(
50068
52026
  definition.evaluator.scores ?? []
50069
52027
  )) {
50070
- if (isBatchScorer(scorer)) {
52028
+ if (isWorkflowScorer(scorer)) {
50071
52029
  stages.push({ kind: "score", scorerName: name });
50072
52030
  }
50073
52031
  }
50074
52032
  const plans = [];
50075
52033
  for (const { kind, scorerName: scorerName2 } of stages) {
50076
- const batchSize = processorForStage(definition, kind, scorerName2).batchSize ?? DEFAULT_BATCH_SIZE;
50077
- if (!Number.isInteger(batchSize) || batchSize < 1) {
50078
- throw new Error(
50079
- `Invalid batchSize for ${scorerName2 ?? "task"}: ${batchSize}`
50080
- );
50081
- }
50082
- for (let offset = 0; offset < caseIds.length; offset += batchSize) {
50083
- const itemIds = caseIds.slice(offset, offset + batchSize);
52034
+ for (const itemId of caseIds) {
50084
52035
  plans.push({
50085
- id: deterministicId(
50086
- stableStringify([runId, kind, scorerName2, itemIds])
50087
- ),
52036
+ id: deterministicId(stableStringify([runId, kind, scorerName2, itemId])),
50088
52037
  kind,
50089
52038
  scorerName: scorerName2,
50090
- itemIds
52039
+ itemId
50091
52040
  });
50092
52041
  }
50093
52042
  }
@@ -50147,7 +52096,7 @@ async function readCaseRecord(definition, store, key, id) {
50147
52096
  }))
50148
52097
  )
50149
52098
  ]);
50150
- if (!base) throw new Error(`Durable eval case ${id} is missing`);
52099
+ if (!base) throw new Error(`Workflow eval case ${id} is missing`);
50151
52100
  const scores = /* @__PURE__ */ Object.create(null);
50152
52101
  for (const { name, value } of scoreValues) {
50153
52102
  if (value !== void 0) scores[name] = value;
@@ -50178,32 +52127,34 @@ async function readCaseRecord(definition, store, key, id) {
50178
52127
  loggedClassifications
50179
52128
  };
50180
52129
  }
50181
- async function readRunState(definition, store, key) {
52130
+ async function readRunState(definition, store, key, caseIds) {
50182
52131
  const record = await readJson(store, key);
50183
52132
  if (!record) return void 0;
50184
- const plans = plannedBatches(definition, record.runId, record.caseIds);
50185
- const [cases, batchRecords] = await Promise.all([
52133
+ const selectedIds = caseIds ?? (record.caseCount === 0 ? [] : await readJson(store, `${key}/case-ids`));
52134
+ if (!selectedIds)
52135
+ throw new Error(`Workflow eval run ${record.runId} has no case index`);
52136
+ const plans = plannedSubmissions(definition, record.runId, selectedIds);
52137
+ const [cases, submissionRecords] = await Promise.all([
50186
52138
  Promise.all(
50187
- record.caseIds.map((id) => readCaseRecord(definition, store, key, id))
52139
+ selectedIds.map((id) => readCaseRecord(definition, store, key, id))
50188
52140
  ),
50189
52141
  Promise.all(
50190
52142
  plans.map(async ({ id }) => {
50191
- return readJson(store, batchRecordKey(key, id));
52143
+ return readJson(
52144
+ store,
52145
+ submissionRecordKey(key, id)
52146
+ );
50192
52147
  })
50193
52148
  )
50194
52149
  ]);
50195
- const batches = batchRecords.filter(
52150
+ const submissions = submissionRecords.filter(
50196
52151
  (value) => value !== void 0
50197
52152
  );
50198
- const { caseIds: _caseIds, ...state } = record;
50199
- return { ...state, cases, batches };
52153
+ return { ...record, cases, submissions };
50200
52154
  }
50201
52155
  async function writeRunRecord(store, key, state) {
50202
- const { cases, batches: _batches, ...record } = state;
50203
- await writeJson(store, key, {
50204
- ...record,
50205
- caseIds: cases.map(({ id }) => id)
50206
- });
52156
+ const { cases: _cases, submissions: _submissions, ...record } = state;
52157
+ await writeJson(store, key, record);
50207
52158
  }
50208
52159
  async function writeCaseBaseRecords(store, key, records) {
50209
52160
  await Promise.all(
@@ -50275,11 +52226,25 @@ async function writeCaseRecords(store, key, records) {
50275
52226
  }
50276
52227
  await Promise.all(writes);
50277
52228
  }
50278
- async function writeBatchRecords(store, key, records) {
52229
+ async function writeSubmissionRecords(store, key, records) {
50279
52230
  await Promise.all(
50280
- records.map(
50281
- (record) => writeJson(store, batchRecordKey(key, record.id), record)
50282
- )
52231
+ records.map(async (record) => {
52232
+ if (record.externalId !== void 0) {
52233
+ const locator = await store.getOrSet(
52234
+ `${key}/external/${encodedKeyPart(record.externalId)}`,
52235
+ encoder.encode(JSON.stringify(record.id))
52236
+ );
52237
+ if (JSON.parse(decoder.decode(locator.value)) !== record.id) {
52238
+ throw new Error(`Duplicate externalId: ${record.externalId}`);
52239
+ }
52240
+ }
52241
+ const progressKey = `${key}/progress/${record.completionMode}`;
52242
+ await store.addToSet(`${progressKey}/submitted`, record.id);
52243
+ if (record.status === "complete") {
52244
+ await store.addToSet(`${progressKey}/complete`, record.id);
52245
+ }
52246
+ await writeJson(store, submissionRecordKey(key, record.id), record);
52247
+ })
50283
52248
  );
50284
52249
  }
50285
52250
  function deterministicId(value) {
@@ -50324,17 +52289,11 @@ function assertJsonValue(value, label) {
50324
52289
  throw new Error(`${label} must be JSON serializable`, { cause: error });
50325
52290
  }
50326
52291
  }
50327
- function resultItemId(value) {
50328
- if (typeof value !== "object" || value === null || !("id" in value) || typeof value.id !== "string") {
50329
- throw new Error("Batch results must contain a string id");
50330
- }
50331
- return value.id;
50332
- }
50333
- function isBatchTask(value) {
50334
- return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_TASK_KIND;
52292
+ function isWorkflowTask(value) {
52293
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === WORKFLOW_TASK_KIND;
50335
52294
  }
50336
- function isBatchScorer(value) {
50337
- return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_SCORER_KIND;
52295
+ function isWorkflowScorer(value) {
52296
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === WORKFLOW_SCORER_KIND;
50338
52297
  }
50339
52298
  function asError(error) {
50340
52299
  return error instanceof Error ? error : new Error(String(error));
@@ -51262,13 +53221,13 @@ var evaluatorDefinitionsSchema = z13.record(
51262
53221
  );
51263
53222
 
51264
53223
  // src/wrappers/elevenlabs.ts
51265
- var clients = /* @__PURE__ */ new WeakMap();
53224
+ var clients2 = /* @__PURE__ */ new WeakMap();
51266
53225
  function wrapElevenLabs(client) {
51267
53226
  if (!isObject(client) || !isObject(client.textToSpeech) || typeof client.textToSpeech.convert !== "function") {
51268
53227
  debugLogger.warn("Unsupported ElevenLabs client. Not wrapping.");
51269
53228
  return client;
51270
53229
  }
51271
- const cached = clients.get(client);
53230
+ const cached = clients2.get(client);
51272
53231
  if (cached) return cached;
51273
53232
  const sdk = client;
51274
53233
  const speech = new Proxy(sdk.textToSpeech, {
@@ -51315,8 +53274,8 @@ function wrapElevenLabs(client) {
51315
53274
  return Reflect.get(target, prop, receiver);
51316
53275
  }
51317
53276
  });
51318
- clients.set(client, proxy);
51319
- clients.set(proxy, proxy);
53277
+ clients2.set(client, proxy);
53278
+ clients2.set(proxy, proxy);
51320
53279
  return proxy;
51321
53280
  }
51322
53281
 
@@ -51331,8 +53290,6 @@ export {
51331
53290
  BRAINTRUST_PARENT_KEY,
51332
53291
  BaseAttachment,
51333
53292
  BaseExperiment,
51334
- BatchScorer,
51335
- BatchTask,
51336
53293
  BraintrustLangChainCallbackHandler,
51337
53294
  BraintrustMiddleware,
51338
53295
  BraintrustObservabilityExporter,
@@ -51346,8 +53303,6 @@ export {
51346
53303
  DEFAULT_MAX_REQUEST_SIZE,
51347
53304
  Dataset2 as Dataset,
51348
53305
  DatasetPipeline,
51349
- DurableEvalMemoryStore,
51350
- DurableEvalRedisStore,
51351
53306
  ERR_PERMALINK,
51352
53307
  Eval,
51353
53308
  EvalResultWithSummary,
@@ -51382,6 +53337,10 @@ export {
51382
53337
  TestBackgroundLogger,
51383
53338
  ToolBuilder,
51384
53339
  UUIDGenerator,
53340
+ WorkflowEvalMemoryStore,
53341
+ WorkflowEvalRedisStore,
53342
+ WorkflowScorer,
53343
+ WorkflowTask,
51385
53344
  X_CACHED_HEADER,
51386
53345
  _exportsForTestingOnly,
51387
53346
  _internalGetGlobalState,
@@ -51407,12 +53366,13 @@ export {
51407
53366
  deepCopyEvent,
51408
53367
  exports_exports as default,
51409
53368
  defaultErrorScoreHandler,
51410
- defineDurableEval,
53369
+ defineWorkflowEval,
51411
53370
  deserializePlainStringAsJSON,
51412
53371
  devNullWritableStream,
51413
53372
  evaluatorDefinitionSchema,
51414
53373
  evaluatorDefinitionsSchema,
51415
53374
  extractTraceContextFromHeaders,
53375
+ failOpenAIAgentsTrace,
51416
53376
  flush,
51417
53377
  getContextManager,
51418
53378
  getIdGenerator,
@@ -51459,12 +53419,14 @@ export {
51459
53419
  setFetch,
51460
53420
  setMaskingFunction,
51461
53421
  spanComponentsToObjectId,
53422
+ startOpenAIAgentsTrace,
51462
53423
  startSpan,
51463
53424
  summarize,
51464
53425
  templateRegistry,
51465
53426
  ToolFunctionDefinition as toolFunctionDefinitionSchema,
51466
53427
  traceable,
51467
53428
  traced,
53429
+ updateOpenAIAgentsTrace,
51468
53430
  updateSpan,
51469
53431
  uploadLogs3OverflowPayload,
51470
53432
  utf8ByteLength2 as utf8ByteLength,
@@ -51493,6 +53455,7 @@ export {
51493
53455
  wrapGroq,
51494
53456
  wrapHuggingFace,
51495
53457
  wrapHuggingFaceTransformers,
53458
+ wrapLangGraphSDK,
51496
53459
  wrapLangSmithClient,
51497
53460
  wrapLangSmithRunTrees,
51498
53461
  wrapLangSmithTraceable,