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
@@ -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) {
@@ -13529,6 +13568,18 @@ function defineChannels(pkg, channels, options) {
13529
13568
  var openAIChannels = defineChannels(
13530
13569
  "openai",
13531
13570
  {
13571
+ agentsTraceStart: channel({
13572
+ channelName: "agents.trace.start",
13573
+ kind: "async"
13574
+ }),
13575
+ agentsTraceCapture: channel({
13576
+ channelName: "agents.trace.capture",
13577
+ kind: "async"
13578
+ }),
13579
+ agentsTraceFail: channel({
13580
+ channelName: "agents.trace.fail",
13581
+ kind: "async"
13582
+ }),
13532
13583
  filesCreateTraced: channel({
13533
13584
  channelName: "files.create-traced",
13534
13585
  kind: "async"
@@ -13897,6 +13948,23 @@ function getCachedMetricFromHeaders(headers) {
13897
13948
  return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
13898
13949
  }
13899
13950
 
13951
+ // src/instrumentation/plugins/openai-manual-instrumentation-utils.ts
13952
+ async function deterministicDigest(namespace, ...parts) {
13953
+ const encoded = new TextEncoder().encode(
13954
+ [namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
13955
+ );
13956
+ return new Uint8Array(
13957
+ await globalThis.crypto.subtle.digest("SHA-256", encoded)
13958
+ );
13959
+ }
13960
+ function digestHex(bytes, length) {
13961
+ return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
13962
+ }
13963
+ function digestUuid(bytes) {
13964
+ const hex = digestHex(bytes, 16);
13965
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13966
+ }
13967
+
13900
13968
  // src/instrumentation/plugins/openai-batch-instrumentation.ts
13901
13969
  var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
13902
13970
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
@@ -13937,21 +14005,6 @@ async function exportParent(parent) {
13937
14005
  }
13938
14006
  return void 0;
13939
14007
  }
13940
- async function deterministicDigest(namespace, ...parts) {
13941
- const encoded = new TextEncoder().encode(
13942
- [namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
13943
- );
13944
- return new Uint8Array(
13945
- await globalThis.crypto.subtle.digest("SHA-256", encoded)
13946
- );
13947
- }
13948
- function digestHex(bytes, length) {
13949
- return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
13950
- }
13951
- function digestUuid(bytes) {
13952
- const hex = digestHex(bytes, 16);
13953
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13954
- }
13955
14008
  async function batchSpanIds(inputFileId) {
13956
14009
  const [row, span, root] = await Promise.all([
13957
14010
  deterministicDigest("openai:batch:row", inputFileId),
@@ -14442,6 +14495,628 @@ var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resol
14442
14495
  return result;
14443
14496
  });
14444
14497
 
14498
+ // src/instrumentation/plugins/openai-agents-api-instrumentation.ts
14499
+ var TERMINAL_TURN_EVENTS = /* @__PURE__ */ new Set([
14500
+ "agent.session.turn.completed",
14501
+ "agent.session.turn.failed",
14502
+ "agent.session.turn.cancelled"
14503
+ ]);
14504
+ var TURN_LIFECYCLE_EVENTS = /* @__PURE__ */ new Set([
14505
+ "agent.session.turn.created",
14506
+ "agent.session.turn.in_progress",
14507
+ ...TERMINAL_TURN_EVENTS
14508
+ ]);
14509
+ var SESSION_EVENTS = /* @__PURE__ */ new Set([
14510
+ "agent.session.created",
14511
+ "agent.session.failed",
14512
+ "agent.session.idle",
14513
+ "agent.session.in_progress",
14514
+ "agent.session.requires_action"
14515
+ ]);
14516
+ var SUBAGENT_EVENTS = /* @__PURE__ */ new Set([
14517
+ "agent.session.subagent.active",
14518
+ "agent.session.subagent.closed",
14519
+ "agent.session.subagent.created"
14520
+ ]);
14521
+ function read2(value, key) {
14522
+ if (!isObject(value)) {
14523
+ return void 0;
14524
+ }
14525
+ try {
14526
+ return Reflect.get(value, key);
14527
+ } catch {
14528
+ return void 0;
14529
+ }
14530
+ }
14531
+ function stringValue(value) {
14532
+ return typeof value === "string" && value.length > 0 ? value : void 0;
14533
+ }
14534
+ function recordValue(record, key) {
14535
+ return Object.hasOwn(record, key) ? record[key] : void 0;
14536
+ }
14537
+ function setRecordValue(record, key, value) {
14538
+ Object.defineProperty(record, key, {
14539
+ configurable: true,
14540
+ enumerable: true,
14541
+ value,
14542
+ writable: true
14543
+ });
14544
+ }
14545
+ function loggedError(value, fallback2) {
14546
+ if (value instanceof Error) {
14547
+ return value;
14548
+ }
14549
+ const message = stringValue(read2(value, "message"));
14550
+ return new Error(message ?? (typeof value === "string" ? value : fallback2));
14551
+ }
14552
+ function logInstrumentationError(context, error) {
14553
+ debugLogger.debug(`OpenAI Agents API instrumentation ${context}:`, error);
14554
+ }
14555
+ async function childSpanIds2(rootKey, kind, providerId) {
14556
+ const [row, span] = await Promise.all([
14557
+ deterministicDigest("openai:agents:row", rootKey, kind, providerId),
14558
+ deterministicDigest("openai:agents:span", rootKey, kind, providerId)
14559
+ ]);
14560
+ return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
14561
+ }
14562
+ function traceMetadata(args) {
14563
+ const metadata = {};
14564
+ const suppliedMetadata = read2(args, "metadata");
14565
+ if (isObject(suppliedMetadata)) {
14566
+ try {
14567
+ for (const key of Object.keys(suppliedMetadata)) {
14568
+ metadata[key] = read2(suppliedMetadata, key);
14569
+ }
14570
+ } catch (error) {
14571
+ logInstrumentationError("could not read supplied metadata", error);
14572
+ }
14573
+ }
14574
+ const agent = read2(args, "agent");
14575
+ const agentId = stringValue(read2(agent, "id")) ?? stringValue(read2(args, "agent_id"));
14576
+ const agentName = stringValue(read2(agent, "name"));
14577
+ const model = stringValue(read2(agent, "model"));
14578
+ return {
14579
+ ...metadata,
14580
+ api: "agents",
14581
+ ...agentId ? { agent_id: agentId } : {},
14582
+ ...agentName ? { agent_name: agentName } : {},
14583
+ ...model ? { model } : {},
14584
+ provider: "openai"
14585
+ };
14586
+ }
14587
+ function copyState(state) {
14588
+ return {
14589
+ ...state,
14590
+ callItems: { ...state.callItems },
14591
+ eventIds: [...state.eventIds],
14592
+ openTools: { ...state.openTools },
14593
+ subagents: { ...state.subagents },
14594
+ turnSubagents: { ...state.turnSubagents }
14595
+ };
14596
+ }
14597
+ function startRootSpan(state) {
14598
+ const root = SpanComponentsV4.fromStr(state.root);
14599
+ const parent = SpanComponentsV4.fromStr(state.rootParent);
14600
+ const rowId = stringValue(root.data.row_id);
14601
+ const rootSpanId = stringValue(root.data.root_span_id);
14602
+ const spanId = stringValue(root.data.span_id);
14603
+ if (!rowId || !rootSpanId || !spanId) {
14604
+ throw new Error("OpenAI Agents trace root is invalid");
14605
+ }
14606
+ const hasParentSpan = Boolean(
14607
+ parent.data.row_id && parent.data.span_id && parent.data.root_span_id
14608
+ );
14609
+ return withCurrent(
14610
+ NOOP_SPAN,
14611
+ () => _internalStartSpanWithInitialMergeAndParentSpanIds(
14612
+ withSpanInstrumentationName(
14613
+ {
14614
+ name: "openai.agents.turn",
14615
+ type: "task" /* TASK */,
14616
+ parent: state.rootParent,
14617
+ ...!hasParentSpan ? {
14618
+ parentSpanIds: {
14619
+ parentSpanIds: [],
14620
+ rootSpanId
14621
+ }
14622
+ } : {},
14623
+ spanId,
14624
+ startTime: state.startTime,
14625
+ event: { id: rowId }
14626
+ },
14627
+ INSTRUMENTATION_NAMES.OPENAI
14628
+ )
14629
+ )
14630
+ );
14631
+ }
14632
+ async function startSubagentSpan(state, subagentId, input, metadata, visiting = /* @__PURE__ */ new Set()) {
14633
+ const subagent = recordValue(state.subagents, subagentId);
14634
+ let parent = state.root;
14635
+ if (subagent?.parentAgentId && subagent.parentAgentId !== subagentId && recordValue(state.subagents, subagent.parentAgentId) && !visiting.has(subagent.parentAgentId)) {
14636
+ visiting.add(subagentId);
14637
+ parent = await (await startSubagentSpan(
14638
+ state,
14639
+ subagent.parentAgentId,
14640
+ void 0,
14641
+ void 0,
14642
+ visiting
14643
+ )).export();
14644
+ }
14645
+ const ids = await childSpanIds2(state.rootKey, "subagent", subagentId);
14646
+ return withCurrent(
14647
+ NOOP_SPAN,
14648
+ () => _internalStartSpanWithInitialMerge(
14649
+ withSpanInstrumentationName(
14650
+ {
14651
+ name: "openai.agents.subagent",
14652
+ type: "task" /* TASK */,
14653
+ parent,
14654
+ spanId: ids.spanId,
14655
+ startTime: subagent?.openedAt,
14656
+ event: {
14657
+ id: ids.rowId,
14658
+ ...input !== void 0 ? { input } : {},
14659
+ metadata: {
14660
+ ...metadata,
14661
+ agent_id: subagentId,
14662
+ ...subagent?.parentAgentId ? { parent_agent_id: subagent.parentAgentId } : {},
14663
+ provider: "openai"
14664
+ }
14665
+ }
14666
+ },
14667
+ INSTRUMENTATION_NAMES.OPENAI
14668
+ )
14669
+ )
14670
+ );
14671
+ }
14672
+ async function parentForTurn(state, turnId) {
14673
+ const subagentId = turnId ? recordValue(state.turnSubagents, turnId) : void 0;
14674
+ if (!subagentId) {
14675
+ return state.root;
14676
+ }
14677
+ return await (await startSubagentSpan(state, subagentId)).export();
14678
+ }
14679
+ async function startToolSpan(state, tool, input) {
14680
+ const ids = await childSpanIds2(state.rootKey, "tool", tool.itemId);
14681
+ return withCurrent(
14682
+ NOOP_SPAN,
14683
+ async () => _internalStartSpanWithInitialMerge(
14684
+ withSpanInstrumentationName(
14685
+ {
14686
+ name: tool.name,
14687
+ type: "tool" /* TOOL */,
14688
+ parent: await parentForTurn(state, tool.turnId),
14689
+ spanId: ids.spanId,
14690
+ startTime: tool.startTime,
14691
+ event: {
14692
+ id: ids.rowId,
14693
+ ...input !== void 0 ? { input } : {},
14694
+ metadata: {
14695
+ item_id: tool.itemId,
14696
+ provider: "openai",
14697
+ tool_type: tool.toolType,
14698
+ ...tool.turnId ? { turn_id: tool.turnId } : {}
14699
+ }
14700
+ }
14701
+ },
14702
+ INSTRUMENTATION_NAMES.OPENAI
14703
+ )
14704
+ )
14705
+ );
14706
+ }
14707
+ function toolFromItem(item, observedAt) {
14708
+ const itemId = stringValue(read2(item, "id"));
14709
+ const toolType = stringValue(read2(item, "type"));
14710
+ if (!itemId || !toolType) {
14711
+ return void 0;
14712
+ }
14713
+ const turnId = stringValue(read2(item, "turn_id"));
14714
+ switch (toolType) {
14715
+ case "function_call":
14716
+ return {
14717
+ input: read2(item, "arguments"),
14718
+ tool: {
14719
+ itemId,
14720
+ name: stringValue(read2(item, "name")) ?? "Function call",
14721
+ startTime: observedAt,
14722
+ toolType,
14723
+ ...turnId ? { turnId } : {}
14724
+ }
14725
+ };
14726
+ case "mcp_call": {
14727
+ const name = stringValue(read2(item, "name")) ?? "MCP call";
14728
+ const server = stringValue(read2(item, "server_label"));
14729
+ return {
14730
+ input: read2(item, "arguments"),
14731
+ tool: {
14732
+ itemId,
14733
+ name: server ? `${server}.${name}` : name,
14734
+ startTime: observedAt,
14735
+ toolType,
14736
+ ...turnId ? { turnId } : {}
14737
+ }
14738
+ };
14739
+ }
14740
+ case "web_search_call":
14741
+ return {
14742
+ input: read2(item, "action"),
14743
+ tool: {
14744
+ itemId,
14745
+ name: "Web search",
14746
+ startTime: observedAt,
14747
+ toolType,
14748
+ ...turnId ? { turnId } : {}
14749
+ }
14750
+ };
14751
+ case "command_execution":
14752
+ return {
14753
+ input: {
14754
+ command: read2(item, "command"),
14755
+ cwd: read2(item, "cwd")
14756
+ },
14757
+ tool: {
14758
+ itemId,
14759
+ name: "Command execution",
14760
+ startTime: observedAt,
14761
+ toolType,
14762
+ ...turnId ? { turnId } : {}
14763
+ }
14764
+ };
14765
+ default:
14766
+ return void 0;
14767
+ }
14768
+ }
14769
+ function textFromContent(content) {
14770
+ if (!Array.isArray(content)) {
14771
+ return void 0;
14772
+ }
14773
+ const text = [];
14774
+ for (const part of content) {
14775
+ const partText = read2(part, "text");
14776
+ if (read2(part, "type") === "output_text" && typeof partText === "string") {
14777
+ text.push(partText);
14778
+ }
14779
+ }
14780
+ return text.length > 0 ? text.join("") : void 0;
14781
+ }
14782
+ function toolOutput(item, toolType) {
14783
+ switch (toolType) {
14784
+ case "function_call":
14785
+ return read2(item, "output");
14786
+ case "mcp_call":
14787
+ return read2(item, "output");
14788
+ case "web_search_call":
14789
+ return read2(item, "action");
14790
+ case "command_execution":
14791
+ return read2(item, "output");
14792
+ default:
14793
+ return void 0;
14794
+ }
14795
+ }
14796
+ function toolFailed(item, toolType) {
14797
+ const status = read2(item, "status");
14798
+ const explicitError = read2(item, "error");
14799
+ if (explicitError !== void 0 && explicitError !== null) {
14800
+ return loggedError(explicitError, `OpenAI ${toolType} failed`);
14801
+ }
14802
+ if (status === "failed" || status === "incomplete") {
14803
+ return new Error(`OpenAI ${toolType} ${status}`);
14804
+ }
14805
+ if (toolType === "command_execution" && typeof read2(item, "exit_code") === "number" && read2(item, "exit_code") !== 0) {
14806
+ return new Error(
14807
+ `OpenAI command exited with code ${read2(item, "exit_code")}`
14808
+ );
14809
+ }
14810
+ return void 0;
14811
+ }
14812
+ async function completeTool(state, tool, item, endTime) {
14813
+ const span = await startToolSpan(state, tool);
14814
+ const output = toolOutput(item, tool.toolType);
14815
+ const error = toolFailed(item, tool.toolType);
14816
+ span.log({
14817
+ ...output !== void 0 ? { output } : {},
14818
+ ...error ? { error } : {},
14819
+ metadata: {
14820
+ status: read2(item, "status"),
14821
+ ...tool.toolType === "command_execution" ? { exit_code: read2(item, "exit_code") } : {}
14822
+ }
14823
+ });
14824
+ span.end({ endTime });
14825
+ Reflect.deleteProperty(state.openTools, tool.itemId);
14826
+ }
14827
+ async function captureMessage(state, item) {
14828
+ if (read2(item, "type") !== "message" || read2(item, "role") !== "assistant" || read2(item, "phase") !== "final_answer") {
14829
+ return;
14830
+ }
14831
+ const output = textFromContent(read2(item, "content"));
14832
+ if (output === void 0) {
14833
+ return;
14834
+ }
14835
+ const turnId = stringValue(read2(item, "turn_id"));
14836
+ const subagentId = turnId ? recordValue(state.turnSubagents, turnId) : void 0;
14837
+ if (subagentId) {
14838
+ (await startSubagentSpan(state, subagentId)).log({ output });
14839
+ } else {
14840
+ startRootSpan(state).log({ output });
14841
+ }
14842
+ }
14843
+ async function captureItem(state, item, isDone, observedAt) {
14844
+ await captureMessage(state, item);
14845
+ const itemType = stringValue(read2(item, "type"));
14846
+ if (itemType === "function_call_output") {
14847
+ const callId = stringValue(read2(item, "call_id"));
14848
+ const itemId = callId ? recordValue(state.callItems, callId) : void 0;
14849
+ const tool2 = itemId ? recordValue(state.openTools, itemId) : void 0;
14850
+ if (tool2) {
14851
+ await completeTool(state, tool2, item, observedAt);
14852
+ }
14853
+ return;
14854
+ }
14855
+ const descriptor = toolFromItem(item, observedAt);
14856
+ if (!descriptor) {
14857
+ return;
14858
+ }
14859
+ const existing = recordValue(state.openTools, descriptor.tool.itemId);
14860
+ const tool = existing ?? descriptor.tool;
14861
+ setRecordValue(state.openTools, tool.itemId, tool);
14862
+ if (itemType === "function_call") {
14863
+ const callId = stringValue(read2(item, "call_id"));
14864
+ if (callId) {
14865
+ setRecordValue(state.callItems, callId, tool.itemId);
14866
+ }
14867
+ }
14868
+ await startToolSpan(state, tool, descriptor.input);
14869
+ const status = read2(item, "status");
14870
+ const terminalFunctionCall = itemType === "function_call" && (status === "failed" || status === "incomplete");
14871
+ if (itemType !== "function_call" && (isDone || status !== "in_progress") || terminalFunctionCall) {
14872
+ await completeTool(state, tool, item, observedAt);
14873
+ }
14874
+ }
14875
+ function updateSessionMetadata(state, session) {
14876
+ const sessionId = stringValue(read2(session, "id"));
14877
+ const agent = read2(session, "agent");
14878
+ startRootSpan(state).log({
14879
+ metadata: {
14880
+ ...sessionId ? { session_id: sessionId } : {},
14881
+ ...stringValue(read2(agent, "id")) ? { agent_id: read2(agent, "id") } : {},
14882
+ ...stringValue(read2(agent, "name")) ? { agent_name: read2(agent, "name") } : {},
14883
+ ...stringValue(read2(agent, "model")) ? { model: read2(agent, "model") } : {}
14884
+ }
14885
+ });
14886
+ }
14887
+ async function captureSubagent(state, eventType, subagent, observedAt) {
14888
+ const subagentId = stringValue(read2(subagent, "id"));
14889
+ if (!subagentId) {
14890
+ return;
14891
+ }
14892
+ const existing = recordValue(state.subagents, subagentId);
14893
+ const observedOpenedAt = read2(subagent, "opened_at");
14894
+ const openedAt = typeof observedOpenedAt === "number" && Number.isFinite(observedOpenedAt) && observedOpenedAt >= 0 ? observedOpenedAt : existing?.openedAt ?? observedAt;
14895
+ const observedClosedAt = read2(subagent, "closed_at");
14896
+ const closedAt = typeof observedClosedAt === "number" && Number.isFinite(observedClosedAt) && observedClosedAt >= 0 ? observedClosedAt : existing?.closedAt;
14897
+ const parentAgentId = stringValue(read2(subagent, "parent_agent_id")) ?? existing?.parentAgentId;
14898
+ setRecordValue(state.subagents, subagentId, {
14899
+ ...closedAt !== void 0 ? { closedAt } : {},
14900
+ openedAt,
14901
+ ...parentAgentId ? { parentAgentId } : {}
14902
+ });
14903
+ const span = await startSubagentSpan(
14904
+ state,
14905
+ subagentId,
14906
+ read2(subagent, "instructions"),
14907
+ {
14908
+ ...stringValue(read2(subagent, "name")) ? { agent_name: read2(subagent, "name") } : {},
14909
+ status: read2(subagent, "status")
14910
+ }
14911
+ );
14912
+ if (eventType === "agent.session.subagent.closed") {
14913
+ span.end({ endTime: closedAt ?? observedAt });
14914
+ }
14915
+ }
14916
+ async function closeTrace(state, endTime, error, usage) {
14917
+ if (state.ended) {
14918
+ return;
14919
+ }
14920
+ for (const tool of Object.values(state.openTools)) {
14921
+ const span = await startToolSpan(state, tool);
14922
+ span.log({
14923
+ error: error ?? new Error("OpenAI Agents turn ended before tool completion")
14924
+ });
14925
+ span.end({ endTime });
14926
+ }
14927
+ state.openTools = {};
14928
+ for (const subagentId of Object.keys(state.subagents)) {
14929
+ const subagent = state.subagents[subagentId];
14930
+ const span = await startSubagentSpan(state, subagentId);
14931
+ span.end({ endTime: subagent.closedAt ?? endTime });
14932
+ }
14933
+ const root = startRootSpan(state);
14934
+ root.log({
14935
+ ...error ? { error } : {},
14936
+ metrics: parseMetricsFromUsage(usage)
14937
+ });
14938
+ root.end({ endTime });
14939
+ state.ended = true;
14940
+ }
14941
+ async function captureTurnLifecycle(state, event, eventType, observedAt) {
14942
+ const turn = read2(event, "turn");
14943
+ const turnId = stringValue(read2(event, "turn_id")) ?? stringValue(read2(turn, "id"));
14944
+ const subagentId = stringValue(read2(turn, "subagent_id"));
14945
+ if (turnId && subagentId) {
14946
+ setRecordValue(state.turnSubagents, turnId, subagentId);
14947
+ if (!recordValue(state.subagents, subagentId)) {
14948
+ const createdAt = read2(turn, "created_at");
14949
+ setRecordValue(state.subagents, subagentId, {
14950
+ openedAt: typeof createdAt === "number" && Number.isFinite(createdAt) && createdAt >= 0 ? createdAt : observedAt
14951
+ });
14952
+ }
14953
+ await startSubagentSpan(state, subagentId);
14954
+ }
14955
+ const sessionId = stringValue(read2(event, "session_id"));
14956
+ if (sessionId) {
14957
+ startRootSpan(state).log({ metadata: { session_id: sessionId } });
14958
+ }
14959
+ if (!TERMINAL_TURN_EVENTS.has(eventType) || subagentId) {
14960
+ if (subagentId && eventType === "agent.session.turn.failed") {
14961
+ (await startSubagentSpan(state, subagentId)).log({
14962
+ error: loggedError(read2(turn, "error"), "OpenAI subagent turn failed")
14963
+ });
14964
+ }
14965
+ return;
14966
+ }
14967
+ const completedAt = read2(turn, "completed_at");
14968
+ const endTime = typeof completedAt === "number" && Number.isFinite(completedAt) && completedAt >= 0 ? completedAt : observedAt;
14969
+ const usage = read2(event, "usage") ?? read2(turn, "usage");
14970
+ const error = eventType === "agent.session.turn.completed" ? void 0 : loggedError(
14971
+ read2(turn, "error"),
14972
+ eventType === "agent.session.turn.cancelled" ? "OpenAI Agents turn cancelled" : "OpenAI Agents turn failed"
14973
+ );
14974
+ await closeTrace(state, endTime, error, usage);
14975
+ }
14976
+ async function captureEvent(state, event) {
14977
+ if (state.ended) {
14978
+ return state;
14979
+ }
14980
+ const eventType = stringValue(read2(event, "type"));
14981
+ const eventId = stringValue(read2(event, "event_id"));
14982
+ if (!eventType || eventId && state.eventIds.includes(eventId)) {
14983
+ return state;
14984
+ }
14985
+ const next = copyState(state);
14986
+ const observedAt = getCurrentUnixTimestamp();
14987
+ let handled = false;
14988
+ if (SESSION_EVENTS.has(eventType)) {
14989
+ const session = read2(event, "session");
14990
+ if (session) {
14991
+ updateSessionMetadata(next, session);
14992
+ }
14993
+ handled = true;
14994
+ }
14995
+ if (eventType === "agent.session.turn.item.added") {
14996
+ await captureItem(next, read2(event, "item"), false, observedAt);
14997
+ handled = true;
14998
+ } else if (eventType === "agent.session.turn.item.done") {
14999
+ await captureItem(next, read2(event, "item"), true, observedAt);
15000
+ handled = true;
15001
+ } else if (TURN_LIFECYCLE_EVENTS.has(eventType)) {
15002
+ await captureTurnLifecycle(next, event, eventType, observedAt);
15003
+ handled = true;
15004
+ } else if (SUBAGENT_EVENTS.has(eventType)) {
15005
+ await captureSubagent(next, eventType, read2(event, "subagent"), observedAt);
15006
+ handled = true;
15007
+ } else if (eventType === "agent.session.turn.output_text.delta" && next.firstTokenAt === void 0 && stringValue(read2(event, "delta"))) {
15008
+ next.firstTokenAt = observedAt;
15009
+ startRootSpan(next).log({
15010
+ metrics: { time_to_first_token: observedAt - next.startTime }
15011
+ });
15012
+ handled = true;
15013
+ } else if (eventType === "agent.session.failed") {
15014
+ const session = read2(event, "session");
15015
+ const lastActiveAt = read2(session, "last_active_at");
15016
+ const endTime = typeof lastActiveAt === "number" && Number.isFinite(lastActiveAt) && lastActiveAt >= 0 ? lastActiveAt : observedAt;
15017
+ await closeTrace(
15018
+ next,
15019
+ endTime,
15020
+ loggedError(read2(session, "error"), "OpenAI Agents session failed"),
15021
+ read2(session, "usage")
15022
+ );
15023
+ handled = true;
15024
+ } else if (eventType === "error") {
15025
+ await closeTrace(
15026
+ next,
15027
+ observedAt,
15028
+ loggedError(read2(event, "error"), "OpenAI Agents session failed")
15029
+ );
15030
+ handled = true;
15031
+ }
15032
+ if (!handled) {
15033
+ return state;
15034
+ }
15035
+ if (eventId) {
15036
+ next.eventIds.push(eventId);
15037
+ }
15038
+ return next;
15039
+ }
15040
+ var interceptOpenAIAgentsTraceStart = async (target, thisArg, args) => {
15041
+ const fallback2 = await Reflect.apply(target, thisArg, args);
15042
+ try {
15043
+ const state = args[0].state;
15044
+ const parent = state.rootParent;
15045
+ const traceArgs = args[0].args;
15046
+ const parentComponents = SpanComponentsV4.fromStr(parent);
15047
+ const hasParentSpan = Boolean(
15048
+ parentComponents.data.row_id && parentComponents.data.span_id && parentComponents.data.root_span_id
15049
+ );
15050
+ const rootComponents = SpanComponentsV4.fromStr(state.root);
15051
+ const rowId = stringValue(rootComponents.data.row_id);
15052
+ const rootSpanId = stringValue(rootComponents.data.root_span_id);
15053
+ const spanId = stringValue(rootComponents.data.span_id);
15054
+ if (!rowId || !rootSpanId || !spanId) {
15055
+ throw new Error("OpenAI Agents trace root is invalid");
15056
+ }
15057
+ withCurrent(
15058
+ NOOP_SPAN,
15059
+ () => _internalStartSpanWithInitialMergeAndParentSpanIds(
15060
+ withSpanInstrumentationName(
15061
+ {
15062
+ name: "openai.agents.turn",
15063
+ type: "task" /* TASK */,
15064
+ parent,
15065
+ ...!hasParentSpan ? {
15066
+ parentSpanIds: {
15067
+ parentSpanIds: [],
15068
+ rootSpanId
15069
+ }
15070
+ } : {},
15071
+ spanId,
15072
+ startTime: state.startTime,
15073
+ event: {
15074
+ id: rowId,
15075
+ input: read2(traceArgs, "input"),
15076
+ metadata: traceMetadata(traceArgs)
15077
+ }
15078
+ },
15079
+ INSTRUMENTATION_NAMES.OPENAI
15080
+ )
15081
+ )
15082
+ );
15083
+ return state;
15084
+ } catch (error) {
15085
+ logInstrumentationError("could not start trace", error);
15086
+ return fallback2;
15087
+ }
15088
+ };
15089
+ var interceptOpenAIAgentsTraceCapture = async (target, thisArg, args) => {
15090
+ const fallback2 = await Reflect.apply(target, thisArg, args);
15091
+ if (!args[0].state) {
15092
+ return fallback2;
15093
+ }
15094
+ try {
15095
+ return await captureEvent(args[0].state, args[0].event);
15096
+ } catch (error) {
15097
+ logInstrumentationError("could not capture event", error);
15098
+ return fallback2;
15099
+ }
15100
+ };
15101
+ var interceptOpenAIAgentsTraceFail = async (target, thisArg, args) => {
15102
+ const fallback2 = await Reflect.apply(target, thisArg, args);
15103
+ if (!args[0].state) {
15104
+ return fallback2;
15105
+ }
15106
+ try {
15107
+ const next = copyState(args[0].state);
15108
+ await closeTrace(
15109
+ next,
15110
+ getCurrentUnixTimestamp(),
15111
+ loggedError(args[0].error, "OpenAI Agents request failed")
15112
+ );
15113
+ return next;
15114
+ } catch (error) {
15115
+ logInstrumentationError("could not fail trace", error);
15116
+ return fallback2;
15117
+ }
15118
+ };
15119
+
14445
15120
  // src/instrumentation/plugins/openai-plugin.ts
14446
15121
  var OpenAIPlugin = class extends BasePlugin {
14447
15122
  constructor() {
@@ -14449,6 +15124,13 @@ var OpenAIPlugin = class extends BasePlugin {
14449
15124
  }
14450
15125
  onEnable() {
14451
15126
  this.unsubscribers.push(
15127
+ openAIChannels.agentsTraceStart.intercept(
15128
+ interceptOpenAIAgentsTraceStart
15129
+ ),
15130
+ openAIChannels.agentsTraceCapture.intercept(
15131
+ interceptOpenAIAgentsTraceCapture
15132
+ ),
15133
+ openAIChannels.agentsTraceFail.intercept(interceptOpenAIAgentsTraceFail),
14452
15134
  openAIChannels.filesCreateTraced.intercept(
14453
15135
  interceptOpenAIFilesCreateTraced
14454
15136
  ),
@@ -15009,7 +15691,7 @@ async function* patchCodexEventStream(events, state) {
15009
15691
  try {
15010
15692
  await handleCodexEvent(state, event);
15011
15693
  } catch (error) {
15012
- logInstrumentationError("OpenAI Codex stream event", error);
15694
+ logInstrumentationError2("OpenAI Codex stream event", error);
15013
15695
  }
15014
15696
  yield event;
15015
15697
  }
@@ -15509,10 +16191,10 @@ function safeLog(span, event) {
15509
16191
  try {
15510
16192
  span.log(event);
15511
16193
  } catch (error) {
15512
- logInstrumentationError("OpenAI Codex span log", error);
16194
+ logInstrumentationError2("OpenAI Codex span log", error);
15513
16195
  }
15514
16196
  }
15515
- function logInstrumentationError(context, error) {
16197
+ function logInstrumentationError2(context, error) {
15516
16198
  debugLogger.error(`Error processing ${context}:`, error);
15517
16199
  }
15518
16200
 
@@ -16907,27 +17589,8 @@ function continuationParentFromCreateSessionParams(params) {
16907
17589
  }
16908
17590
  return context.parent;
16909
17591
  }
16910
- function exportSpanSynchronously(span) {
16911
- const parentInfo = span.getParentInfo();
16912
- if (!parentInfo) {
16913
- return void 0;
16914
- }
16915
- const objectId = parentInfo.objectId.getSync().value;
16916
- if (!objectId && !parentInfo.computeObjectMetadataArgs) {
16917
- return void 0;
16918
- }
16919
- return new SpanComponentsV4({
16920
- object_type: parentInfo.objectType,
16921
- ...objectId ? { object_id: objectId } : {
16922
- compute_object_metadata_args: parentInfo.computeObjectMetadataArgs ?? {}
16923
- },
16924
- row_id: span.id,
16925
- root_span_id: span.rootSpanId,
16926
- span_id: span.spanId
16927
- }).toStr();
16928
- }
16929
17592
  function exportedParent(parent) {
16930
- return typeof parent === "string" ? parent : exportSpanSynchronously(parent);
17593
+ return typeof parent === "string" ? parent : _internalExportParentSynchronously(parent);
16931
17594
  }
16932
17595
  function addSerializedContext(args) {
16933
17596
  if (!isObject(args.continuation) || args.sessionId === void 0) {
@@ -17684,16 +18347,16 @@ function braintrustAISDKTelemetry() {
17684
18347
  if (!toolCallId || !state) {
17685
18348
  return;
17686
18349
  }
17687
- const toolOutput = event.toolOutput;
18350
+ const toolOutput2 = event.toolOutput;
17688
18351
  const workflowToolError = event.success === false && "error" in event ? event.error : void 0;
17689
- if (toolOutput?.type === "tool-error" || workflowToolError !== void 0) {
17690
- const error = toolOutput?.error ?? workflowToolError;
18352
+ if (toolOutput2?.type === "tool-error" || workflowToolError !== void 0) {
18353
+ const error = toolOutput2?.error ?? workflowToolError;
17691
18354
  state.span.log({
17692
18355
  error: error instanceof Error ? error.message : String(error),
17693
18356
  metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
17694
18357
  });
17695
18358
  } else {
17696
- const output = toolOutput && "output" in toolOutput ? toolOutput.output : event.output;
18359
+ const output = toolOutput2 && "output" in toolOutput2 ? toolOutput2.output : event.output;
17697
18360
  state.span.log({
17698
18361
  ...shouldRecordOutputs(event) ? { output } : {},
17699
18362
  metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
@@ -20152,9 +20815,9 @@ function patchAISDKStreamingResult(args) {
20152
20815
  }
20153
20816
  finalize({ metrics, output });
20154
20817
  } catch (error) {
20155
- const loggedError = toLoggedError(error);
20818
+ const loggedError2 = toLoggedError(error);
20156
20819
  try {
20157
- span.log({ error: loggedError });
20820
+ span.log({ error: loggedError2 });
20158
20821
  } catch (loggingError) {
20159
20822
  debugLogger.error(
20160
20823
  "Error logging AI SDK streaming failure:",
@@ -20162,7 +20825,7 @@ function patchAISDKStreamingResult(args) {
20162
20825
  );
20163
20826
  }
20164
20827
  finalize({
20165
- error: error instanceof Error ? error : new Error(String(loggedError))
20828
+ error: error instanceof Error ? error : new Error(String(loggedError2))
20166
20829
  });
20167
20830
  }
20168
20831
  };
@@ -20275,9 +20938,9 @@ function patchAISDKStreamingResult(args) {
20275
20938
  }
20276
20939
  controller.enqueue(value);
20277
20940
  } catch (error) {
20278
- const loggedError = toLoggedError(error);
20941
+ const loggedError2 = toLoggedError(error);
20279
20942
  try {
20280
- span.log({ error: loggedError });
20943
+ span.log({ error: loggedError2 });
20281
20944
  } catch (loggingError) {
20282
20945
  debugLogger.error(
20283
20946
  "Error logging AI SDK base stream failure:",
@@ -20285,7 +20948,7 @@ function patchAISDKStreamingResult(args) {
20285
20948
  );
20286
20949
  }
20287
20950
  finalize({
20288
- error: error instanceof Error ? error : new Error(String(loggedError))
20951
+ error: error instanceof Error ? error : new Error(String(loggedError2))
20289
20952
  });
20290
20953
  controller.error(error);
20291
20954
  }
@@ -23179,7 +23842,7 @@ function wrapSendOptionsCallbacks(options, state) {
23179
23842
  try {
23180
23843
  await handleInteractionUpdate(state, args.update);
23181
23844
  } catch (error) {
23182
- logInstrumentationError2("Cursor SDK onDelta", error);
23845
+ logInstrumentationError3("Cursor SDK onDelta", error);
23183
23846
  }
23184
23847
  if (originalOnDelta) {
23185
23848
  return originalOnDelta(args);
@@ -23189,7 +23852,7 @@ function wrapSendOptionsCallbacks(options, state) {
23189
23852
  try {
23190
23853
  handleStepUpdate(state, args.step);
23191
23854
  } catch (error) {
23192
- logInstrumentationError2("Cursor SDK onStep", error);
23855
+ logInstrumentationError3("Cursor SDK onStep", error);
23193
23856
  }
23194
23857
  if (originalOnStep) {
23195
23858
  return originalOnStep(args);
@@ -23271,7 +23934,7 @@ async function* patchCursorStream(stream, state) {
23271
23934
  try {
23272
23935
  await handleStreamMessage2(state, message);
23273
23936
  } catch (error) {
23274
- logInstrumentationError2("Cursor SDK stream", error);
23937
+ logInstrumentationError3("Cursor SDK stream", error);
23275
23938
  }
23276
23939
  yield message;
23277
23940
  }
@@ -23335,7 +23998,7 @@ async function handleToolUpdate(state, update) {
23335
23998
  if (!state.activeToolSpans.has(callId)) {
23336
23999
  state.activeToolSpans.set(
23337
24000
  callId,
23338
- await startToolSpan(state, {
24001
+ await startToolSpan2(state, {
23339
24002
  args,
23340
24003
  callId,
23341
24004
  name,
@@ -23346,7 +24009,7 @@ async function handleToolUpdate(state, update) {
23346
24009
  }
23347
24010
  return;
23348
24011
  }
23349
- const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan(state, {
24012
+ const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan2(state, {
23350
24013
  args,
23351
24014
  callId,
23352
24015
  name,
@@ -23383,7 +24046,7 @@ async function handleStreamMessage2(state, message) {
23383
24046
  } else if (block?.type === "tool_use" && block.id) {
23384
24047
  state.activeToolSpans.set(
23385
24048
  block.id,
23386
- await startToolSpan(state, {
24049
+ await startToolSpan2(state, {
23387
24050
  args: block.input,
23388
24051
  callId: block.id,
23389
24052
  name: block.name,
@@ -23418,7 +24081,7 @@ async function handleToolMessage(state, message) {
23418
24081
  if (!state.activeToolSpans.has(callId)) {
23419
24082
  state.activeToolSpans.set(
23420
24083
  callId,
23421
- await startToolSpan(state, {
24084
+ await startToolSpan2(state, {
23422
24085
  args: message.args,
23423
24086
  callId,
23424
24087
  name: message.name,
@@ -23429,7 +24092,7 @@ async function handleToolMessage(state, message) {
23429
24092
  }
23430
24093
  return;
23431
24094
  }
23432
- const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan(state, {
24095
+ const toolState = state.activeToolSpans.get(callId) ?? await startToolSpan2(state, {
23433
24096
  args: message.args,
23434
24097
  callId,
23435
24098
  name: message.name,
@@ -23456,7 +24119,7 @@ async function handleConversation(state, turns) {
23456
24119
  const command = turn.turn?.shellCommand?.command;
23457
24120
  if (command) {
23458
24121
  const callId = `shell:${state.activeToolSpans.size}:${command}`;
23459
- const toolState = await startToolSpan(state, {
24122
+ const toolState = await startToolSpan2(state, {
23460
24123
  args: turn.turn?.shellCommand,
23461
24124
  callId,
23462
24125
  name: "shell",
@@ -23480,7 +24143,7 @@ async function handleConversationStep(state, step) {
23480
24143
  }
23481
24144
  const toolCall = step.message;
23482
24145
  const callId = typeof toolCall?.callId === "string" ? toolCall.callId : `conversation-tool:${state.activeToolSpans.size}`;
23483
- const toolState = await startToolSpan(state, {
24146
+ const toolState = await startToolSpan2(state, {
23484
24147
  args: extractToolArgs(toolCall),
23485
24148
  callId,
23486
24149
  name: extractToolName(toolCall),
@@ -23511,7 +24174,7 @@ function handleStepUpdate(state, step) {
23511
24174
  state.stepText.push(step.message.text);
23512
24175
  }
23513
24176
  }
23514
- async function startToolSpan(state, args) {
24177
+ async function startToolSpan2(state, args) {
23515
24178
  const name = args.name || "unknown";
23516
24179
  const metadata = {
23517
24180
  "cursor_sdk.tool.status": args.status,
@@ -23798,10 +24461,10 @@ function safeLog2(span, event) {
23798
24461
  try {
23799
24462
  span.log(event);
23800
24463
  } catch (error) {
23801
- logInstrumentationError2("Cursor SDK span log", error);
24464
+ logInstrumentationError3("Cursor SDK span log", error);
23802
24465
  }
23803
24466
  }
23804
- function logInstrumentationError2(context, error) {
24467
+ function logInstrumentationError3(context, error) {
23805
24468
  debugLogger.error(`Error processing ${context}:`, error);
23806
24469
  }
23807
24470
  function cleanMetrics2(metrics) {
@@ -24639,6 +25302,10 @@ var googleGenAIChannels = defineChannels(
24639
25302
  channelName: "models.embedContent",
24640
25303
  kind: "async"
24641
25304
  }),
25305
+ httpResponseJson: channel({
25306
+ channelName: "httpResponse.json",
25307
+ kind: "async"
25308
+ }),
24642
25309
  interactionsCreate: channel({
24643
25310
  channelName: "interactions.create",
24644
25311
  kind: "async"
@@ -24787,13 +25454,45 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24787
25454
  subscribeToEmbedContentChannel() {
24788
25455
  const tracingChannel = googleGenAIChannels.embedContent.tracingChannel();
24789
25456
  const states = /* @__PURE__ */ new WeakMap();
25457
+ const embeddingSpans = /* @__PURE__ */ new WeakSet();
25458
+ this.unsubscribers.push(
25459
+ googleGenAIChannels.httpResponseJson.intercept(
25460
+ (target, thisArg, args) => {
25461
+ const span = currentSpan();
25462
+ const result = Reflect.apply(target, thisArg, args);
25463
+ if (embeddingSpans.has(span)) {
25464
+ void Promise.resolve(result).then(
25465
+ (response) => {
25466
+ try {
25467
+ const metrics = cleanMetrics3(
25468
+ extractEmbedContentMetrics(response)
25469
+ );
25470
+ if (embeddingSpans.has(span) && Object.keys(metrics).length > 0) {
25471
+ span.log({ metrics });
25472
+ }
25473
+ } catch (error) {
25474
+ debugLogger.error(
25475
+ "Error reading Google GenAI embedding usage:",
25476
+ error
25477
+ );
25478
+ }
25479
+ },
25480
+ () => {
25481
+ }
25482
+ // The embedding channel handles the original rejection.
25483
+ );
25484
+ }
25485
+ return result;
25486
+ }
25487
+ )
25488
+ );
24790
25489
  const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
24791
25490
  tracingChannel,
24792
25491
  states,
24793
25492
  (event) => {
24794
25493
  const params = event.arguments[0];
24795
25494
  const input = serializeEmbedContentInput(params);
24796
- const metadata = extractEmbedContentMetadata(params);
25495
+ const metadata = { provider: "google", model: params.model };
24797
25496
  const span = startSpan(
24798
25497
  withSpanInstrumentationName(
24799
25498
  {
@@ -24806,6 +25505,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24806
25505
  INSTRUMENTATION_NAMES.GOOGLE_GENAI
24807
25506
  )
24808
25507
  );
25508
+ embeddingSpans.add(span);
24809
25509
  return {
24810
25510
  span,
24811
25511
  startTime: getCurrentUnixTimestamp()
@@ -24817,7 +25517,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24817
25517
  ensureSpanState(states, event, () => {
24818
25518
  const params = event.arguments[0];
24819
25519
  const input = serializeEmbedContentInput(params);
24820
- const metadata = extractEmbedContentMetadata(params);
25520
+ const metadata = { provider: "google", model: params.model };
24821
25521
  const span = startSpan(
24822
25522
  withSpanInstrumentationName(
24823
25523
  {
@@ -24830,6 +25530,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24830
25530
  INSTRUMENTATION_NAMES.GOOGLE_GENAI
24831
25531
  )
24832
25532
  );
25533
+ embeddingSpans.add(span);
24833
25534
  return {
24834
25535
  span,
24835
25536
  startTime: getCurrentUnixTimestamp()
@@ -24842,20 +25543,28 @@ var GoogleGenAIPlugin = class extends BasePlugin {
24842
25543
  return;
24843
25544
  }
24844
25545
  try {
24845
- const output = summarizeEmbedContentOutput(event.result);
24846
25546
  spanState.span.log({
24847
- ...output ? { output } : {},
25547
+ output: summarizeEmbedContentOutput(event.result),
24848
25548
  metrics: cleanMetrics3(
24849
25549
  extractEmbedContentMetrics(event.result, spanState.startTime)
24850
25550
  )
24851
25551
  });
24852
25552
  } finally {
25553
+ embeddingSpans.delete(spanState.span);
24853
25554
  spanState.span.end();
24854
25555
  states.delete(event);
24855
25556
  }
24856
25557
  },
24857
25558
  error: (event) => {
24858
- logErrorAndEndSpan(states, event);
25559
+ const spanState = states.get(event);
25560
+ if (!spanState) return;
25561
+ try {
25562
+ spanState.span.log({ error: event.error, output: { count: 0 } });
25563
+ } finally {
25564
+ embeddingSpans.delete(spanState.span);
25565
+ spanState.span.end();
25566
+ states.delete(event);
25567
+ }
24859
25568
  }
24860
25569
  };
24861
25570
  tracingChannel.subscribe(handlers);
@@ -25090,15 +25799,53 @@ function serializeGenerateContentInput(params) {
25090
25799
  return input;
25091
25800
  }
25092
25801
  function serializeEmbedContentInput(params) {
25802
+ let contents = Array.isArray(params.contents) ? params.contents : [params.contents];
25803
+ if (params.model.includes("gemini-embedding-2") && contents.length > 0 && contents.every(
25804
+ (content) => typeof content === "string" || !Array.isArray(content) && !("parts" in content)
25805
+ )) {
25806
+ contents = [contents];
25807
+ }
25093
25808
  const input = {
25094
- model: params.model,
25095
- contents: serializeContentCollection(params.contents)
25809
+ inputs: contents.map((content) => {
25810
+ const parts = typeof content === "string" ? [content] : Array.isArray(content) ? content : "parts" in content ? content.parts : [content];
25811
+ const normalized = parts.flatMap((part) => {
25812
+ if (typeof part === "string") return [{ type: "text", text: part }];
25813
+ if (part.text !== void 0) return [{ type: "text", text: part.text }];
25814
+ const media = part.inlineData ?? part.fileData;
25815
+ if (!media) return [];
25816
+ const data = "data" in media ? `data:${media.mimeType};base64,${typeof media.data === "string" ? media.data : uint8ArrayToBase64(media.data)}` : media.fileUri;
25817
+ return media.mimeType?.startsWith("image/") ? [{ type: "image_url", image_url: { url: data } }] : [
25818
+ {
25819
+ type: "file",
25820
+ file: {
25821
+ file_data: data,
25822
+ ..."displayName" in media && media.displayName ? { filename: media.displayName } : {}
25823
+ }
25824
+ }
25825
+ ];
25826
+ });
25827
+ return {
25828
+ content: normalized.length === 1 && normalized[0].type === "text" ? normalized[0].text : normalized
25829
+ };
25830
+ }),
25831
+ ...params.config?.outputDimensionality !== void 0 ? { output_dimensions: params.config.outputDimensionality } : {}
25096
25832
  };
25097
- const config = params.config ? tryToDict(params.config) : null;
25098
- if (config) {
25099
- input.config = config;
25833
+ try {
25834
+ const processed = processInputAttachments(input);
25835
+ const hasInlineMedia = processed.inputs.some(
25836
+ ({ content }) => Array.isArray(content) && content.some((part) => {
25837
+ const data = part.type === "image_url" ? part.image_url.url : part.type === "file" ? part.file.file_data : void 0;
25838
+ return typeof data === "string" && data.startsWith("data:");
25839
+ })
25840
+ );
25841
+ return hasInlineMedia ? input : processed;
25842
+ } catch (error) {
25843
+ debugLogger.error(
25844
+ "Error processing Google GenAI embedding attachments:",
25845
+ error
25846
+ );
25847
+ return input;
25100
25848
  }
25101
- return input;
25102
25849
  }
25103
25850
  function serializeInteractionInput(params) {
25104
25851
  const input = {
@@ -25286,19 +26033,6 @@ function extractGenerateContentMetadata(params) {
25286
26033
  }
25287
26034
  return metadata;
25288
26035
  }
25289
- function extractEmbedContentMetadata(params) {
25290
- const metadata = {};
25291
- if (params.model) {
25292
- metadata.model = params.model;
25293
- }
25294
- const config = params.config ? tryToDict(params.config) : null;
25295
- if (config) {
25296
- Object.keys(config).forEach((key) => {
25297
- metadata[key] = config[key];
25298
- });
25299
- }
25300
- return metadata;
25301
- }
25302
26036
  function extractGenerateContentMetrics(response, startTime) {
25303
26037
  const metrics = {};
25304
26038
  if (startTime !== void 0) {
@@ -25318,15 +26052,23 @@ function extractEmbedContentMetrics(response, startTime) {
25318
26052
  const end = getCurrentUnixTimestamp();
25319
26053
  metrics.start = startTime;
25320
26054
  metrics.end = end;
25321
- metrics.duration = end - startTime;
25322
- }
25323
- if (response?.usageMetadata) {
25324
- populateUsageMetrics(metrics, response.usageMetadata);
25325
26055
  }
25326
26056
  const embeddingTokenCount = extractEmbedPromptTokenCount(response);
25327
26057
  if (embeddingTokenCount !== void 0) {
25328
26058
  metrics.prompt_tokens = embeddingTokenCount;
25329
- metrics.tokens = embeddingTokenCount;
26059
+ }
26060
+ const totalTokens = response?.usageMetadata?.totalTokenCount ?? embeddingTokenCount;
26061
+ if (totalTokens !== void 0) {
26062
+ metrics.tokens = totalTokens;
26063
+ }
26064
+ const audioTokens = (response?.usageMetadata?.promptTokenDetails ?? response?.usageMetadata?.promptTokensDetails)?.filter(
26065
+ (detail) => detail.modality === "AUDIO" && detail.tokenCount !== void 0
26066
+ );
26067
+ if (audioTokens?.length) {
26068
+ metrics.prompt_audio_tokens = audioTokens.reduce(
26069
+ (sum, detail) => sum + (detail.tokenCount ?? 0),
26070
+ 0
26071
+ );
25330
26072
  }
25331
26073
  return metrics;
25332
26074
  }
@@ -25365,41 +26107,25 @@ function extractEmbedPromptTokenCount(response) {
25365
26107
  if (typeof usagePromptTokens === "number" && Number.isFinite(usagePromptTokens)) {
25366
26108
  return usagePromptTokens;
25367
26109
  }
25368
- const usageTotalTokens = response.usageMetadata?.totalTokenCount;
25369
- if (typeof usageTotalTokens === "number" && Number.isFinite(usageTotalTokens)) {
25370
- return usageTotalTokens;
25371
- }
25372
26110
  const embeddings = Array.isArray(response.embeddings) ? response.embeddings : response.embedding ? [response.embedding] : [];
25373
26111
  if (embeddings.length === 0) {
25374
26112
  return void 0;
25375
26113
  }
25376
26114
  let total = 0;
25377
- let sawAny = false;
25378
26115
  for (const embedding of embeddings) {
25379
26116
  const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
25380
26117
  const tokenCount2 = embeddingStats?.tokenCount;
25381
26118
  if (typeof tokenCount2 === "number" && Number.isFinite(tokenCount2)) {
25382
26119
  total += tokenCount2;
25383
- sawAny = true;
26120
+ } else {
26121
+ return void 0;
25384
26122
  }
25385
26123
  }
25386
- return sawAny ? total : void 0;
26124
+ return total;
25387
26125
  }
25388
26126
  function summarizeEmbedContentOutput(response) {
25389
- if (!response) {
25390
- return void 0;
25391
- }
25392
- const embeddings = Array.isArray(response.embeddings) ? response.embeddings : response.embedding ? [response.embedding] : [];
25393
- if (embeddings.length === 0) {
25394
- return void 0;
25395
- }
25396
- const firstValues = embeddings[0]?.values;
25397
- if (!Array.isArray(firstValues)) {
25398
- return void 0;
25399
- }
25400
26127
  return {
25401
- embedding_count: embeddings.length,
25402
- embedding_length: firstValues.length
26128
+ count: Array.isArray(response?.embeddings) ? response.embeddings.length : response?.embedding ? 1 : 0
25403
26129
  };
25404
26130
  }
25405
26131
  function populateUsageMetrics(metrics, usage) {
@@ -29026,6 +29752,379 @@ function aggregateMistralStreamChunks(chunks) {
29026
29752
  };
29027
29753
  }
29028
29754
 
29755
+ // src/instrumentation/plugins/langgraph-sdk-channels.ts
29756
+ var langGraphSDKChannels = defineChannels(
29757
+ "@langchain/langgraph-sdk",
29758
+ {
29759
+ wait: channel({
29760
+ channelName: "runs.wait",
29761
+ kind: "async"
29762
+ }),
29763
+ stream: channel({
29764
+ channelName: "runs.stream",
29765
+ kind: "sync-stream"
29766
+ })
29767
+ },
29768
+ { instrumentationName: INSTRUMENTATION_NAMES.LANGGRAPH_SDK }
29769
+ );
29770
+
29771
+ // src/instrumentation/plugins/langgraph-sdk-plugin.ts
29772
+ var LangGraphSDKPlugin = class extends BasePlugin {
29773
+ onEnable() {
29774
+ this.unsubscribers.push(
29775
+ langGraphSDKChannels.wait.intercept(
29776
+ (target, self, args) => instrumentRun("wait", args, () => Reflect.apply(target, self, args))
29777
+ ),
29778
+ langGraphSDKChannels.stream.intercept(
29779
+ (target, self, args) => instrumentRun("stream", args, () => Reflect.apply(target, self, args))
29780
+ )
29781
+ );
29782
+ }
29783
+ onDisable() {
29784
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
29785
+ }
29786
+ };
29787
+ function normalizeMessage(value) {
29788
+ if (!isObject(value)) return value;
29789
+ 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);
29790
+ if (typeof role !== "string") return value;
29791
+ const message = {
29792
+ role,
29793
+ content: value.content ?? ""
29794
+ };
29795
+ for (const key of ["name", "tool_call_id", "refusal"]) {
29796
+ if (value[key] !== void 0) message[key] = value[key];
29797
+ }
29798
+ const additional = isObject(value.additional_kwargs) ? value.additional_kwargs : {};
29799
+ const toolCalls2 = Array.isArray(value.tool_calls) && value.tool_calls.length ? value.tool_calls : additional.tool_calls;
29800
+ if (Array.isArray(toolCalls2) && toolCalls2.length > 0) {
29801
+ message.tool_calls = toolCalls2.map((call) => {
29802
+ if (!isObject(call)) return call;
29803
+ if (isObject(call.function)) return call;
29804
+ return {
29805
+ id: call.id,
29806
+ type: "function",
29807
+ function: {
29808
+ name: call.name,
29809
+ arguments: typeof call.args === "string" ? call.args : JSON.stringify(call.args ?? {})
29810
+ }
29811
+ };
29812
+ });
29813
+ }
29814
+ if (Array.isArray(value.invalid_tool_calls) && value.invalid_tool_calls.length > 0)
29815
+ message.invalid_tool_calls = value.invalid_tool_calls;
29816
+ if (message.refusal === void 0 && additional.refusal !== void 0)
29817
+ message.refusal = additional.refusal;
29818
+ return message;
29819
+ }
29820
+ function normalizeRunError(value) {
29821
+ let name;
29822
+ let message;
29823
+ if (value instanceof Error) {
29824
+ name = value.name;
29825
+ message = value.message;
29826
+ } else if (isObject(value) && typeof value.error === "string" && typeof value.message === "string") {
29827
+ name = value.error;
29828
+ message = value.message;
29829
+ } else {
29830
+ return value;
29831
+ }
29832
+ for (let depth = 0; depth < 3; depth++) {
29833
+ try {
29834
+ const nested = JSON.parse(
29835
+ message.startsWith(`${name}: `) ? message.slice(name.length + 2) : message
29836
+ );
29837
+ if (!isObject(nested) || typeof nested.error !== "string" || typeof nested.message !== "string")
29838
+ break;
29839
+ name = nested.error;
29840
+ message = nested.message;
29841
+ } catch {
29842
+ break;
29843
+ }
29844
+ }
29845
+ if (value instanceof Error && name === value.name && message === value.message)
29846
+ return value;
29847
+ return Object.assign(new Error(message), { name });
29848
+ }
29849
+ function normalizeState(value) {
29850
+ if (!isObject(value)) return value;
29851
+ return Object.fromEntries(
29852
+ Object.entries(value).map(([key, field]) => {
29853
+ if (key === "messages" && Array.isArray(field))
29854
+ return [key, field.map(normalizeMessage)];
29855
+ if (key === "__error__") {
29856
+ const error = normalizeRunError(field);
29857
+ if (error instanceof Error)
29858
+ return [key, { error: error.name, message: error.message }];
29859
+ }
29860
+ return [key, field];
29861
+ })
29862
+ );
29863
+ }
29864
+ function normalizeRunOutput(value, input) {
29865
+ if (!isObject(value)) return value;
29866
+ if (Array.isArray(value.messages)) {
29867
+ if (value.__interrupt__ !== void 0 || value.__error__ !== void 0)
29868
+ return void 0;
29869
+ const inputMessages = isObject(input) && Array.isArray(input.messages) ? input.messages : [];
29870
+ let inputPrefixLength = 0;
29871
+ while (inputPrefixLength < inputMessages.length) {
29872
+ const previous = inputMessages[inputPrefixLength];
29873
+ const message = value.messages[inputPrefixLength];
29874
+ 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)))
29875
+ break;
29876
+ inputPrefixLength++;
29877
+ }
29878
+ for (let index = value.messages.length - 1; index >= inputPrefixLength; index--) {
29879
+ const message = value.messages[index];
29880
+ const normalized = normalizeMessage(message);
29881
+ if (!isObject(normalized)) continue;
29882
+ if (normalized.role === "user") return void 0;
29883
+ if (normalized.role !== "assistant") continue;
29884
+ if (inputMessages.some((previous) => {
29885
+ if (!isObject(previous) || !isObject(message)) return false;
29886
+ return previous.id !== void 0 && previous.id === message.id && JSON.stringify(normalizeMessage(previous)) === JSON.stringify(normalized);
29887
+ }))
29888
+ continue;
29889
+ return normalized;
29890
+ }
29891
+ return void 0;
29892
+ }
29893
+ const result = Object.fromEntries(
29894
+ Object.entries(value).filter(
29895
+ ([key]) => key !== "__interrupt__" && key !== "__error__"
29896
+ )
29897
+ );
29898
+ return !Object.keys(result).length && (value.__interrupt__ !== void 0 || value.__error__ !== void 0) ? void 0 : result;
29899
+ }
29900
+ function instrumentRun(operation, [threadId, assistantId, options], invoke2) {
29901
+ if (isAutoInstrumentationSuppressed()) return invoke2();
29902
+ const start = getCurrentUnixTimestamp();
29903
+ let span;
29904
+ try {
29905
+ const metadata = {
29906
+ "langgraph.thread_id": threadId,
29907
+ "langgraph.assistant_id": assistantId
29908
+ };
29909
+ for (const key of [
29910
+ "streamMode",
29911
+ "streamSubgraphs",
29912
+ "interruptBefore",
29913
+ "interruptAfter",
29914
+ "multitaskStrategy",
29915
+ "durability"
29916
+ ]) {
29917
+ if (options?.[key] !== void 0) metadata[key] = options[key];
29918
+ }
29919
+ span = startSpan(
29920
+ withSpanInstrumentationName(
29921
+ {
29922
+ name: `langgraph.runs.${operation}`,
29923
+ spanAttributes: { type: "task" /* TASK */ },
29924
+ event: {
29925
+ input: options?.command === void 0 ? normalizeState(options?.input) : {
29926
+ input: normalizeState(options.input),
29927
+ command: options.command
29928
+ },
29929
+ metadata
29930
+ }
29931
+ },
29932
+ INSTRUMENTATION_NAMES.LANGGRAPH_SDK
29933
+ )
29934
+ );
29935
+ } catch (error) {
29936
+ debugLogger.error("Error starting LangGraph SDK span:", error);
29937
+ return invoke2();
29938
+ }
29939
+ let ended = false;
29940
+ let output;
29941
+ let streamError;
29942
+ let firstToken;
29943
+ const updates = [];
29944
+ const usageByMessage = /* @__PURE__ */ new Map();
29945
+ const captureUsage = (id, usage) => {
29946
+ if (!isObject(usage)) return;
29947
+ const metrics = {};
29948
+ for (const [source, destination] of [
29949
+ ["input_tokens", "prompt_tokens"],
29950
+ ["output_tokens", "completion_tokens"],
29951
+ ["total_tokens", "tokens"]
29952
+ ]) {
29953
+ const value = usage[source];
29954
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0)
29955
+ metrics[destination] = value;
29956
+ }
29957
+ if (metrics.tokens === void 0 && metrics.prompt_tokens !== void 0 && metrics.completion_tokens !== void 0)
29958
+ metrics.tokens = metrics.prompt_tokens + metrics.completion_tokens;
29959
+ usageByMessage.set(id, { ...usageByMessage.get(id), ...metrics });
29960
+ };
29961
+ const messages = /* @__PURE__ */ new Map();
29962
+ const messageSnapshots = /* @__PURE__ */ new Map();
29963
+ const finish = (error) => {
29964
+ if (ended) return;
29965
+ ended = true;
29966
+ try {
29967
+ const metrics = {};
29968
+ for (const usage of usageByMessage.values()) {
29969
+ for (const [key, value] of Object.entries(usage))
29970
+ metrics[key] = (metrics[key] ?? 0) + value;
29971
+ }
29972
+ if (firstToken !== void 0)
29973
+ metrics.time_to_first_token = firstToken - start;
29974
+ const finalMessages = [
29975
+ ...new Map([...messages, ...messageSnapshots]).values()
29976
+ ];
29977
+ let loggedOutput = normalizeRunOutput(output, options?.input);
29978
+ if (loggedOutput === void 0 && finalMessages.length)
29979
+ loggedOutput = normalizeRunOutput(
29980
+ { messages: finalMessages },
29981
+ void 0
29982
+ );
29983
+ if (output === void 0 && !finalMessages.length && updates.length) {
29984
+ const results = updates.map((update) => normalizeRunOutput(update, options?.input)).filter((update) => update !== void 0);
29985
+ if (results.length) loggedOutput = { updates: results };
29986
+ }
29987
+ const interrupted = [output, ...updates].find(
29988
+ (state) => isObject(state) && state.__interrupt__ !== void 0
29989
+ );
29990
+ span.log({
29991
+ ...loggedOutput !== void 0 ? { output: loggedOutput } : {},
29992
+ ...isObject(interrupted) ? { metadata: { "langgraph.interrupts": interrupted.__interrupt__ } } : {},
29993
+ ...error !== void 0 || streamError !== void 0 ? { error: normalizeRunError(error ?? streamError) } : {},
29994
+ metrics
29995
+ });
29996
+ } catch (error2) {
29997
+ debugLogger.error("Error logging LangGraph SDK span:", error2);
29998
+ }
29999
+ try {
30000
+ span.end();
30001
+ } catch (error2) {
30002
+ debugLogger.error("Error ending LangGraph SDK span:", error2);
30003
+ }
30004
+ };
30005
+ const observeMessages = (value, streaming) => {
30006
+ if (!isObject(value) || !Array.isArray(value.messages)) return;
30007
+ const inputMessages = isObject(options?.input) && Array.isArray(options.input.messages) ? options.input.messages : [];
30008
+ for (const message of value.messages) {
30009
+ if (!isObject(message) || message.type !== "ai" && message.role !== "assistant")
30010
+ continue;
30011
+ if (message.id !== void 0 && inputMessages.some(
30012
+ (input) => isObject(input) && input.id === message.id
30013
+ ))
30014
+ continue;
30015
+ captureUsage(
30016
+ typeof message.id === "string" ? message.id : "message",
30017
+ message.usage_metadata
30018
+ );
30019
+ if (streaming && (typeof message.content === "string" ? message.content.length > 0 : Array.isArray(message.content) && message.content.some(
30020
+ (part) => isObject(part) && typeof part.text === "string" && part.text.length > 0
30021
+ )))
30022
+ firstToken ??= getCurrentUnixTimestamp();
30023
+ }
30024
+ };
30025
+ const onChunk = ({ event, data }) => {
30026
+ if (ended) return;
30027
+ if (event === "metadata" && isObject(data)) {
30028
+ if (typeof data.run_id === "string")
30029
+ span.log({ metadata: { "langgraph.run_id": data.run_id } });
30030
+ } else if (event === "error") {
30031
+ streamError = normalizeRunError(data);
30032
+ } else if (event === "values") {
30033
+ output = data;
30034
+ observeMessages(data, true);
30035
+ } else if (event === "updates") {
30036
+ if (isObject(data)) {
30037
+ const stateUpdates = [];
30038
+ for (const [node, update] of Object.entries(data)) {
30039
+ observeMessages(update, true);
30040
+ if (isObject(update) && Array.isArray(update.messages)) {
30041
+ for (const message of update.messages) {
30042
+ if (isObject(message))
30043
+ messageSnapshots.set(
30044
+ typeof message.id === "string" ? message.id : `update-${messageSnapshots.size}`,
30045
+ message
30046
+ );
30047
+ }
30048
+ const state = Object.fromEntries(
30049
+ Object.entries(update).filter(([key]) => key !== "messages")
30050
+ );
30051
+ if (Object.keys(state).length) stateUpdates.push([node, state]);
30052
+ } else {
30053
+ stateUpdates.push([node, update]);
30054
+ }
30055
+ }
30056
+ if (stateUpdates.length) updates.push(Object.fromEntries(stateUpdates));
30057
+ } else {
30058
+ updates.push(data);
30059
+ }
30060
+ } else if ((event === "messages" || event === "messages/partial" || event === "messages/complete") && Array.isArray(data)) {
30061
+ const parts = event === "messages" ? [data[0]] : data;
30062
+ for (const part of parts) {
30063
+ if (!isObject(part)) continue;
30064
+ const id = typeof part.id === "string" ? part.id : "message";
30065
+ captureUsage(id, part.usage_metadata);
30066
+ const previous = messages.get(id);
30067
+ messages.set(
30068
+ id,
30069
+ event === "messages" && previous && typeof part.content === "string" && typeof previous.content === "string" ? { ...part, content: previous.content + part.content } : part
30070
+ );
30071
+ if (typeof part.content === "string" && part.content.length > 0)
30072
+ firstToken ??= getCurrentUnixTimestamp();
30073
+ }
30074
+ }
30075
+ };
30076
+ let result;
30077
+ try {
30078
+ result = withCurrent(
30079
+ span,
30080
+ () => runWithAutoInstrumentationSuppressed(invoke2)
30081
+ );
30082
+ } catch (error) {
30083
+ finish(error);
30084
+ throw error;
30085
+ }
30086
+ if (operation === "stream") {
30087
+ try {
30088
+ patchStreamIfNeeded(result, {
30089
+ shouldCollect: (chunk) => {
30090
+ try {
30091
+ onChunk(chunk);
30092
+ } catch (error) {
30093
+ debugLogger.error(
30094
+ "Error processing LangGraph stream event:",
30095
+ error
30096
+ );
30097
+ }
30098
+ return false;
30099
+ },
30100
+ aroundNext: (next) => withCurrent(span, () => runWithAutoInstrumentationSuppressed(next)),
30101
+ onComplete: () => finish(),
30102
+ onCancel: () => finish(),
30103
+ onError: (error) => finish(error)
30104
+ });
30105
+ } catch (error) {
30106
+ debugLogger.error("Error observing LangGraph stream:", error);
30107
+ finish();
30108
+ }
30109
+ } else {
30110
+ void Promise.resolve(result).then(
30111
+ (value) => {
30112
+ try {
30113
+ output = value;
30114
+ observeMessages(value, false);
30115
+ if (isObject(value) && isObject(value.__error__))
30116
+ streamError = normalizeRunError(value.__error__);
30117
+ finish();
30118
+ } catch (error) {
30119
+ finish(error);
30120
+ }
30121
+ },
30122
+ (error) => finish(error)
30123
+ );
30124
+ }
30125
+ return result;
30126
+ }
30127
+
29029
30128
  // src/instrumentation/plugins/ollama-channels.ts
29030
30129
  var ollamaChannels = defineChannels(
29031
30130
  "ollama",
@@ -29235,7 +30334,7 @@ function normalizeTextAndImages(content, images) {
29235
30334
  ...unrecognizedImages.length > 0 ? { unrecognizedImages } : {}
29236
30335
  };
29237
30336
  }
29238
- function normalizeMessage(message, toolCallId, syntheticToolCallIdOffset = 0) {
30337
+ function normalizeMessage2(message, toolCallId, syntheticToolCallIdOffset = 0) {
29239
30338
  if (typeof message.role !== "string") {
29240
30339
  return void 0;
29241
30340
  }
@@ -29281,7 +30380,7 @@ function normalizeMessages(messages) {
29281
30380
  toolCallId = pendingToolCallIds.get(toolName)?.shift();
29282
30381
  }
29283
30382
  }
29284
- const normalized = normalizeMessage(
30383
+ const normalized = normalizeMessage2(
29285
30384
  ollamaMessage,
29286
30385
  toolCallId,
29287
30386
  syntheticToolCallIdOffset
@@ -29400,7 +30499,7 @@ function extractOllamaChatOutput(result, syntheticToolCallIdOffset = 0) {
29400
30499
  if (!isObject(result) || !isObject(result.message)) {
29401
30500
  return void 0;
29402
30501
  }
29403
- const message = normalizeMessage(
30502
+ const message = normalizeMessage2(
29404
30503
  result.message,
29405
30504
  void 0,
29406
30505
  syntheticToolCallIdOffset
@@ -32120,14 +33219,14 @@ function extractActionSpanMetadata(args) {
32120
33219
  const options = extractRunInNewSpanOptions(args);
32121
33220
  const labels = isObject(options?.labels) ? options.labels : void 0;
32122
33221
  const metadata = isObject(options?.metadata) ? options.metadata : void 0;
32123
- const actionType = stringValue(labels?.["genkit:metadata:subtype"]);
32124
- const name = stringValue(metadata?.name);
33222
+ const actionType = stringValue2(labels?.["genkit:metadata:subtype"]);
33223
+ const name = stringValue2(metadata?.name);
32125
33224
  if (!actionType || !name) {
32126
33225
  return void 0;
32127
33226
  }
32128
33227
  return {
32129
33228
  actionType,
32130
- key: stringValue(labels?.["genkit:key"]),
33229
+ key: stringValue2(labels?.["genkit:key"]),
32131
33230
  name
32132
33231
  };
32133
33232
  }
@@ -32237,7 +33336,7 @@ function pickNumberMetrics(values) {
32237
33336
  })
32238
33337
  );
32239
33338
  }
32240
- function stringValue(value) {
33339
+ function stringValue2(value) {
32241
33340
  return typeof value === "string" ? value : void 0;
32242
33341
  }
32243
33342
 
@@ -32922,7 +34021,7 @@ function subscribeToFlueContext(value, state) {
32922
34021
  try {
32923
34022
  unsubscribe?.();
32924
34023
  } catch (error) {
32925
- logInstrumentationError3("Flue context unsubscribe", error);
34024
+ logInstrumentationError4("Flue context unsubscribe", error);
32926
34025
  }
32927
34026
  };
32928
34027
  try {
@@ -32938,7 +34037,7 @@ function subscribeToFlueContext(value, state) {
32938
34037
  });
32939
34038
  state.contexts.add(value);
32940
34039
  } catch (error) {
32941
- logInstrumentationError3("Flue context subscription", error);
34040
+ logInstrumentationError4("Flue context subscription", error);
32942
34041
  }
32943
34042
  }
32944
34043
  function isAutoContextTerminalEvent(event, ctx) {
@@ -32994,7 +34093,7 @@ var FlueObserveBridge = class {
32994
34093
  try {
32995
34094
  this.handleEvent(event, flueContextFromUnknown(ctx));
32996
34095
  } catch (error) {
32997
- logInstrumentationError3("Flue observe", error);
34096
+ logInstrumentationError4("Flue observe", error);
32998
34097
  }
32999
34098
  }
33000
34099
  reset() {
@@ -33011,7 +34110,7 @@ var FlueObserveBridge = class {
33011
34110
  try {
33012
34111
  span = this.spanForExecutionOperation(operation, executionContext);
33013
34112
  } catch (error) {
33014
- logInstrumentationError3("Flue execution interceptor", error);
34113
+ logInstrumentationError4("Flue execution interceptor", error);
33015
34114
  }
33016
34115
  return span ? runWithCurrentSpanStore(span, next) : next();
33017
34116
  }
@@ -33217,7 +34316,7 @@ var FlueObserveBridge = class {
33217
34316
  this.runsById.delete(event.runId);
33218
34317
  }
33219
34318
  void flush().catch((error) => {
33220
- logInstrumentationError3("Flue flush", error);
34319
+ logInstrumentationError4("Flue flush", error);
33221
34320
  });
33222
34321
  }
33223
34322
  handleOperationStart(event) {
@@ -33992,17 +35091,17 @@ function safeLog3(span, event) {
33992
35091
  try {
33993
35092
  span.log(event);
33994
35093
  } catch (error) {
33995
- logInstrumentationError3("Flue span log", error);
35094
+ logInstrumentationError4("Flue span log", error);
33996
35095
  }
33997
35096
  }
33998
35097
  function safeEnd(span, endTime) {
33999
35098
  try {
34000
35099
  span.end(endTime === void 0 ? void 0 : { endTime });
34001
35100
  } catch (error) {
34002
- logInstrumentationError3("Flue span end", error);
35101
+ logInstrumentationError4("Flue span end", error);
34003
35102
  }
34004
35103
  }
34005
- function logInstrumentationError3(label, error) {
35104
+ function logInstrumentationError4(label, error) {
34006
35105
  debugLogger.debug(`Error in ${label} instrumentation:`, error);
34007
35106
  }
34008
35107
 
@@ -34570,10 +35669,10 @@ var LangSmithPlugin = class extends BasePlugin {
34570
35669
  const creates = ownValue(batch, "runCreates");
34571
35670
  if (Array.isArray(creates)) {
34572
35671
  const parentFirst = [...creates].sort((left, right) => {
34573
- const leftId = stringValue2(ownValue(left, "id"));
34574
- const rightId = stringValue2(ownValue(right, "id"));
34575
- const leftParent = stringValue2(ownValue(left, "parent_run_id"));
34576
- const rightParent = stringValue2(ownValue(right, "parent_run_id"));
35672
+ const leftId = stringValue3(ownValue(left, "id"));
35673
+ const rightId = stringValue3(ownValue(right, "id"));
35674
+ const leftParent = stringValue3(ownValue(left, "parent_run_id"));
35675
+ const rightParent = stringValue3(ownValue(right, "parent_run_id"));
34577
35676
  if (leftParent && leftParent === rightId) {
34578
35677
  return 1;
34579
35678
  }
@@ -34592,13 +35691,13 @@ var LangSmithPlugin = class extends BasePlugin {
34592
35691
  if (Array.isArray(updates)) {
34593
35692
  for (const run of updates) {
34594
35693
  this.containLifecycleFailure("batchIngestRuns update", () => {
34595
- this.processUpdate(stringValue2(ownValue(run, "id")) ?? "", run);
35694
+ this.processUpdate(stringValue3(ownValue(run, "id")) ?? "", run);
34596
35695
  });
34597
35696
  }
34598
35697
  }
34599
35698
  }
34600
35699
  processCreate(run) {
34601
- const id = stringValue2(ownValue(run, "id"));
35700
+ const id = stringValue3(ownValue(run, "id"));
34602
35701
  if (!id || this.completedRuns.get(id)) {
34603
35702
  return;
34604
35703
  }
@@ -34631,7 +35730,7 @@ var LangSmithPlugin = class extends BasePlugin {
34631
35730
  this.endIfComplete(id, activeRun, run);
34632
35731
  }
34633
35732
  processUpdate(explicitId, run) {
34634
- const id = stringValue2(explicitId) ?? stringValue2(ownValue(run, "id"));
35733
+ const id = stringValue3(explicitId) ?? stringValue3(ownValue(run, "id"));
34635
35734
  if (!id || this.completedRuns.get(id)) {
34636
35735
  return;
34637
35736
  }
@@ -34654,13 +35753,13 @@ var LangSmithPlugin = class extends BasePlugin {
34654
35753
  this.endIfComplete(id, active, active.run);
34655
35754
  }
34656
35755
  startRunSpan(id, run) {
34657
- const traceId = stringValue2(ownValue(run, "trace_id")) ?? id;
34658
- const parentId = stringValue2(ownValue(run, "parent_run_id")) ?? stringValue2(ownValue(ownValue(run, "parent_run"), "id"));
35756
+ const traceId = stringValue3(ownValue(run, "trace_id")) ?? id;
35757
+ const parentId = stringValue3(ownValue(run, "parent_run_id")) ?? stringValue3(ownValue(ownValue(run, "parent_run"), "id"));
34659
35758
  const startTime = timestampSeconds(ownValue(run, "start_time"));
34660
35759
  return startSpan(
34661
35760
  withSpanInstrumentationName(
34662
35761
  {
34663
- name: stringValue2(ownValue(run, "name")) ?? "LangSmith run",
35762
+ name: stringValue3(ownValue(run, "name")) ?? "LangSmith run",
34664
35763
  spanId: id,
34665
35764
  parentSpanIds: {
34666
35765
  parentSpanIds: parentId ? [parentId] : [],
@@ -34752,7 +35851,7 @@ function mergeRuns(previous, current) {
34752
35851
  function isRecord2(value) {
34753
35852
  return typeof value === "object" && value !== null && !Array.isArray(value);
34754
35853
  }
34755
- function stringValue2(value) {
35854
+ function stringValue3(value) {
34756
35855
  return typeof value === "string" && value.length > 0 ? value : void 0;
34757
35856
  }
34758
35857
  function timestampSeconds(value) {
@@ -34770,7 +35869,7 @@ function timestampSeconds(value) {
34770
35869
  return void 0;
34771
35870
  }
34772
35871
  function dottedOrderDepth(run) {
34773
- const dottedOrder = stringValue2(ownValue(run, "dotted_order"));
35872
+ const dottedOrder = stringValue3(ownValue(run, "dotted_order"));
34774
35873
  return dottedOrder ? dottedOrder.split(".").length : Number.MAX_SAFE_INTEGER;
34775
35874
  }
34776
35875
  function mapRunType(runType) {
@@ -34975,7 +36074,7 @@ var PiCodingAgentPlugin = class extends BasePlugin {
34975
36074
  }
34976
36075
  );
34977
36076
  } catch (error) {
34978
- logInstrumentationError4("Pi Coding Agent prompt start", error);
36077
+ logInstrumentationError5("Pi Coding Agent prompt start", error);
34979
36078
  }
34980
36079
  if (!state) {
34981
36080
  return runWithAutoInstrumentationSuppressed(invokeTarget);
@@ -35108,12 +36207,12 @@ function installPiAgentInstrumentation(agent) {
35108
36207
  () => handlePiAgentEvent(state, event)
35109
36208
  );
35110
36209
  } catch (error) {
35111
- logInstrumentationError4("Pi Coding Agent event", error);
36210
+ logInstrumentationError5("Pi Coding Agent event", error);
35112
36211
  }
35113
36212
  });
35114
36213
  piAgentEventSubscriptions.add(agent);
35115
36214
  } catch (error) {
35116
- logInstrumentationError4("Pi Coding Agent event subscription", error);
36215
+ logInstrumentationError5("Pi Coding Agent event subscription", error);
35117
36216
  }
35118
36217
  }
35119
36218
  function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
@@ -35163,7 +36262,7 @@ function wrapPiToolExecutors(tools) {
35163
36262
  });
35164
36263
  tool.execute = wrappedExecute;
35165
36264
  } catch (error) {
35166
- logInstrumentationError4("Pi Coding Agent tool wrapping", error);
36265
+ logInstrumentationError5("Pi Coding Agent tool wrapping", error);
35167
36266
  }
35168
36267
  }
35169
36268
  }
@@ -35242,7 +36341,7 @@ function patchAssistantMessageStream(stream, promptState, llmState) {
35242
36341
  try {
35243
36342
  await iterator.return();
35244
36343
  } catch (cleanupError) {
35245
- logInstrumentationError4(
36344
+ logInstrumentationError5(
35246
36345
  "Pi Coding Agent stream cleanup",
35247
36346
  cleanupError
35248
36347
  );
@@ -35407,7 +36506,7 @@ function finishPiPromptRun(state, error) {
35407
36506
  try {
35408
36507
  state.span.end();
35409
36508
  } catch (endError) {
35410
- logInstrumentationError4("Pi Coding Agent prompt end", endError);
36509
+ logInstrumentationError5("Pi Coding Agent prompt end", endError);
35411
36510
  }
35412
36511
  }
35413
36512
  }
@@ -35739,10 +36838,10 @@ function safeLog4(span, event) {
35739
36838
  try {
35740
36839
  span.log(event);
35741
36840
  } catch (error) {
35742
- logInstrumentationError4("Pi Coding Agent span log", error);
36841
+ logInstrumentationError5("Pi Coding Agent span log", error);
35743
36842
  }
35744
36843
  }
35745
- function logInstrumentationError4(context, error) {
36844
+ function logInstrumentationError5(context, error) {
35746
36845
  debugLogger.debug(`${context}:`, error);
35747
36846
  }
35748
36847
 
@@ -35980,7 +37079,7 @@ function handleAgentStreamEvent(state, event) {
35980
37079
  finalizeModelSpan(state, event);
35981
37080
  break;
35982
37081
  case "beforeToolCallEvent":
35983
- startToolSpan2(state, event);
37082
+ startToolSpan3(state, event);
35984
37083
  break;
35985
37084
  case "afterToolCallEvent":
35986
37085
  finalizeToolSpan(state, event);
@@ -36005,7 +37104,7 @@ function handleAgentStreamEvent(state, event) {
36005
37104
  break;
36006
37105
  }
36007
37106
  } catch (error) {
36008
- logInstrumentationError5("Strands Agent SDK event", error);
37107
+ logInstrumentationError6("Strands Agent SDK event", error);
36009
37108
  }
36010
37109
  }
36011
37110
  function handleMultiAgentStreamEvent(state, event, activeChildParents) {
@@ -36041,7 +37140,7 @@ function handleMultiAgentStreamEvent(state, event, activeChildParents) {
36041
37140
  break;
36042
37141
  }
36043
37142
  } catch (error) {
36044
- logInstrumentationError5("Strands Agent SDK multi-agent event", error);
37143
+ logInstrumentationError6("Strands Agent SDK multi-agent event", error);
36045
37144
  }
36046
37145
  }
36047
37146
  function buildModelSpanInput(event, attachmentCache) {
@@ -36120,7 +37219,7 @@ function finalizeModelSpan(state, event) {
36120
37219
  });
36121
37220
  modelState.span.end();
36122
37221
  }
36123
- function startToolSpan2(state, event) {
37222
+ function startToolSpan3(state, event) {
36124
37223
  const toolUse = event.toolUse;
36125
37224
  const key = toolKey2(toolUse);
36126
37225
  if (state.activeTools.has(key)) {
@@ -36400,7 +37499,7 @@ function getModelConfig(model) {
36400
37499
  try {
36401
37500
  return model.getConfig();
36402
37501
  } catch (error) {
36403
- logInstrumentationError5("Strands Agent SDK model config", error);
37502
+ logInstrumentationError6("Strands Agent SDK model config", error);
36404
37503
  return void 0;
36405
37504
  }
36406
37505
  }
@@ -36483,7 +37582,7 @@ function processStrandsInputAttachments(input, cache = createStrandsAttachmentCa
36483
37582
  try {
36484
37583
  return processStrandsInputNode(input, cache);
36485
37584
  } catch (error) {
36486
- logInstrumentationError5("Strands Agent SDK input attachments", error);
37585
+ logInstrumentationError6("Strands Agent SDK input attachments", error);
36487
37586
  return input;
36488
37587
  }
36489
37588
  }
@@ -36703,10 +37802,10 @@ function safeLog5(span, event) {
36703
37802
  try {
36704
37803
  span.log(event);
36705
37804
  } catch (error) {
36706
- logInstrumentationError5("Strands Agent SDK span log", error);
37805
+ logInstrumentationError6("Strands Agent SDK span log", error);
36707
37806
  }
36708
37807
  }
36709
- function logInstrumentationError5(context, error) {
37808
+ function logInstrumentationError6(context, error) {
36710
37809
  debugLogger.debug(`${context}:`, error);
36711
37810
  }
36712
37811
 
@@ -37109,10 +38208,10 @@ function observeAudioStream(value, observe, complete, cancel, span) {
37109
38208
  const getReader = value.getReader;
37110
38209
  value.getReader = function(...args) {
37111
38210
  const reader = Reflect.apply(getReader, this, args);
37112
- const read3 = reader.read;
38211
+ const read4 = reader.read;
37113
38212
  reader.read = function(...readArgs) {
37114
38213
  return Promise.resolve(
37115
- withCurrent(span, () => Reflect.apply(read3, this, readArgs))
38214
+ withCurrent(span, () => Reflect.apply(read4, this, readArgs))
37116
38215
  ).then(
37117
38216
  (result) => {
37118
38217
  if (result.value) safeObserve(result.value);
@@ -37629,14 +38728,14 @@ var CloudflareAIChatPlugin = class extends BasePlugin {
37629
38728
  const result = event.arguments[0];
37630
38729
  state = agent ? this.findResponseState(
37631
38730
  agent,
37632
- stringValue3(ownValue2(result, "requestId"))
38731
+ stringValue4(ownValue2(result, "requestId"))
37633
38732
  ) : void 0;
37634
38733
  if (!state) {
37635
38734
  return;
37636
38735
  }
37637
38736
  state.responseObserved = true;
37638
38737
  const output = serializeMessage(ownValue2(result, "message"));
37639
- const status = stringValue3(ownValue2(result, "status"));
38738
+ const status = stringValue4(ownValue2(result, "status"));
37640
38739
  const error = ownValue2(result, "error");
37641
38740
  const input = ownValue2(result, "continuation") === true ? state.input : serializeMessages(readProperty(agent, "messages"))?.filter(
37642
38741
  (message) => typeof output?.id !== "string" || message.id !== output.id
@@ -37683,7 +38782,7 @@ var CloudflareAIChatPlugin = class extends BasePlugin {
37683
38782
  }
37684
38783
  try {
37685
38784
  const agent = asObject(event.self);
37686
- const requestId = stringValue3(event.arguments[0]);
38785
+ const requestId = stringValue4(event.arguments[0]);
37687
38786
  const key = requestId ?? /* @__PURE__ */ Symbol("cloudflare-ai-chat-turn");
37688
38787
  const activeForAgent = agent ? this.getActiveTurns(agent) : void 0;
37689
38788
  const existing = activeForAgent?.get(key);
@@ -37852,7 +38951,7 @@ function ownValue2(value, key) {
37852
38951
  const descriptor = Object.getOwnPropertyDescriptor(object, key);
37853
38952
  return descriptor && "value" in descriptor ? descriptor.value : void 0;
37854
38953
  }
37855
- function stringValue3(value) {
38954
+ function stringValue4(value) {
37856
38955
  return typeof value === "string" ? value : void 0;
37857
38956
  }
37858
38957
  function serializeMessages(value) {
@@ -37970,7 +39069,7 @@ var CloudflareAgentsPlugin = class extends BasePlugin {
37970
39069
  );
37971
39070
  spans.set(event, span);
37972
39071
  } catch (error) {
37973
- logInstrumentationError6("start", error);
39072
+ logInstrumentationError7("start", error);
37974
39073
  }
37975
39074
  },
37976
39075
  asyncEnd: (event) => {
@@ -37990,7 +39089,7 @@ var CloudflareAgentsPlugin = class extends BasePlugin {
37990
39089
  }
37991
39090
  }
37992
39091
  } catch (error) {
37993
- logInstrumentationError6("completion", error);
39092
+ logInstrumentationError7("completion", error);
37994
39093
  } finally {
37995
39094
  safelyEndSpan(span);
37996
39095
  }
@@ -38004,7 +39103,7 @@ var CloudflareAgentsPlugin = class extends BasePlugin {
38004
39103
  try {
38005
39104
  span.log({ error: event.error });
38006
39105
  } catch (error) {
38007
- logInstrumentationError6("rejection", error);
39106
+ logInstrumentationError7("rejection", error);
38008
39107
  } finally {
38009
39108
  safelyEndSpan(span);
38010
39109
  }
@@ -38034,10 +39133,10 @@ function safelyEndSpan(span) {
38034
39133
  try {
38035
39134
  span.end();
38036
39135
  } catch (error) {
38037
- logInstrumentationError6("span end", error);
39136
+ logInstrumentationError7("span end", error);
38038
39137
  }
38039
39138
  }
38040
- function logInstrumentationError6(operation, error) {
39139
+ function logInstrumentationError7(operation, error) {
38041
39140
  debugLogger.error(
38042
39141
  `Failed to process Cloudflare Agents ${operation} instrumentation:`,
38043
39142
  error
@@ -38062,6 +39161,7 @@ var BraintrustPlugin = class extends BasePlugin {
38062
39161
  openRouterPlugin = null;
38063
39162
  openRouterAgentPlugin = null;
38064
39163
  mistralPlugin = null;
39164
+ langGraphSDKPlugin = null;
38065
39165
  ollamaPlugin = null;
38066
39166
  googleADKPlugin = null;
38067
39167
  coherePlugin = null;
@@ -38142,6 +39242,10 @@ var BraintrustPlugin = class extends BasePlugin {
38142
39242
  this.mistralPlugin = new MistralPlugin();
38143
39243
  this.mistralPlugin.enable();
38144
39244
  }
39245
+ if (integrations.langgraphSDK !== false) {
39246
+ this.langGraphSDKPlugin = new LangGraphSDKPlugin();
39247
+ this.langGraphSDKPlugin.enable();
39248
+ }
38145
39249
  if (integrations.ollama !== false) {
38146
39250
  this.ollamaPlugin = new OllamaPlugin();
38147
39251
  this.ollamaPlugin.enable();
@@ -38270,6 +39374,10 @@ var BraintrustPlugin = class extends BasePlugin {
38270
39374
  this.mistralPlugin.disable();
38271
39375
  this.mistralPlugin = null;
38272
39376
  }
39377
+ if (this.langGraphSDKPlugin) {
39378
+ this.langGraphSDKPlugin.disable();
39379
+ this.langGraphSDKPlugin = null;
39380
+ }
38273
39381
  if (this.ollamaPlugin) {
38274
39382
  this.ollamaPlugin.disable();
38275
39383
  this.ollamaPlugin = null;
@@ -38411,6 +39519,9 @@ var envIntegrationAliases = {
38411
39519
  "langchain-js": "langchain",
38412
39520
  "@langchain": "langchain",
38413
39521
  langgraph: "langgraph",
39522
+ langgraphsdk: "langgraphSDK",
39523
+ "langgraph-sdk": "langgraphSDK",
39524
+ "@langchain/langgraph-sdk": "langgraphSDK",
38414
39525
  langsmith: "langsmith",
38415
39526
  voyage: "voyageai",
38416
39527
  "voyage-ai": "voyageai",
@@ -38451,6 +39562,7 @@ function getDefaultInstrumentationIntegrations() {
38451
39562
  gitHubCopilot: true,
38452
39563
  langchain: true,
38453
39564
  langgraph: true,
39565
+ langgraphSDK: true,
38454
39566
  langsmith: true,
38455
39567
  voyageai: true,
38456
39568
  elevenlabs: true,
@@ -38617,8 +39729,6 @@ __export(exports_exports, {
38617
39729
  BRAINTRUST_PARENT_KEY: () => BRAINTRUST_PARENT_KEY,
38618
39730
  BaseAttachment: () => BaseAttachment,
38619
39731
  BaseExperiment: () => BaseExperiment,
38620
- BatchScorer: () => BatchScorer,
38621
- BatchTask: () => BatchTask,
38622
39732
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
38623
39733
  BraintrustMiddleware: () => BraintrustMiddleware,
38624
39734
  BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
@@ -38632,8 +39742,6 @@ __export(exports_exports, {
38632
39742
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
38633
39743
  Dataset: () => Dataset2,
38634
39744
  DatasetPipeline: () => DatasetPipeline,
38635
- DurableEvalMemoryStore: () => DurableEvalMemoryStore,
38636
- DurableEvalRedisStore: () => DurableEvalRedisStore,
38637
39745
  ERR_PERMALINK: () => ERR_PERMALINK,
38638
39746
  Eval: () => Eval,
38639
39747
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -38668,6 +39776,10 @@ __export(exports_exports, {
38668
39776
  TestBackgroundLogger: () => TestBackgroundLogger,
38669
39777
  ToolBuilder: () => ToolBuilder,
38670
39778
  UUIDGenerator: () => UUIDGenerator,
39779
+ WorkflowEvalMemoryStore: () => WorkflowEvalMemoryStore,
39780
+ WorkflowEvalRedisStore: () => WorkflowEvalRedisStore,
39781
+ WorkflowScorer: () => WorkflowScorer,
39782
+ WorkflowTask: () => WorkflowTask,
38671
39783
  X_CACHED_HEADER: () => X_CACHED_HEADER,
38672
39784
  _exportsForTestingOnly: () => _exportsForTestingOnly,
38673
39785
  _internalGetGlobalState: () => _internalGetGlobalState,
@@ -38692,12 +39804,13 @@ __export(exports_exports, {
38692
39804
  currentSpan: () => currentSpan,
38693
39805
  deepCopyEvent: () => deepCopyEvent,
38694
39806
  defaultErrorScoreHandler: () => defaultErrorScoreHandler,
38695
- defineDurableEval: () => defineDurableEval,
39807
+ defineWorkflowEval: () => defineWorkflowEval,
38696
39808
  deserializePlainStringAsJSON: () => deserializePlainStringAsJSON,
38697
39809
  devNullWritableStream: () => devNullWritableStream,
38698
39810
  evaluatorDefinitionSchema: () => evaluatorDefinitionSchema,
38699
39811
  evaluatorDefinitionsSchema: () => evaluatorDefinitionsSchema,
38700
39812
  extractTraceContextFromHeaders: () => extractTraceContextFromHeaders,
39813
+ failOpenAIAgentsTrace: () => failOpenAIAgentsTrace,
38701
39814
  flush: () => flush,
38702
39815
  getContextManager: () => getContextManager,
38703
39816
  getIdGenerator: () => getIdGenerator,
@@ -38744,12 +39857,14 @@ __export(exports_exports, {
38744
39857
  setFetch: () => setFetch,
38745
39858
  setMaskingFunction: () => setMaskingFunction,
38746
39859
  spanComponentsToObjectId: () => spanComponentsToObjectId,
39860
+ startOpenAIAgentsTrace: () => startOpenAIAgentsTrace,
38747
39861
  startSpan: () => startSpan,
38748
39862
  summarize: () => summarize,
38749
39863
  templateRegistry: () => templateRegistry,
38750
39864
  toolFunctionDefinitionSchema: () => ToolFunctionDefinition,
38751
39865
  traceable: () => traceable,
38752
39866
  traced: () => traced,
39867
+ updateOpenAIAgentsTrace: () => updateOpenAIAgentsTrace,
38753
39868
  updateSpan: () => updateSpan,
38754
39869
  uploadLogs3OverflowPayload: () => uploadLogs3OverflowPayload,
38755
39870
  utf8ByteLength: () => utf8ByteLength2,
@@ -38778,6 +39893,7 @@ __export(exports_exports, {
38778
39893
  wrapGroq: () => wrapGroq,
38779
39894
  wrapHuggingFace: () => wrapHuggingFace,
38780
39895
  wrapHuggingFaceTransformers: () => wrapHuggingFaceTransformers,
39896
+ wrapLangGraphSDK: () => wrapLangGraphSDK,
38781
39897
  wrapLangSmithClient: () => wrapLangSmithClient,
38782
39898
  wrapLangSmithRunTrees: () => wrapLangSmithRunTrees,
38783
39899
  wrapLangSmithTraceable: () => wrapLangSmithTraceable,
@@ -38977,7 +40093,7 @@ function createLazyAPIPromise(ensureExecuted, ensureResponse, getAPIPromise) {
38977
40093
  }
38978
40094
 
38979
40095
  // src/openai-batch.ts
38980
- function read2(value, key) {
40096
+ function read3(value, key) {
38981
40097
  if (value === null || typeof value !== "object" && typeof value !== "function") {
38982
40098
  return void 0;
38983
40099
  }
@@ -38988,7 +40104,7 @@ function read2(value, key) {
38988
40104
  }
38989
40105
  }
38990
40106
  function isAsyncIterable5(value) {
38991
- return typeof read2(value, Symbol.asyncIterator) === "function";
40107
+ return typeof read3(value, Symbol.asyncIterator) === "function";
38992
40108
  }
38993
40109
  function teeAsyncIterable(source) {
38994
40110
  const iterator = source[Symbol.asyncIterator]();
@@ -39031,7 +40147,7 @@ function teeAsyncIterable(source) {
39031
40147
  }
39032
40148
  }
39033
40149
  };
39034
- const path = read2(source, "path");
40150
+ const path = read3(source, "path");
39035
40151
  if (typeof path === "string") {
39036
40152
  Object.defineProperty(upload, "path", { value: path });
39037
40153
  }
@@ -39052,8 +40168,8 @@ function teeUpload(upload) {
39052
40168
  function openaiFilesCreateTraced(files) {
39053
40169
  return (params, options) => {
39054
40170
  const parent = getSpanParentObject();
39055
- const purpose = read2(params, "purpose");
39056
- const file = read2(params, "file");
40171
+ const purpose = read3(params, "purpose");
40172
+ const file = read3(params, "file");
39057
40173
  if (purpose !== "batch") {
39058
40174
  return files.create(params, options);
39059
40175
  }
@@ -39144,6 +40260,143 @@ async function completeOpenAIBatchTrace(args) {
39144
40260
  );
39145
40261
  }
39146
40262
 
40263
+ // src/openai-agents-api.ts
40264
+ function isRecord3(value) {
40265
+ return typeof value === "object" && value !== null && !Array.isArray(value);
40266
+ }
40267
+ function validateStartArgs(value) {
40268
+ if (!isRecord3(value)) {
40269
+ throw new TypeError(
40270
+ "startOpenAIAgentsTrace expected an OpenAI Agents parameters object"
40271
+ );
40272
+ }
40273
+ const agent = value.agent;
40274
+ if (agent !== void 0 && agent !== null && !isRecord3(agent)) {
40275
+ throw new TypeError(
40276
+ "startOpenAIAgentsTrace expected agent to be an object or null"
40277
+ );
40278
+ }
40279
+ 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")) {
40280
+ throw new TypeError(
40281
+ "startOpenAIAgentsTrace received invalid agent identity fields"
40282
+ );
40283
+ }
40284
+ if (value.agent_id !== void 0 && typeof value.agent_id !== "string") {
40285
+ throw new TypeError(
40286
+ "startOpenAIAgentsTrace expected agent_id to be a string"
40287
+ );
40288
+ }
40289
+ if (value.metadata !== void 0 && value.metadata !== null && !isRecord3(value.metadata)) {
40290
+ throw new TypeError(
40291
+ "startOpenAIAgentsTrace expected metadata to be an object or null"
40292
+ );
40293
+ }
40294
+ return value;
40295
+ }
40296
+ function validateEvent(event) {
40297
+ if (!isRecord3(event) || typeof event.type !== "string" || event.type.length === 0) {
40298
+ throw new TypeError(
40299
+ "updateOpenAIAgentsTrace expected an OpenAI Agents event object"
40300
+ );
40301
+ }
40302
+ return event;
40303
+ }
40304
+ function createTraceState() {
40305
+ const parent = _internalExportParentSynchronously(getSpanParentObject());
40306
+ if (!parent) {
40307
+ return null;
40308
+ }
40309
+ const parentComponents = SpanComponentsV4.fromStr(parent);
40310
+ const rowId = newId();
40311
+ const useLegacyIds = resolveUseLegacyUuidIds();
40312
+ const spanId = useLegacyIds ? newId() : newId().replaceAll("-", "").slice(0, 16);
40313
+ const rootSpanId = useLegacyIds ? spanId : newId().replaceAll("-", "");
40314
+ const root = new SpanComponentsV4({
40315
+ object_type: parentComponents.data.object_type,
40316
+ ...parentComponents.data.object_id ? { object_id: parentComponents.data.object_id } : {
40317
+ compute_object_metadata_args: parentComponents.data.compute_object_metadata_args ?? {}
40318
+ },
40319
+ propagated_event: parentComponents.data.propagated_event,
40320
+ root_span_id: rootSpanId,
40321
+ row_id: rowId,
40322
+ span_id: spanId
40323
+ }).toStr();
40324
+ return {
40325
+ callItems: {},
40326
+ ended: false,
40327
+ eventIds: [],
40328
+ openTools: {},
40329
+ root,
40330
+ rootKey: spanId,
40331
+ rootParent: parent,
40332
+ startTime: getCurrentUnixTimestamp(),
40333
+ subagents: {},
40334
+ turnSubagents: {},
40335
+ version: 1
40336
+ };
40337
+ }
40338
+ function startOpenAIAgentsTrace(args) {
40339
+ const validatedArgs = validateStartArgs(args);
40340
+ const state = createTraceState();
40341
+ if (!state) {
40342
+ return null;
40343
+ }
40344
+ try {
40345
+ void openAIChannels.agentsTraceStart.invoke(
40346
+ async () => state,
40347
+ void 0,
40348
+ [{ args: validatedArgs, state }],
40349
+ {}
40350
+ ).catch((error) => {
40351
+ debugLogger.debug(
40352
+ "OpenAI Agents API instrumentation could not start:",
40353
+ error
40354
+ );
40355
+ });
40356
+ } catch (error) {
40357
+ debugLogger.debug(
40358
+ "OpenAI Agents API instrumentation could not start:",
40359
+ error
40360
+ );
40361
+ }
40362
+ return state;
40363
+ }
40364
+ async function updateOpenAIAgentsTrace(token, event) {
40365
+ const state = token;
40366
+ const validatedEvent = validateEvent(event);
40367
+ try {
40368
+ return await openAIChannels.agentsTraceCapture.invoke(
40369
+ async () => state,
40370
+ void 0,
40371
+ [{ state, event: validatedEvent }],
40372
+ {}
40373
+ );
40374
+ } catch (error) {
40375
+ debugLogger.debug(
40376
+ "OpenAI Agents API instrumentation could not update:",
40377
+ error
40378
+ );
40379
+ return token;
40380
+ }
40381
+ }
40382
+ async function failOpenAIAgentsTrace(token, error) {
40383
+ const state = token;
40384
+ try {
40385
+ return await openAIChannels.agentsTraceFail.invoke(
40386
+ async () => state,
40387
+ void 0,
40388
+ [{ state, error }],
40389
+ {}
40390
+ );
40391
+ } catch (instrumentationError) {
40392
+ debugLogger.debug(
40393
+ "OpenAI Agents API instrumentation could not record failure:",
40394
+ instrumentationError
40395
+ );
40396
+ return token;
40397
+ }
40398
+ }
40399
+
39147
40400
  // src/functions/invoke.ts
39148
40401
  async function invoke(args) {
39149
40402
  const {
@@ -40593,7 +41846,31 @@ var MAX_STORED_LLM_INPUTS = 100;
40593
41846
  var MAX_STORED_REASONING_BLOCKS = 100;
40594
41847
  var MAX_STORED_SPAN_REFERENCES = 1e4;
40595
41848
  var MAX_STORED_STEP_STARTS = 1e4;
41849
+ var EVE_HANDLED_EVENT_TYPES = /* @__PURE__ */ new Set([
41850
+ "action.result",
41851
+ "actions.requested",
41852
+ "message.completed",
41853
+ "message.received",
41854
+ "reasoning.completed",
41855
+ "result.completed",
41856
+ "session.completed",
41857
+ "session.failed",
41858
+ "session.started",
41859
+ "step.completed",
41860
+ "step.failed",
41861
+ "step.started",
41862
+ "subagent.called",
41863
+ "subagent.completed",
41864
+ "turn.completed",
41865
+ "turn.failed",
41866
+ "turn.started"
41867
+ ]);
40596
41868
  function braintrustEveHook(options) {
41869
+ if (!options || typeof options.defineState !== "function") {
41870
+ throw new TypeError(
41871
+ "braintrustEveHook requires Eve's defineState function"
41872
+ );
41873
+ }
40597
41874
  const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
40598
41875
  const bridge = new EveBridge(state);
40599
41876
  return {
@@ -40605,15 +41882,27 @@ function braintrustEveHook(options) {
40605
41882
  };
40606
41883
  }
40607
41884
  function createLegacyEveInstrumentation(options) {
41885
+ if (!options || typeof options.defineState !== "function") {
41886
+ throw new TypeError(
41887
+ "braintrustEveInstrumentation requires Eve's defineState function"
41888
+ );
41889
+ }
40608
41890
  const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
40609
41891
  return {
40610
41892
  events: {
40611
41893
  "step.started": (input) => {
40612
41894
  try {
41895
+ if (!isEveInstrumentationStepStartedEventInput(input)) {
41896
+ debugLogger.warn(
41897
+ "Ignoring malformed Eve instrumentation step.started event"
41898
+ );
41899
+ return void 0;
41900
+ }
40613
41901
  captureEveModelInput(state, input);
40614
41902
  } catch (error) {
40615
41903
  debugLogger.warn("Error in Eve LLM input capture:", error);
40616
41904
  }
41905
+ return void 0;
40617
41906
  }
40618
41907
  },
40619
41908
  recordInputs: false,
@@ -40622,7 +41911,77 @@ function createLegacyEveInstrumentation(options) {
40622
41911
  };
40623
41912
  }
40624
41913
  function isEveHandleMessageStreamEvent(event) {
40625
- return isObject(event) && typeof event["type"] === "string";
41914
+ if (!isObject(event) || typeof event["type"] !== "string") {
41915
+ return false;
41916
+ }
41917
+ const type = event["type"];
41918
+ if (type === "session.completed") {
41919
+ return true;
41920
+ }
41921
+ if (!isObject(event["data"])) {
41922
+ return false;
41923
+ }
41924
+ const data = event["data"];
41925
+ if (type === "session.started") {
41926
+ return true;
41927
+ }
41928
+ if (type === "session.failed") {
41929
+ return typeof data["sessionId"] === "string" && typeof data["code"] === "string" && typeof data["message"] === "string";
41930
+ }
41931
+ if (type === "session.waiting") {
41932
+ return data["wait"] === "next-user-message";
41933
+ }
41934
+ if (typeof data["turnId"] !== "string" || typeof data["sequence"] !== "number" || !Number.isFinite(data["sequence"])) {
41935
+ return false;
41936
+ }
41937
+ if (type === "turn.started" || type === "turn.completed" || type === "subagent.called" || type === "subagent.completed") {
41938
+ if (type === "subagent.called") {
41939
+ return typeof data["callId"] === "string" && typeof data["childSessionId"] === "string" && typeof data["name"] === "string";
41940
+ }
41941
+ if (type === "subagent.completed") {
41942
+ return typeof data["callId"] === "string" && typeof data["subagentName"] === "string";
41943
+ }
41944
+ return true;
41945
+ }
41946
+ if (type === "turn.failed") {
41947
+ return typeof data["code"] === "string" && typeof data["message"] === "string";
41948
+ }
41949
+ if (type === "message.received") {
41950
+ return typeof data["message"] === "string";
41951
+ }
41952
+ if (typeof data["stepIndex"] !== "number" || !Number.isFinite(data["stepIndex"]) || data["stepIndex"] < 0) {
41953
+ return false;
41954
+ }
41955
+ switch (type) {
41956
+ case "step.started":
41957
+ return true;
41958
+ case "message.completed":
41959
+ return typeof data["finishReason"] === "string" && (typeof data["message"] === "string" || data["message"] === null);
41960
+ case "reasoning.completed":
41961
+ return typeof data["reasoning"] === "string";
41962
+ case "result.completed":
41963
+ return true;
41964
+ case "step.completed":
41965
+ return typeof data["finishReason"] === "string";
41966
+ case "step.failed":
41967
+ return typeof data["code"] === "string" && typeof data["message"] === "string";
41968
+ case "actions.requested":
41969
+ return Array.isArray(data["actions"]);
41970
+ case "action.result":
41971
+ return isObject(data["result"]) && (data["status"] === "completed" || data["status"] === "failed" || data["status"] === "rejected");
41972
+ default:
41973
+ return false;
41974
+ }
41975
+ }
41976
+ function isEveInstrumentationStepStartedEventInput(input) {
41977
+ if (!isObject(input)) {
41978
+ return false;
41979
+ }
41980
+ const modelInput = input["modelInput"];
41981
+ const session = input["session"];
41982
+ const step = input["step"];
41983
+ const turn = input["turn"];
41984
+ 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"]);
40626
41985
  }
40627
41986
  var ResumedEveSpan = class {
40628
41987
  constructor(reference) {
@@ -40791,7 +42150,17 @@ var EveBridge = class {
40791
42150
  });
40792
42151
  }
40793
42152
  async handle(event, ctx, hookMetadata) {
42153
+ try {
42154
+ await this.handleUnchecked(event, ctx, hookMetadata);
42155
+ } catch (error) {
42156
+ debugLogger.warn("Error in Eve hook instrumentation:", error);
42157
+ }
42158
+ }
42159
+ async handleUnchecked(event, ctx, hookMetadata) {
40794
42160
  if (!isEveHandleMessageStreamEvent(event)) {
42161
+ if (isObject(event) && typeof event["type"] === "string" && EVE_HANDLED_EVENT_TYPES.has(event["type"])) {
42162
+ debugLogger.warn(`Ignoring malformed Eve hook ${event["type"]} event`);
42163
+ }
40795
42164
  return;
40796
42165
  }
40797
42166
  const run = async () => {
@@ -41117,9 +42486,14 @@ var EveBridge = class {
41117
42486
  }
41118
42487
  for (const action of traceActions) {
41119
42488
  const name = action.kind === "tool-call" ? action.toolName : action.subagentName ?? action.name ?? "agent";
42489
+ let args = "null";
42490
+ try {
42491
+ args = JSON.stringify(action.input) ?? "null";
42492
+ } catch {
42493
+ }
41120
42494
  toolCallsById.set(action.callId, {
41121
42495
  function: {
41122
- arguments: JSON.stringify(action.input),
42496
+ arguments: args,
41123
42497
  name
41124
42498
  },
41125
42499
  id: action.callId,
@@ -41988,17 +43362,33 @@ function consumeCapturedEveModelInput(state, sessionId, turnId, stepIndex) {
41988
43362
  }
41989
43363
  }
41990
43364
  function capturedModelInput(modelInput) {
41991
- const { instructions, messages } = modelInput;
41992
- const value = [];
41993
- if (typeof instructions === "string") {
41994
- value.push({ content: instructions, role: "system" });
41995
- } else if (Array.isArray(instructions)) {
41996
- value.push(...instructions.map(capturedEveModelMessage));
41997
- } else if (instructions) {
41998
- value.push(capturedEveModelMessage(instructions));
41999
- }
42000
- value.push(...messages.map(capturedEveModelMessage));
42001
43365
  try {
43366
+ if (!isObject(modelInput) || !Array.isArray(modelInput["messages"])) {
43367
+ return void 0;
43368
+ }
43369
+ const value = [];
43370
+ const instructions = modelInput["instructions"];
43371
+ if (typeof instructions === "string") {
43372
+ value.push({ content: instructions, role: "system" });
43373
+ } else if (Array.isArray(instructions)) {
43374
+ for (const instruction of instructions) {
43375
+ const captured = capturedEveModelMessage(instruction);
43376
+ if (captured?.role === "system") {
43377
+ value.push(captured);
43378
+ }
43379
+ }
43380
+ } else {
43381
+ const captured = capturedEveModelMessage(instructions);
43382
+ if (captured?.role === "system") {
43383
+ value.push(captured);
43384
+ }
43385
+ }
43386
+ for (const message of modelInput["messages"]) {
43387
+ const captured = capturedEveModelMessage(message);
43388
+ if (captured) {
43389
+ value.push(captured);
43390
+ }
43391
+ }
42002
43392
  const cloned = JSON.parse(JSON.stringify(value));
42003
43393
  if (!Array.isArray(cloned)) {
42004
43394
  return void 0;
@@ -42009,116 +43399,202 @@ function capturedModelInput(modelInput) {
42009
43399
  }
42010
43400
  }
42011
43401
  function capturedEveModelMessage(message) {
42012
- const { content, role } = message;
43402
+ if (!isObject(message)) {
43403
+ return void 0;
43404
+ }
43405
+ const role = message["role"];
43406
+ if (role !== "system" && role !== "user" && role !== "assistant" && role !== "tool") {
43407
+ return void 0;
43408
+ }
43409
+ const content = message["content"];
42013
43410
  if (typeof content === "string") {
42014
43411
  return { content, role };
42015
43412
  }
42016
- return { content: content.map(capturedEveModelContentPart), role };
43413
+ if (!Array.isArray(content)) {
43414
+ return void 0;
43415
+ }
43416
+ const capturedContent = [];
43417
+ for (const part of content) {
43418
+ const captured = capturedEveModelContentPart(part);
43419
+ if (captured) {
43420
+ capturedContent.push(captured);
43421
+ }
43422
+ }
43423
+ return { content: capturedContent, role };
42017
43424
  }
42018
43425
  function capturedEveModelContentPart(part) {
42019
- switch (part.type) {
43426
+ if (!isObject(part) || typeof part["type"] !== "string") {
43427
+ return void 0;
43428
+ }
43429
+ switch (part["type"]) {
42020
43430
  case "text":
42021
- case "reasoning":
42022
- return { text: part.text, type: part.type };
43431
+ case "reasoning": {
43432
+ const text = part["text"];
43433
+ return typeof text === "string" ? { text, type: part["type"] } : void 0;
43434
+ }
42023
43435
  case "image":
43436
+ if (!Object.hasOwn(part, "image")) {
43437
+ return void 0;
43438
+ }
42024
43439
  return {
42025
- image: part.image,
42026
- ...part.mediaType !== void 0 ? { mediaType: part.mediaType } : {},
43440
+ image: part["image"],
43441
+ ...typeof part["mediaType"] === "string" ? { mediaType: part["mediaType"] } : {},
42027
43442
  type: "image"
42028
43443
  };
42029
43444
  case "file":
42030
- case "reasoning-file":
43445
+ case "reasoning-file": {
43446
+ if (!Object.hasOwn(part, "data") || typeof part["mediaType"] !== "string") {
43447
+ return void 0;
43448
+ }
42031
43449
  return {
42032
- data: part.data,
42033
- ...part.type === "file" && part.filename !== void 0 ? { filename: part.filename } : {},
42034
- mediaType: part.mediaType,
42035
- type: part.type
43450
+ data: part["data"],
43451
+ ...part["type"] === "file" && typeof part["filename"] === "string" ? { filename: part["filename"] } : {},
43452
+ mediaType: part["mediaType"],
43453
+ type: part["type"]
42036
43454
  };
43455
+ }
42037
43456
  case "custom":
42038
43457
  return {
42039
- ..."kind" in part ? { kind: part.kind } : {},
43458
+ ...typeof part["kind"] === "string" ? { kind: part["kind"] } : {},
42040
43459
  type: "custom"
42041
43460
  };
42042
- case "tool-call":
43461
+ case "tool-call": {
43462
+ if (typeof part["toolCallId"] !== "string" || typeof part["toolName"] !== "string") {
43463
+ return void 0;
43464
+ }
42043
43465
  return {
42044
- input: part.input,
42045
- ...part.providerExecuted !== void 0 ? { providerExecuted: part.providerExecuted } : {},
42046
- toolCallId: part.toolCallId,
42047
- toolName: part.toolName,
43466
+ input: part["input"],
43467
+ ...typeof part["providerExecuted"] === "boolean" ? { providerExecuted: part["providerExecuted"] } : {},
43468
+ toolCallId: part["toolCallId"],
43469
+ toolName: part["toolName"],
42048
43470
  type: "tool-call"
42049
43471
  };
43472
+ }
42050
43473
  case "tool-result": {
42051
- const output = part.output;
43474
+ const output = part["output"];
43475
+ if (typeof part["toolCallId"] !== "string" || typeof part["toolName"] !== "string" || !isObject(output) || typeof output["type"] !== "string") {
43476
+ return void 0;
43477
+ }
42052
43478
  let capturedOutput;
42053
- switch (output.type) {
43479
+ switch (output["type"]) {
42054
43480
  case "text":
42055
- case "error-text":
42056
- capturedOutput = { type: output.type, value: output.value };
43481
+ case "error-text": {
43482
+ if (typeof output["value"] !== "string") {
43483
+ return void 0;
43484
+ }
43485
+ capturedOutput = {
43486
+ type: output["type"],
43487
+ value: output["value"]
43488
+ };
42057
43489
  break;
43490
+ }
42058
43491
  case "json":
42059
43492
  case "error-json":
42060
- capturedOutput = { type: output.type, value: output.value };
43493
+ capturedOutput = {
43494
+ type: output["type"],
43495
+ value: output["value"]
43496
+ };
42061
43497
  break;
42062
43498
  case "execution-denied":
42063
43499
  capturedOutput = {
42064
- ...output.reason !== void 0 ? { reason: output.reason } : {},
43500
+ ...typeof output["reason"] === "string" ? { reason: output["reason"] } : {},
42065
43501
  type: "execution-denied"
42066
43502
  };
42067
43503
  break;
42068
- case "content":
43504
+ case "content": {
43505
+ if (!Array.isArray(output["value"])) {
43506
+ return void 0;
43507
+ }
43508
+ const value = [];
43509
+ for (const outputPart of output["value"]) {
43510
+ const captured = capturedEveModelContentPart(outputPart);
43511
+ if (captured) {
43512
+ value.push(captured);
43513
+ }
43514
+ }
42069
43515
  capturedOutput = {
42070
43516
  type: "content",
42071
- value: output.value.map(capturedEveModelContentPart)
43517
+ value
42072
43518
  };
42073
43519
  break;
43520
+ }
43521
+ default:
43522
+ return void 0;
42074
43523
  }
42075
43524
  return {
42076
43525
  output: capturedOutput,
42077
- toolCallId: part.toolCallId,
42078
- toolName: part.toolName,
43526
+ toolCallId: part["toolCallId"],
43527
+ toolName: part["toolName"],
42079
43528
  type: "tool-result"
42080
43529
  };
42081
43530
  }
42082
- case "tool-approval-request":
43531
+ case "tool-approval-request": {
43532
+ if (typeof part["approvalId"] !== "string" || typeof part["toolCallId"] !== "string") {
43533
+ return void 0;
43534
+ }
42083
43535
  return {
42084
- approvalId: part.approvalId,
42085
- ...part.isAutomatic !== void 0 ? { isAutomatic: part.isAutomatic } : {},
42086
- ...part.signature !== void 0 ? { signature: part.signature } : {},
42087
- toolCallId: part.toolCallId,
43536
+ approvalId: part["approvalId"],
43537
+ ...typeof part["isAutomatic"] === "boolean" ? { isAutomatic: part["isAutomatic"] } : {},
43538
+ ...typeof part["signature"] === "string" ? { signature: part["signature"] } : {},
43539
+ toolCallId: part["toolCallId"],
42088
43540
  type: "tool-approval-request"
42089
43541
  };
42090
- case "tool-approval-response":
43542
+ }
43543
+ case "tool-approval-response": {
43544
+ if (typeof part["approvalId"] !== "string" || typeof part["approved"] !== "boolean") {
43545
+ return void 0;
43546
+ }
42091
43547
  return {
42092
- approvalId: part.approvalId,
42093
- approved: part.approved,
42094
- ...part.providerExecuted !== void 0 ? { providerExecuted: part.providerExecuted } : {},
42095
- ...part.reason !== void 0 ? { reason: part.reason } : {},
43548
+ approvalId: part["approvalId"],
43549
+ approved: part["approved"],
43550
+ ...typeof part["providerExecuted"] === "boolean" ? { providerExecuted: part["providerExecuted"] } : {},
43551
+ ...typeof part["reason"] === "string" ? { reason: part["reason"] } : {},
42096
43552
  type: "tool-approval-response"
42097
43553
  };
43554
+ }
42098
43555
  case "file-data":
42099
- case "image-data":
43556
+ case "image-data": {
43557
+ if (typeof part["data"] !== "string" || typeof part["mediaType"] !== "string") {
43558
+ return void 0;
43559
+ }
42100
43560
  return {
42101
- data: part.data,
42102
- ...part.type === "file-data" && part.filename !== void 0 ? { filename: part.filename } : {},
42103
- mediaType: part.mediaType,
42104
- type: part.type
43561
+ data: part["data"],
43562
+ ...part["type"] === "file-data" && typeof part["filename"] === "string" ? { filename: part["filename"] } : {},
43563
+ mediaType: part["mediaType"],
43564
+ type: part["type"]
42105
43565
  };
43566
+ }
42106
43567
  case "file-url":
42107
- case "image-url":
43568
+ case "image-url": {
43569
+ if (typeof part["url"] !== "string") {
43570
+ return void 0;
43571
+ }
42108
43572
  return {
42109
- ...part.type === "file-url" && part.mediaType !== void 0 ? { mediaType: part.mediaType } : {},
42110
- type: part.type,
42111
- url: part.url
43573
+ ...part["type"] === "file-url" && typeof part["mediaType"] === "string" ? { mediaType: part["mediaType"] } : {},
43574
+ type: part["type"],
43575
+ url: part["url"]
42112
43576
  };
43577
+ }
42113
43578
  case "file-id":
42114
- case "image-file-id":
42115
- return { fileId: part.fileId, type: part.type };
43579
+ case "image-file-id": {
43580
+ const fileId = part["fileId"];
43581
+ if (typeof fileId !== "string" && !isObject(fileId)) {
43582
+ return void 0;
43583
+ }
43584
+ return { fileId, type: part["type"] };
43585
+ }
42116
43586
  case "file-reference":
42117
- case "image-file-reference":
43587
+ case "image-file-reference": {
43588
+ if (!isObject(part["providerReference"])) {
43589
+ return void 0;
43590
+ }
42118
43591
  return {
42119
- providerReference: part.providerReference,
42120
- type: part.type
43592
+ providerReference: part["providerReference"],
43593
+ type: part["type"]
42121
43594
  };
43595
+ }
43596
+ default:
43597
+ return void 0;
42122
43598
  }
42123
43599
  }
42124
43600
  function isCapturedModelInput(input) {
@@ -42254,18 +43730,54 @@ function createEveInstrumentationProvider(options = {}) {
42254
43730
  recordOutputs: true
42255
43731
  }),
42256
43732
  events: {
42257
- "action.completed": (event, context) => bridge.handleActionTerminal(event, context),
42258
- "action.failed": (event, context) => bridge.handleActionTerminal(event, context),
42259
- "action.started": (event, context) => bridge.handleActionStarted(event, context),
42260
- "model.call.completed": (event, context) => bridge.handleModelTerminal(event, context),
42261
- "model.call.failed": (event, context) => bridge.handleModelTerminal(event, context),
42262
- "model.call.started": (event, context) => bridge.handleModelStarted(event, context),
42263
- "step.attempt.completed": (event) => bridge.handleStepAttemptTerminal(event),
42264
- "step.attempt.failed": (event) => bridge.handleStepAttemptTerminal(event),
42265
- "turn.cancelled": (event, context) => bridge.handleTurnTerminal(event, context),
42266
- "turn.completed": (event, context) => bridge.handleTurnTerminal(event, context),
42267
- "turn.failed": (event, context) => bridge.handleTurnTerminal(event, context),
42268
- "turn.started": (event, context) => bridge.handleTurnStarted(event, context)
43733
+ "action.completed": providerHandler(
43734
+ "action.completed",
43735
+ bridge.handleActionTerminal.bind(bridge)
43736
+ ),
43737
+ "action.failed": providerHandler(
43738
+ "action.failed",
43739
+ bridge.handleActionTerminal.bind(bridge)
43740
+ ),
43741
+ "action.started": providerHandler(
43742
+ "action.started",
43743
+ bridge.handleActionStarted.bind(bridge)
43744
+ ),
43745
+ "model.call.completed": providerHandler(
43746
+ "model.call.completed",
43747
+ bridge.handleModelTerminal.bind(bridge)
43748
+ ),
43749
+ "model.call.failed": providerHandler(
43750
+ "model.call.failed",
43751
+ bridge.handleModelTerminal.bind(bridge)
43752
+ ),
43753
+ "model.call.started": providerHandler(
43754
+ "model.call.started",
43755
+ bridge.handleModelStarted.bind(bridge)
43756
+ ),
43757
+ "step.attempt.completed": providerHandler(
43758
+ "step.attempt.completed",
43759
+ (event) => bridge.handleStepAttemptTerminal(event)
43760
+ ),
43761
+ "step.attempt.failed": providerHandler(
43762
+ "step.attempt.failed",
43763
+ (event) => bridge.handleStepAttemptTerminal(event)
43764
+ ),
43765
+ "turn.cancelled": providerHandler(
43766
+ "turn.cancelled",
43767
+ bridge.handleTurnTerminal.bind(bridge)
43768
+ ),
43769
+ "turn.completed": providerHandler(
43770
+ "turn.completed",
43771
+ bridge.handleTurnTerminal.bind(bridge)
43772
+ ),
43773
+ "turn.failed": providerHandler(
43774
+ "turn.failed",
43775
+ bridge.handleTurnTerminal.bind(bridge)
43776
+ ),
43777
+ "turn.started": providerHandler(
43778
+ "turn.started",
43779
+ bridge.handleTurnStarted.bind(bridge)
43780
+ )
42269
43781
  },
42270
43782
  flush,
42271
43783
  setup: options.setup
@@ -42621,17 +44133,20 @@ function modelOutput(event) {
42621
44133
  const reasoning = [];
42622
44134
  const toolCalls2 = [];
42623
44135
  for (const part of content) {
42624
- if (part.type === "text") {
42625
- text += part.text;
42626
- } else if (part.type === "reasoning" && part.text.trim().length > 0) {
42627
- reasoning.push({ content: part.text });
42628
- } else if (part.type === "tool-call") {
44136
+ if (!isObject(part)) {
44137
+ continue;
44138
+ }
44139
+ if (part["type"] === "text" && typeof part["text"] === "string") {
44140
+ text += part["text"];
44141
+ } else if (part["type"] === "reasoning" && typeof part["text"] === "string" && part["text"].trim().length > 0) {
44142
+ reasoning.push({ content: part["text"] });
44143
+ } else if (part["type"] === "tool-call" && typeof part["toolName"] === "string" && typeof part["callId"] === "string") {
42629
44144
  toolCalls2.push({
42630
44145
  function: {
42631
- arguments: safeJsonStringify(part.input),
42632
- name: part.toolName
44146
+ arguments: safeJsonStringify(part["input"]),
44147
+ name: part["toolName"]
42633
44148
  },
42634
- id: part.callId,
44149
+ id: part["callId"],
42635
44150
  type: "function"
42636
44151
  });
42637
44152
  }
@@ -42650,13 +44165,13 @@ function modelOutput(event) {
42650
44165
  ];
42651
44166
  }
42652
44167
  function usageMetrics(usage) {
42653
- const promptTokens = nonNegativeNumber(usage.inputTokens);
42654
- const completionTokens = nonNegativeNumber(usage.outputTokens);
44168
+ const promptTokens = nonNegativeNumber(usage?.inputTokens);
44169
+ const completionTokens = nonNegativeNumber(usage?.outputTokens);
42655
44170
  const cachedTokens = nonNegativeNumber(
42656
- usage.inputTokenDetails?.cacheReadTokens
44171
+ usage?.inputTokenDetails?.cacheReadTokens
42657
44172
  );
42658
44173
  const cacheCreationTokens = nonNegativeNumber(
42659
- usage.inputTokenDetails?.cacheWriteTokens
44174
+ usage?.inputTokenDetails?.cacheWriteTokens
42660
44175
  );
42661
44176
  return {
42662
44177
  ...promptTokens !== void 0 ? { prompt_tokens: promptTokens } : {},
@@ -42693,10 +44208,76 @@ function turnIdempotencyKey(sessionId, turnId) {
42693
44208
  function actionIdempotencyKey(sessionId, turnId, callId) {
42694
44209
  return `action:${sessionId}:${turnId}:${callId}`;
42695
44210
  }
44211
+ function providerHandler(type, handler) {
44212
+ return async (event, context) => {
44213
+ try {
44214
+ if (!isEveProviderEvent(event, type) || !isEveProviderContext(context)) {
44215
+ debugLogger.warn(`Ignoring malformed Eve provider ${type} event`);
44216
+ return;
44217
+ }
44218
+ await handler(event, context);
44219
+ } catch (error) {
44220
+ debugLogger.warn(`Error in Eve provider ${type}:`, error);
44221
+ }
44222
+ };
44223
+ }
44224
+ function isEveProviderEvent(event, type) {
44225
+ if (!isObject(event) || event["type"] !== type || typeof event["idempotencyKey"] !== "string" || event["idempotencyKey"].length === 0) {
44226
+ return false;
44227
+ }
44228
+ if (type === "turn.started") {
44229
+ const parentLineage = event["parentLineage"];
44230
+ 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));
44231
+ }
44232
+ if (type === "turn.cancelled" || type === "turn.completed" || type === "turn.failed") {
44233
+ return typeof event["sessionId"] === "string" && typeof event["turnId"] === "string";
44234
+ }
44235
+ if (!isEveProviderScope(event["scope"])) {
44236
+ return false;
44237
+ }
44238
+ if (type === "model.call.started") {
44239
+ const model = event["model"];
44240
+ return isObject(model) && typeof model["modelId"] === "string" && typeof model["provider"] === "string";
44241
+ }
44242
+ if (type === "model.call.completed") {
44243
+ return typeof event["finishReason"] === "string" && isObject(event["usage"]) && (event["content"] === void 0 || Array.isArray(event["content"]));
44244
+ }
44245
+ if (type === "model.call.failed") {
44246
+ return true;
44247
+ }
44248
+ if (type === "action.started") {
44249
+ 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");
44250
+ }
44251
+ if (type === "action.completed") {
44252
+ const output = event["output"];
44253
+ return event["outcome"] === "completed" && isObject(output) && (output["type"] === "result" || output["type"] === "error");
44254
+ }
44255
+ if (type === "action.failed") {
44256
+ return event["outcome"] === "abandoned" || event["outcome"] === "cancelled" || event["outcome"] === "failed" || event["outcome"] === "rejected";
44257
+ }
44258
+ return type === "step.attempt.completed" || type === "step.attempt.failed";
44259
+ }
44260
+ function isEveProviderContext(value) {
44261
+ if (!isObject(value) || !isObject(value["state"])) {
44262
+ return false;
44263
+ }
44264
+ return typeof value["state"]["get"] === "function" && typeof value["state"]["set"] === "function";
44265
+ }
44266
+ function isEveProviderScope(value) {
44267
+ 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");
44268
+ }
44269
+ function isEveProviderParentLineage(value) {
44270
+ return isObject(value) && typeof value["callId"] === "string" && typeof value["sessionId"] === "string" && typeof value["turnId"] === "string";
44271
+ }
42696
44272
 
42697
44273
  // src/instrumentation/plugins/eve-instrumentation.ts
42698
44274
  var EVE_INSTRUMENTATION_PROVIDER = /* @__PURE__ */ Symbol.for("eve.instrumentation.provider");
42699
44275
  function braintrustEveInstrumentation(options) {
44276
+ if (!options || typeof options !== "object") {
44277
+ throw new TypeError(
44278
+ "braintrustEveInstrumentation requires an options object"
44279
+ );
44280
+ }
42700
44281
  const definition = "defineState" in options ? createLegacyEveInstrumentation(options) : createEveInstrumentationProvider(options);
42701
44282
  const declaration = {
42702
44283
  ...definition,
@@ -43933,6 +45514,7 @@ function wrapClient(client) {
43933
45514
  }
43934
45515
 
43935
45516
  // src/wrappers/google-genai.ts
45517
+ var patchedHttpResponses = /* @__PURE__ */ new WeakSet();
43936
45518
  function wrapGoogleGenAI(googleGenAI) {
43937
45519
  if (!googleGenAI || typeof googleGenAI !== "object") {
43938
45520
  console.warn("Invalid Google GenAI module. Not wrapping.");
@@ -43944,6 +45526,21 @@ function wrapGoogleGenAI(googleGenAI) {
43944
45526
  );
43945
45527
  return googleGenAI;
43946
45528
  }
45529
+ const httpResponse = googleGenAI.HttpResponse;
45530
+ if (typeof httpResponse === "function" && isObject(httpResponse.prototype) && typeof httpResponse.prototype.json === "function" && !patchedHttpResponses.has(httpResponse.prototype)) {
45531
+ const prototype = httpResponse.prototype;
45532
+ const originalJson = prototype.json;
45533
+ if (Reflect.set(prototype, "json", function() {
45534
+ return googleGenAIChannels.httpResponseJson.invoke(
45535
+ originalJson,
45536
+ this,
45537
+ [],
45538
+ {}
45539
+ );
45540
+ })) {
45541
+ patchedHttpResponses.add(prototype);
45542
+ }
45543
+ }
43947
45544
  return new Proxy(googleGenAI, {
43948
45545
  get(target, prop, receiver) {
43949
45546
  if (prop === "GoogleGenAI") {
@@ -44194,17 +45791,17 @@ function wrapGenkit(genkit) {
44194
45791
  console.warn("Unsupported Genkit object. Not wrapping.");
44195
45792
  return genkit;
44196
45793
  }
44197
- function isRecord3(value) {
45794
+ function isRecord4(value) {
44198
45795
  return typeof value === "object" && value !== null;
44199
45796
  }
44200
45797
  function isPropertyBag(value) {
44201
- return isRecord3(value) || typeof value === "function";
45798
+ return isRecord4(value) || typeof value === "function";
44202
45799
  }
44203
45800
  function hasFunction(value, methodName) {
44204
45801
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
44205
45802
  }
44206
45803
  function isGenkitInstance(value) {
44207
- return isRecord3(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
45804
+ return isRecord4(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
44208
45805
  }
44209
45806
  function isGenkitModule(value) {
44210
45807
  return hasFunction(value, "genkit");
@@ -44258,7 +45855,7 @@ function patchGenkitRegistry(instance) {
44258
45855
  patchGenkitRegistryConstructor(registry2);
44259
45856
  }
44260
45857
  function patchGenkitRegistryLookup(registry2) {
44261
- if (!isRecord3(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
45858
+ if (!isRecord4(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
44262
45859
  return;
44263
45860
  }
44264
45861
  const originalLookupAction = registry2.lookupAction;
@@ -44284,7 +45881,7 @@ function patchGenkitRegistryLookup(registry2) {
44284
45881
  }
44285
45882
  }
44286
45883
  function patchGenkitRegistryConstructor(registry2) {
44287
- if (!isRecord3(registry2)) {
45884
+ if (!isRecord4(registry2)) {
44288
45885
  return;
44289
45886
  }
44290
45887
  const constructor = registry2.constructor;
@@ -44300,7 +45897,7 @@ function patchGenkitRegistryConstructor(registry2) {
44300
45897
  configurable: true,
44301
45898
  value: (...args) => {
44302
45899
  const childRegistry = originalWithParent.apply(constructor, args);
44303
- if (args.some((arg) => isRecord3(arg) && hasRegistryPatchedFlag(arg))) {
45900
+ if (args.some((arg) => isRecord4(arg) && hasRegistryPatchedFlag(arg))) {
44304
45901
  patchGenkitRegistryLookup(childRegistry);
44305
45902
  patchGenkitRegistryConstructor(childRegistry);
44306
45903
  }
@@ -44399,7 +45996,7 @@ function hasRegistryConstructorPatchedFlag(value) {
44399
45996
  );
44400
45997
  }
44401
45998
  function isPromiseLike2(value) {
44402
- return isRecord3(value) && "then" in value && typeof value.then === "function";
45999
+ return isRecord4(value) && "then" in value && typeof value.then === "function";
44403
46000
  }
44404
46001
 
44405
46002
  // src/wrappers/huggingface.ts
@@ -44876,14 +46473,14 @@ function wrapMistral(mistral) {
44876
46473
  console.warn("Unsupported Mistral library. Not wrapping.");
44877
46474
  return mistral;
44878
46475
  }
44879
- function isRecord4(value) {
46476
+ function isRecord5(value) {
44880
46477
  return typeof value === "object" && value !== null;
44881
46478
  }
44882
46479
  function hasFunction3(value, methodName) {
44883
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
46480
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
44884
46481
  }
44885
46482
  function isSupportedMistralClient(value) {
44886
- if (!isRecord4(value)) {
46483
+ if (!isRecord5(value)) {
44887
46484
  return false;
44888
46485
  }
44889
46486
  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);
@@ -45058,6 +46655,42 @@ function wrapAgentsStream(stream) {
45058
46655
  });
45059
46656
  }
45060
46657
 
46658
+ // src/wrappers/langgraph-sdk.ts
46659
+ var clients = /* @__PURE__ */ new WeakMap();
46660
+ function wrapLangGraphSDK(client) {
46661
+ const runsClient = isObject(client) ? client.runs : void 0;
46662
+ if (!isObject(client) || !isObject(runsClient) || !["wait", "stream"].every((key) => typeof runsClient[key] === "function")) {
46663
+ debugLogger.warn("Unsupported LangGraph SDK client. Not wrapping.");
46664
+ return client;
46665
+ }
46666
+ const sdk = client;
46667
+ const cached = clients.get(sdk);
46668
+ if (cached) return cached;
46669
+ const runs = new Proxy(sdk.runs, {
46670
+ get(target, key) {
46671
+ switch (key) {
46672
+ case "wait":
46673
+ return (...args) => langGraphSDKChannels.wait.invoke(target.wait, target, args, {});
46674
+ case "stream":
46675
+ return (...args) => langGraphSDKChannels.stream.invoke(target.stream, target, args, {});
46676
+ default:
46677
+ const value = Reflect.get(target, key, target);
46678
+ return typeof value === "function" ? value.bind(target) : value;
46679
+ }
46680
+ }
46681
+ });
46682
+ const wrapped = new Proxy(sdk, {
46683
+ get(target, key) {
46684
+ if (key === "runs") return runs;
46685
+ const value = Reflect.get(target, key, target);
46686
+ return typeof value === "function" ? value.bind(target) : value;
46687
+ }
46688
+ });
46689
+ clients.set(sdk, wrapped);
46690
+ clients.set(wrapped, wrapped);
46691
+ return wrapped;
46692
+ }
46693
+
45061
46694
  // src/wrappers/ollama.ts
45062
46695
  function wrapOllama(ollama) {
45063
46696
  if (isSupportedOllamaClient(ollama)) {
@@ -45144,14 +46777,14 @@ function wrapCohere(cohere) {
45144
46777
  return cohere;
45145
46778
  }
45146
46779
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
45147
- function isRecord5(value) {
46780
+ function isRecord6(value) {
45148
46781
  return typeof value === "object" && value !== null;
45149
46782
  }
45150
46783
  function hasFunction4(value, methodName) {
45151
- return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
46784
+ return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
45152
46785
  }
45153
46786
  function isSupportedCohereClient(value) {
45154
- if (!isRecord5(value)) {
46787
+ if (!isRecord6(value)) {
45155
46788
  return false;
45156
46789
  }
45157
46790
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -45289,20 +46922,20 @@ function wrapGroq(groq) {
45289
46922
  console.warn("Unsupported Groq library. Not wrapping.");
45290
46923
  return groq;
45291
46924
  }
45292
- function isRecord6(value) {
46925
+ function isRecord7(value) {
45293
46926
  return typeof value === "object" && value !== null;
45294
46927
  }
45295
46928
  function hasFunction6(value, methodName) {
45296
- return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
46929
+ return isRecord7(value) && methodName in value && typeof value[methodName] === "function";
45297
46930
  }
45298
46931
  function hasChat2(value) {
45299
- return isRecord6(value) && isRecord6(value.completions) && hasFunction6(value.completions, "create");
46932
+ return isRecord7(value) && isRecord7(value.completions) && hasFunction6(value.completions, "create");
45300
46933
  }
45301
46934
  function hasEmbeddings2(value) {
45302
46935
  return hasFunction6(value, "create");
45303
46936
  }
45304
46937
  function isSupportedGroqClient(value) {
45305
- return isRecord6(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
46938
+ return isRecord7(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
45306
46939
  }
45307
46940
  function groqProxy(groq) {
45308
46941
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -45385,11 +47018,11 @@ var BEDROCK_RUNTIME_OPERATION_METHODS = /* @__PURE__ */ new Set([
45385
47018
  "invokeModelWithBidirectionalStream",
45386
47019
  "invokeModelWithResponseStream"
45387
47020
  ]);
45388
- function isRecord7(value) {
47021
+ function isRecord8(value) {
45389
47022
  return typeof value === "object" && value !== null;
45390
47023
  }
45391
47024
  function isSupportedBedrockRuntimeClient(value) {
45392
- return isRecord7(value) && typeof value.send === "function";
47025
+ return isRecord8(value) && typeof value.send === "function";
45393
47026
  }
45394
47027
  function bedrockRuntimeProxy(client) {
45395
47028
  const cached = bedrockRuntimeProxyCache.get(client);
@@ -47715,12 +49348,272 @@ function waterfall(tasks, callback) {
47715
49348
  }
47716
49349
  var waterfall$1 = awaitify(waterfall);
47717
49350
 
49351
+ // src/framework.ts
49352
+ import { v5 as uuidv5 } from "uuid";
49353
+
47718
49354
  // src/trace.ts
49355
+ var spanFilterFields = /* @__PURE__ */ new Set([
49356
+ "spanType",
49357
+ "name",
49358
+ "hasError",
49359
+ "metadata",
49360
+ "duration"
49361
+ ]);
49362
+ function isRecord9(value) {
49363
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
49364
+ return false;
49365
+ }
49366
+ const prototype = Object.getPrototypeOf(value);
49367
+ return prototype === Object.prototype || prototype === null;
49368
+ }
49369
+ function validateMetadataValue(value, ancestors) {
49370
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
49371
+ return;
49372
+ }
49373
+ if (typeof value === "number") {
49374
+ if (Number.isFinite(value)) {
49375
+ return;
49376
+ }
49377
+ throw new Error("filters.metadata numbers must be finite");
49378
+ }
49379
+ if (typeof value !== "object" || value === null) {
49380
+ throw new Error("filters.metadata values must be JSON-serializable");
49381
+ }
49382
+ if (!Array.isArray(value) && !isRecord9(value)) {
49383
+ throw new Error("filters.metadata values must be JSON-serializable");
49384
+ }
49385
+ if (ancestors.has(value)) {
49386
+ throw new Error("filters.metadata must not contain cycles");
49387
+ }
49388
+ ancestors.add(value);
49389
+ if (Array.isArray(value)) {
49390
+ for (let index = 0; index < value.length; index++) {
49391
+ validateMetadataValue(value[index], ancestors);
49392
+ }
49393
+ } else {
49394
+ if (Object.getOwnPropertySymbols(value).length > 0) {
49395
+ throw new Error("filters.metadata keys must be strings");
49396
+ }
49397
+ for (const nested of Object.values(value)) {
49398
+ validateMetadataValue(nested, ancestors);
49399
+ }
49400
+ }
49401
+ ancestors.delete(value);
49402
+ }
49403
+ function compileMetadataLeaves(metadata, path = [], ancestors = /* @__PURE__ */ new WeakSet()) {
49404
+ if (Object.getOwnPropertySymbols(metadata).length > 0) {
49405
+ throw new Error("filters.metadata keys must be strings");
49406
+ }
49407
+ if (ancestors.has(metadata)) {
49408
+ throw new Error("filters.metadata must not contain cycles");
49409
+ }
49410
+ ancestors.add(metadata);
49411
+ const leaves = [];
49412
+ for (const [key, value] of Object.entries(metadata)) {
49413
+ const childPath = [...path, key];
49414
+ if (isRecord9(value)) {
49415
+ leaves.push(...compileMetadataLeaves(value, childPath, ancestors));
49416
+ } else {
49417
+ validateMetadataValue(value, ancestors);
49418
+ leaves.push([childPath, value]);
49419
+ }
49420
+ }
49421
+ ancestors.delete(metadata);
49422
+ return leaves;
49423
+ }
49424
+ function normalizeSpanFilters(filters, spanType) {
49425
+ if (filters != null && !isRecord9(filters)) {
49426
+ throw new Error("filters must be an object");
49427
+ }
49428
+ const values = { ...filters ?? {} };
49429
+ if (spanType !== void 0) {
49430
+ if (!Array.isArray(spanType) || !spanType.every((item) => typeof item === "string")) {
49431
+ throw new Error("spanType must be an array of strings");
49432
+ }
49433
+ if (Object.hasOwn(values, "spanType")) {
49434
+ throw new Error(
49435
+ "spanType cannot be provided both directly and in filters"
49436
+ );
49437
+ }
49438
+ if (spanType.length > 0) {
49439
+ values.spanType = spanType;
49440
+ }
49441
+ }
49442
+ if (Object.keys(values).some((field) => !spanFilterFields.has(field))) {
49443
+ throw new Error("Unsupported span filter fields");
49444
+ }
49445
+ for (const field of ["spanType", "name"]) {
49446
+ if (Object.hasOwn(values, field)) {
49447
+ const items = values[field];
49448
+ if (!Array.isArray(items) || !items.every((item) => typeof item === "string")) {
49449
+ throw new Error(`filters.${field} must be an array of strings`);
49450
+ }
49451
+ }
49452
+ }
49453
+ if (Object.hasOwn(values, "hasError") && typeof values.hasError !== "boolean") {
49454
+ throw new Error("filters.hasError must be a boolean");
49455
+ }
49456
+ let compiledMetadataLeaves = [];
49457
+ if (Object.hasOwn(values, "metadata")) {
49458
+ if (!isRecord9(values.metadata)) {
49459
+ throw new Error("filters.metadata must be an object");
49460
+ }
49461
+ compiledMetadataLeaves = compileMetadataLeaves(values.metadata);
49462
+ }
49463
+ if (Object.hasOwn(values, "duration")) {
49464
+ if (!isRecord9(values.duration) || Object.keys(values.duration).some(
49465
+ (bound) => bound !== "min" && bound !== "max"
49466
+ )) {
49467
+ throw new Error("filters.duration must contain only min and/or max");
49468
+ }
49469
+ if (Object.values(values.duration).some(
49470
+ (bound) => typeof bound !== "number" || !Number.isFinite(bound)
49471
+ )) {
49472
+ throw new Error("filters.duration bounds must be finite numbers");
49473
+ }
49474
+ }
49475
+ const normalized = {};
49476
+ if (Array.isArray(values.spanType)) {
49477
+ normalized.spanType = values.spanType;
49478
+ }
49479
+ if (Array.isArray(values.name)) {
49480
+ normalized.name = values.name;
49481
+ }
49482
+ if (typeof values.hasError === "boolean") {
49483
+ normalized.hasError = values.hasError;
49484
+ }
49485
+ if (isRecord9(values.metadata)) {
49486
+ normalized.metadata = values.metadata;
49487
+ }
49488
+ if (isRecord9(values.duration)) {
49489
+ normalized.duration = {};
49490
+ if (typeof values.duration.min === "number") {
49491
+ normalized.duration.min = values.duration.min;
49492
+ }
49493
+ if (typeof values.duration.max === "number") {
49494
+ normalized.duration.max = values.duration.max;
49495
+ }
49496
+ }
49497
+ return { filters: normalized, metadataLeaves: compiledMetadataLeaves };
49498
+ }
49499
+ function metadataEqual(actual, expected) {
49500
+ if (expected === null) {
49501
+ return actual === null || actual === void 0;
49502
+ }
49503
+ if (Array.isArray(expected)) {
49504
+ return Array.isArray(actual) && actual.length === expected.length && expected.every((value, index) => metadataEqual(actual[index], value));
49505
+ }
49506
+ if (isRecord9(expected)) {
49507
+ if (!isRecord9(actual)) {
49508
+ return false;
49509
+ }
49510
+ const expectedKeys = Object.keys(expected);
49511
+ const actualKeys = Object.keys(actual);
49512
+ return actualKeys.length === expectedKeys.length && expectedKeys.every(
49513
+ (key) => Object.hasOwn(actual, key) && metadataEqual(actual[key], expected[key])
49514
+ );
49515
+ }
49516
+ return actual === expected;
49517
+ }
49518
+ function matchesSpanFilters(span, compiledFilters) {
49519
+ const { filters, metadataLeaves } = compiledFilters;
49520
+ if (filters.spanType !== void 0 && !filters.spanType.includes(span.span_attributes?.type ?? "")) {
49521
+ return false;
49522
+ }
49523
+ if (filters.name !== void 0 && !filters.name.includes(span.span_attributes?.name ?? "")) {
49524
+ return false;
49525
+ }
49526
+ if (filters.hasError !== void 0 && (span.error !== null && span.error !== void 0) !== filters.hasError) {
49527
+ return false;
49528
+ }
49529
+ for (const [path, expected] of metadataLeaves) {
49530
+ let actual = span.metadata;
49531
+ for (const key of path) {
49532
+ actual = isRecord9(actual) && Object.hasOwn(actual, key) ? actual[key] : void 0;
49533
+ }
49534
+ if (!metadataEqual(actual, expected)) {
49535
+ return false;
49536
+ }
49537
+ }
49538
+ if (filters.duration && Object.keys(filters.duration).length > 0) {
49539
+ const metrics = span.metrics;
49540
+ const start = isRecord9(metrics) ? metrics.start : void 0;
49541
+ const end = isRecord9(metrics) ? metrics.end : void 0;
49542
+ if (typeof start !== "number" || !Number.isFinite(start) || typeof end !== "number" || !Number.isFinite(end)) {
49543
+ return false;
49544
+ }
49545
+ const elapsed = end - start;
49546
+ if (filters.duration.min !== void 0 && elapsed < filters.duration.min) {
49547
+ return false;
49548
+ }
49549
+ if (filters.duration.max !== void 0 && elapsed > filters.duration.max) {
49550
+ return false;
49551
+ }
49552
+ }
49553
+ return true;
49554
+ }
49555
+ function btqlComparison(op, name, value) {
49556
+ return {
49557
+ op,
49558
+ left: { op: "ident", name },
49559
+ right: { op: "literal", value }
49560
+ };
49561
+ }
49562
+ function btqlNullCheck(op, name) {
49563
+ return { op, expr: { op: "ident", name } };
49564
+ }
49565
+ function spanFilterClauses(compiledFilters) {
49566
+ const { filters, metadataLeaves } = compiledFilters;
49567
+ const children = [];
49568
+ for (const [field, attribute] of [
49569
+ ["spanType", "type"],
49570
+ ["name", "name"]
49571
+ ]) {
49572
+ const values = filters[field];
49573
+ if (values !== void 0) {
49574
+ children.push(
49575
+ values.length > 0 ? btqlComparison("in", ["span_attributes", attribute], values) : { op: "literal", value: false }
49576
+ );
49577
+ }
49578
+ }
49579
+ if (filters.hasError !== void 0) {
49580
+ children.push(
49581
+ btqlNullCheck(filters.hasError ? "isnotnull" : "isnull", ["error"])
49582
+ );
49583
+ }
49584
+ for (const [path, value] of metadataLeaves) {
49585
+ const name = ["metadata", ...path];
49586
+ children.push(
49587
+ value === null ? btqlNullCheck("isnull", name) : btqlComparison("eq", name, value)
49588
+ );
49589
+ }
49590
+ const elapsed = {
49591
+ op: "sub",
49592
+ left: { op: "ident", name: ["metrics", "end"] },
49593
+ right: { op: "ident", name: ["metrics", "start"] }
49594
+ };
49595
+ if (filters.duration?.min !== void 0) {
49596
+ children.push({
49597
+ op: "ge",
49598
+ left: elapsed,
49599
+ right: { op: "literal", value: filters.duration.min }
49600
+ });
49601
+ }
49602
+ if (filters.duration?.max !== void 0) {
49603
+ children.push({
49604
+ op: "le",
49605
+ left: elapsed,
49606
+ right: { op: "literal", value: filters.duration.max }
49607
+ });
49608
+ }
49609
+ return children;
49610
+ }
47719
49611
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
47720
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false, brainstoreRealtime = true) {
49612
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false, brainstoreRealtime = true, filters) {
49613
+ const normalizedFilters = normalizeSpanFilters(filters, spanTypeFilter);
47721
49614
  const filterExpr = _SpanFetcher.buildFilter(
47722
49615
  rootSpanId,
47723
- spanTypeFilter,
49616
+ normalizedFilters,
47724
49617
  includeScorers
47725
49618
  );
47726
49619
  super(
@@ -47741,42 +49634,22 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
47741
49634
  rootSpanId;
47742
49635
  _state;
47743
49636
  spanTypeFilter;
47744
- static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
49637
+ static buildFilter(rootSpanId, filters, includeScorers = false) {
49638
+ const purpose = ["span_attributes", "purpose"];
47745
49639
  const children = [
47746
- // Base filter: root_span_id = 'value'
47747
- {
47748
- op: "eq",
47749
- left: { op: "ident", name: ["root_span_id"] },
47750
- right: { op: "literal", value: rootSpanId }
47751
- }
49640
+ btqlComparison("eq", ["root_span_id"], rootSpanId)
47752
49641
  ];
47753
49642
  if (!includeScorers) {
47754
49643
  children.push({
47755
49644
  op: "or",
47756
49645
  children: [
47757
- {
47758
- op: "isnull",
47759
- expr: { op: "ident", name: ["span_attributes", "purpose"] }
47760
- },
47761
- {
47762
- op: "ne",
47763
- left: { op: "ident", name: ["span_attributes", "purpose"] },
47764
- right: { op: "literal", value: "scorer" }
47765
- }
49646
+ btqlNullCheck("isnull", purpose),
49647
+ btqlComparison("ne", purpose, "scorer")
47766
49648
  ]
47767
49649
  });
47768
49650
  }
47769
- if (spanTypeFilter && spanTypeFilter.length > 0) {
47770
- children.push({
47771
- op: "in",
47772
- left: { op: "ident", name: ["span_attributes", "type"] },
47773
- right: { op: "literal", value: spanTypeFilter }
47774
- });
47775
- }
47776
- return {
47777
- op: "and",
47778
- children
47779
- };
49651
+ children.push(...spanFilterClauses(filters));
49652
+ return { op: "and", children };
47780
49653
  }
47781
49654
  get id() {
47782
49655
  return Promise.resolve(this._objectId);
@@ -47791,67 +49664,80 @@ var CachedSpanFetcher = class {
47791
49664
  fetchFn;
47792
49665
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState, brainstoreRealtime = true) {
47793
49666
  if (typeof objectTypeOrFetchFn === "function") {
47794
- this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
49667
+ this.fetchFn = async (filters) => (await objectTypeOrFetchFn(filters.filters.spanType)).filter(
49668
+ (span) => matchesSpanFilters(span, filters)
49669
+ );
47795
49670
  } else {
47796
49671
  const objectType = objectTypeOrFetchFn;
47797
- this.fetchFn = async (spanType, includeScorers) => {
49672
+ this.fetchFn = async (filters, includeScorers) => {
47798
49673
  const state = await getState();
47799
49674
  const fetcher = new SpanFetcher(
47800
49675
  objectType,
47801
49676
  objectId,
47802
49677
  rootSpanId,
47803
49678
  state,
47804
- spanType,
49679
+ void 0,
47805
49680
  includeScorers,
47806
- brainstoreRealtime
49681
+ brainstoreRealtime,
49682
+ filters.filters
47807
49683
  );
47808
- const rows = await fetcher.fetchedData();
47809
- return rows.map((row) => ({
47810
- input: row.input,
47811
- output: row.output,
47812
- expected: row.expected,
47813
- error: row.error,
47814
- scores: row.scores,
47815
- metrics: row.metrics,
47816
- metadata: row.metadata,
47817
- span_id: row.span_id,
47818
- span_parents: row.span_parents,
47819
- is_root: row.is_root,
47820
- span_attributes: row.span_attributes,
47821
- id: row.id,
47822
- _xact_id: row._xact_id,
47823
- _pagination_key: row._pagination_key,
47824
- root_span_id: row.root_span_id,
47825
- created: row.created,
47826
- tags: row.tags
47827
- }));
49684
+ let spans = (await fetcher.fetchedData()).map(
49685
+ (row) => ({ ...row })
49686
+ );
49687
+ if (filters.filters.metadata !== void 0) {
49688
+ spans = spans.filter((span) => matchesSpanFilters(span, filters));
49689
+ }
49690
+ return spans;
47828
49691
  };
47829
49692
  }
47830
49693
  }
47831
49694
  async getSpans({
47832
- spanType,
49695
+ spanType: requestedSpanType,
49696
+ filters,
47833
49697
  includeScorers = false
47834
49698
  } = {}) {
49699
+ const normalizedFilters = normalizeSpanFilters(filters, requestedSpanType);
49700
+ const spanType = normalizedFilters.filters.spanType;
49701
+ const hasAdvancedFilters = Object.keys(normalizedFilters.filters).some(
49702
+ (field) => field !== "spanType"
49703
+ );
49704
+ if (spanType?.length === 0) {
49705
+ return [];
49706
+ }
47835
49707
  if (includeScorers) {
47836
- return this.fetchFn(spanType, true);
49708
+ return this.fetchFn(normalizedFilters, true);
47837
49709
  }
47838
49710
  if (this.allFetched) {
47839
- return this.getFromCache(spanType);
49711
+ const spans = this.getFromCache(spanType);
49712
+ return hasAdvancedFilters ? spans.filter((span) => matchesSpanFilters(span, normalizedFilters)) : spans;
47840
49713
  }
47841
- if (!spanType || spanType.length === 0) {
49714
+ if (hasAdvancedFilters && spanType && spanType.every((type) => this.spanCache.has(type))) {
49715
+ return this.getFromCache(spanType).filter(
49716
+ (span) => matchesSpanFilters(span, normalizedFilters)
49717
+ );
49718
+ }
49719
+ if (hasAdvancedFilters) {
49720
+ return this.fetchFn(normalizedFilters, false);
49721
+ }
49722
+ if (!spanType) {
49723
+ this.spanCache.clear();
47842
49724
  await this.fetchSpans(void 0);
47843
- this.allFetched = true;
49725
+ if (this.spanCache.size > 0) {
49726
+ this.allFetched = true;
49727
+ }
47844
49728
  return this.getFromCache(void 0);
47845
49729
  }
47846
- const missingTypes = spanType.filter((t) => !this.spanCache.has(t));
47847
- if (missingTypes.length === 0) {
47848
- return this.getFromCache(spanType);
49730
+ const missingTypes = spanType.filter((type) => !this.spanCache.has(type));
49731
+ if (missingTypes.length > 0) {
49732
+ await this.fetchSpans(missingTypes);
47849
49733
  }
47850
- await this.fetchSpans(missingTypes);
47851
49734
  return this.getFromCache(spanType);
47852
49735
  }
47853
49736
  async fetchSpans(spanType) {
47854
- const spans = await this.fetchFn(spanType, false);
49737
+ const spans = await this.fetchFn(
49738
+ normalizeSpanFilters(spanType ? { spanType } : void 0),
49739
+ false
49740
+ );
47855
49741
  for (const span of spans) {
47856
49742
  const type = span.span_attributes?.type ?? "";
47857
49743
  const existing = this.spanCache.get(type) ?? [];
@@ -47931,34 +49817,20 @@ var LocalTrace = class {
47931
49817
  */
47932
49818
  async getSpans({
47933
49819
  spanType,
49820
+ filters,
47934
49821
  includeScorers = false
47935
49822
  } = {}) {
49823
+ const normalizedFilters = normalizeSpanFilters(filters, spanType);
47936
49824
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
47937
49825
  if (cachedSpans && cachedSpans.length > 0) {
47938
- let spans = includeScorers ? cachedSpans : cachedSpans.filter(
47939
- (span) => span.span_attributes?.purpose !== "scorer"
47940
- );
47941
- if (spanType && spanType.length > 0) {
47942
- spans = spans.filter(
47943
- (span) => spanType.includes(span.span_attributes?.type ?? "")
47944
- );
47945
- }
47946
- return spans.map((span) => ({
47947
- input: span.input,
47948
- output: span.output,
47949
- expected: span.expected,
47950
- error: span.error,
47951
- scores: span.scores,
47952
- metrics: span.metrics,
47953
- metadata: span.metadata,
47954
- span_id: span.span_id,
47955
- span_parents: span.span_parents,
47956
- is_root: span.is_root,
47957
- span_attributes: span.span_attributes,
47958
- tags: span.tags
47959
- }));
47960
- }
47961
- return this.cachedFetcher.getSpans({ spanType, includeScorers });
49826
+ return cachedSpans.filter(
49827
+ (span) => (includeScorers || span.span_attributes?.purpose !== "scorer") && matchesSpanFilters({ ...span }, normalizedFilters)
49828
+ ).map((span) => ({ ...span }));
49829
+ }
49830
+ return this.cachedFetcher.getSpans({
49831
+ filters: normalizedFilters.filters,
49832
+ includeScorers
49833
+ });
47962
49834
  }
47963
49835
  /**
47964
49836
  * Get the thread (preprocessed messages) for this trace.
@@ -48378,7 +50250,7 @@ async function Eval(name, evaluator, reporterOrOpts) {
48378
50250
  data,
48379
50251
  { disabled: Boolean(options.parent || options.noSendLogs) }
48380
50252
  );
48381
- if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
50253
+ if (experiment) {
48382
50254
  await experiment._waitForId();
48383
50255
  }
48384
50256
  if (experiment && options.onStart) {
@@ -48703,6 +50575,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
48703
50575
  } : void 0;
48704
50576
  const parsedDatumOrigin = ObjectReference.safeParse(datum.origin);
48705
50577
  const origin = inlineDatasetOrigin ?? (parsedDatumOrigin?.success ? parsedDatumOrigin.data : void 0);
50578
+ const upsertId = datum.upsert_id && trialIndex > 0 ? uuidv5(
50579
+ `braintrust:eval:${datum.upsert_id}:trial:${trialIndex}`,
50580
+ uuidv5.URL
50581
+ ) : datum.upsert_id;
48706
50582
  const baseEvent = {
48707
50583
  name: "eval",
48708
50584
  spanAttributes: {
@@ -48713,7 +50589,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
48713
50589
  expected: "expected" in datum ? datum.expected : void 0,
48714
50590
  tags: datum.tags,
48715
50591
  origin,
48716
- ...datum.upsert_id ? { id: datum.upsert_id } : {}
50592
+ ...upsertId ? { id: upsertId } : {}
48717
50593
  }
48718
50594
  };
48719
50595
  const callback = async (rootSpan) => {
@@ -49222,14 +51098,14 @@ var defaultReporter = {
49222
51098
  }
49223
51099
  };
49224
51100
 
49225
- // src/durable-eval.ts
51101
+ // src/workflow-eval.ts
49226
51102
  var encoder = new TextEncoder();
49227
51103
  var decoder = new TextDecoder();
49228
- var BATCH_TASK_KIND = "braintrust.durable.batch-task";
49229
- var BATCH_SCORER_KIND = "braintrust.durable.batch-scorer";
49230
- var DEFAULT_BATCH_SIZE = 1e3;
49231
- var DurableEvalMemoryStore = class {
51104
+ var WORKFLOW_TASK_KIND = "braintrust.workflow.task";
51105
+ var WORKFLOW_SCORER_KIND = "braintrust.workflow.scorer";
51106
+ var WorkflowEvalMemoryStore = class {
49232
51107
  values = /* @__PURE__ */ new Map();
51108
+ sets = /* @__PURE__ */ new Map();
49233
51109
  async read(key) {
49234
51110
  return this.values.get(key)?.slice();
49235
51111
  }
@@ -49242,8 +51118,16 @@ var DurableEvalMemoryStore = class {
49242
51118
  this.values.set(key, value.slice());
49243
51119
  return { value: value.slice(), created: true };
49244
51120
  }
51121
+ async addToSet(key, member) {
51122
+ let members = this.sets.get(key);
51123
+ if (!members) this.sets.set(key, members = /* @__PURE__ */ new Set());
51124
+ members.add(member);
51125
+ }
51126
+ async getSetSize(key) {
51127
+ return this.sets.get(key)?.size ?? 0;
51128
+ }
49245
51129
  };
49246
- var DurableEvalRedisStore = class {
51130
+ var WorkflowEvalRedisStore = class {
49247
51131
  client;
49248
51132
  keyPrefix;
49249
51133
  ttlMs;
@@ -49252,14 +51136,16 @@ var DurableEvalRedisStore = class {
49252
51136
  this.keyPrefix = options.keyPrefix ?? "braintrust-eval:";
49253
51137
  this.ttlMs = options.ttlMs ?? 1e3 * 60 * 60 * 24 * 7;
49254
51138
  if (!Number.isInteger(this.ttlMs) || this.ttlMs < 1) {
49255
- throw new Error("DurableEvalRedisStore ttlMs must be a positive integer");
51139
+ throw new Error(
51140
+ "WorkflowEvalRedisStore ttlMs must be a positive integer"
51141
+ );
49256
51142
  }
49257
51143
  }
49258
51144
  async read(key) {
49259
51145
  const value = await this.client.get(`${this.keyPrefix}${key}`);
49260
51146
  if (value == null) return void 0;
49261
51147
  if (typeof value !== "string") {
49262
- throw new Error("DurableEvalRedisStore expected GET to return a string");
51148
+ throw new Error("WorkflowEvalRedisStore expected GET to return a string");
49263
51149
  }
49264
51150
  return base64ToUint8Array(value);
49265
51151
  }
@@ -49276,7 +51162,7 @@ var DurableEvalRedisStore = class {
49276
51162
  await set.call(client, redisKey, encoded, { px: this.ttlMs });
49277
51163
  } else {
49278
51164
  throw new Error(
49279
- "DurableEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
51165
+ "WorkflowEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
49280
51166
  );
49281
51167
  }
49282
51168
  }
@@ -49294,49 +51180,73 @@ var DurableEvalRedisStore = class {
49294
51180
  setOptions = [{ px: this.ttlMs, nx: true, get: true }];
49295
51181
  } else {
49296
51182
  throw new Error(
49297
- "DurableEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
51183
+ "WorkflowEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
49298
51184
  );
49299
51185
  }
49300
51186
  const existing = await set.call(client, redisKey, encoded, ...setOptions);
49301
51187
  if (existing === null) return { value: value.slice(), created: true };
49302
51188
  if (typeof existing !== "string") {
49303
51189
  throw new Error(
49304
- "DurableEvalRedisStore expected atomic SET to return a string or null"
51190
+ "WorkflowEvalRedisStore expected atomic SET to return a string or null"
49305
51191
  );
49306
51192
  }
49307
51193
  return { value: base64ToUint8Array(existing), created: false };
49308
51194
  }
51195
+ async addToSet(key, member) {
51196
+ await this.evalSet(
51197
+ "redis.call('SADD', KEYS[1], ARGV[1]); redis.call('PEXPIRE', KEYS[1], ARGV[2]); return 1",
51198
+ key,
51199
+ [member, String(this.ttlMs)]
51200
+ );
51201
+ }
51202
+ async getSetSize(key) {
51203
+ return this.evalSet("return redis.call('SCARD', KEYS[1])", key, []);
51204
+ }
51205
+ async evalSet(script, key, args) {
51206
+ const client = this.client;
51207
+ const redisKey = `${this.keyPrefix}${key}`;
51208
+ 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);
51209
+ if (typeof result !== "number") {
51210
+ throw new Error(
51211
+ "WorkflowEvalRedisStore expected EVAL to return a number"
51212
+ );
51213
+ }
51214
+ return result;
51215
+ }
49309
51216
  };
49310
- var BatchTask = class {
51217
+ var WorkflowTask = class {
49311
51218
  constructor(processor) {
49312
51219
  this.processor = processor;
49313
51220
  }
49314
51221
  processor;
49315
- kind = BATCH_TASK_KIND;
51222
+ kind = WORKFLOW_TASK_KIND;
49316
51223
  };
49317
- var BatchScorer = class {
51224
+ var WorkflowScorer = class {
49318
51225
  constructor(processor) {
49319
51226
  this.processor = processor;
49320
51227
  this.name = processor.name;
49321
51228
  }
49322
51229
  processor;
49323
- kind = BATCH_SCORER_KIND;
51230
+ kind = WORKFLOW_SCORER_KIND;
49324
51231
  name;
49325
51232
  };
49326
- function defineDurableEval(projectName, evaluator) {
51233
+ function defineWorkflowEval(projectName, evaluator) {
51234
+ if (evaluator.maxConcurrency !== void 0 && (!Number.isInteger(evaluator.maxConcurrency) || evaluator.maxConcurrency < 1)) {
51235
+ throw new Error("maxConcurrency must be a positive integer");
51236
+ }
49327
51237
  const definition = {
49328
51238
  projectName,
49329
51239
  evalName: evaluator.experimentName ?? projectName,
49330
51240
  evaluator
49331
51241
  };
49332
51242
  return {
49333
- start: (options = {}) => startDurableEval(definition, options),
49334
- status: (options) => getDurableEvalStatus(definition, options),
49335
- poll: (options) => pollDurableEval(definition, options),
49336
- processBatchResult: (result) => processDurableBatchResult(definition, result)
51243
+ start: (options = {}) => startWorkflowEval(definition, options),
51244
+ status: (options) => getWorkflowEvalStatus(definition, options),
51245
+ poll: (options) => pollWorkflowEval(definition, options),
51246
+ processSubmissionResult: (result) => processWorkflowSubmissionResult(definition, result)
49337
51247
  };
49338
51248
  }
49339
- async function startDurableEval(definition, options) {
51249
+ async function startWorkflowEval(definition, options) {
49340
51250
  const store = definition.evaluator.store;
49341
51251
  const runId = newId();
49342
51252
  const key = runKey(definition.projectName, definition.evalName, runId);
@@ -49356,7 +51266,7 @@ async function startDurableEval(definition, options) {
49356
51266
  update: true
49357
51267
  }
49358
51268
  );
49359
- if (!isBatchTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isBatchScorer)) {
51269
+ if (!isWorkflowTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isWorkflowScorer)) {
49360
51270
  const result = await runEvaluator(
49361
51271
  experiment,
49362
51272
  {
@@ -49383,67 +51293,91 @@ async function startDurableEval(definition, options) {
49383
51293
  parameters: assertJsonValue(parameters, "eval parameters"),
49384
51294
  status: "completed",
49385
51295
  summary: result.summary,
51296
+ caseCount: 0,
49386
51297
  cases: [],
49387
- batches: []
51298
+ submissions: []
49388
51299
  };
49389
51300
  await experiment?.flush();
49390
51301
  await writeRunRecord(store, key, state2);
49391
51302
  return currentStatus(definition, state2);
49392
51303
  }
51304
+ const cases = await materializeCases(definition, data, experiment);
49393
51305
  const state = {
49394
51306
  runId,
49395
51307
  experimentName,
49396
51308
  noSendLogs: options.noSendLogs ?? false,
49397
51309
  parameters: assertJsonValue(parameters, "eval parameters"),
49398
51310
  status: "running",
49399
- cases: await materializeCases(definition, data, experiment),
49400
- batches: []
51311
+ caseCount: cases.length,
51312
+ cases,
51313
+ submissions: []
49401
51314
  };
51315
+ await writeJson(
51316
+ store,
51317
+ `${key}/case-ids`,
51318
+ cases.map(({ id }) => id)
51319
+ );
49402
51320
  await writeCaseBaseRecords(store, key, state.cases);
49403
51321
  await writeRunRecord(store, key, state);
49404
- return advanceDurableEval(definition, state, store, key, experiment);
51322
+ return advanceWorkflowEval(definition, state, store, key, experiment);
49405
51323
  }
49406
- async function getDurableEvalStatus(definition, options) {
51324
+ async function getWorkflowEvalStatus(definition, options) {
49407
51325
  const store = definition.evaluator.store;
49408
- const state = await readRunState(
49409
- definition,
49410
- store,
49411
- runKey(definition.projectName, definition.evalName, options.runId)
51326
+ const key = runKey(
51327
+ definition.projectName,
51328
+ definition.evalName,
51329
+ options.runId
49412
51330
  );
49413
- if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
51331
+ const state = await readJson(store, key);
51332
+ if (!state) throw new Error(`Workflow eval run ${options.runId} is missing`);
49414
51333
  return currentStatus(definition, state);
49415
51334
  }
49416
- async function processDurableBatchResult(definition, result) {
49417
- if (!result.batchId && !result.externalId) {
49418
- throw new Error("Batch results require batchId or externalId");
51335
+ async function processWorkflowSubmissionResult(definition, result) {
51336
+ if (!result.submissionId && !result.externalId) {
51337
+ throw new Error("Submission results require submissionId or externalId");
49419
51338
  }
49420
51339
  const store = definition.evaluator.store;
49421
51340
  const key = runKey(definition.projectName, definition.evalName, result.runId);
49422
- const state = await readRunState(definition, store, key);
49423
- if (!state) throw new Error(`Durable eval run ${result.runId} is missing`);
49424
- const byBatch = result.batchId ? state.batches.find((candidate) => candidate.id === result.batchId) : void 0;
49425
- const byExternal = result.externalId ? state.batches.find(
49426
- (candidate) => candidate.externalId === result.externalId
51341
+ const run = await readJson(store, key);
51342
+ if (!run) throw new Error(`Workflow eval run ${result.runId} is missing`);
51343
+ const externalSubmissionId = result.externalId ? await readJson(
51344
+ store,
51345
+ `${key}/external/${encodedKeyPart(result.externalId)}`
51346
+ ) : void 0;
51347
+ if (result.submissionId && externalSubmissionId && result.submissionId !== externalSubmissionId) {
51348
+ throw new Error(
51349
+ "submissionId and externalId identify different submissions"
51350
+ );
51351
+ }
51352
+ const submissionId = result.submissionId ?? externalSubmissionId;
51353
+ const submission = submissionId ? await readJson(
51354
+ store,
51355
+ submissionRecordKey(key, submissionId)
49427
51356
  ) : void 0;
49428
- if (byBatch && byExternal && byBatch.id !== byExternal.id) {
49429
- throw new Error("batchId and externalId identify different batches");
49430
- }
49431
- const batch = byBatch ?? byExternal;
49432
- if (!batch) throw new Error("No submitted batch matches this result");
49433
- if (batch.status !== "complete") {
49434
- const records = await collectBatch(definition, state, batch);
49435
- batch.status = "complete";
49436
- await writeCaseRecords(store, key, records);
49437
- await writeBatchRecords(store, key, [batch]);
49438
- }
49439
- return advanceDurableEval(
51357
+ if (!submission) throw new Error("No submission matches this result");
51358
+ if (result.externalId && submission.externalId !== result.externalId) {
51359
+ throw new Error(
51360
+ "submissionId and externalId identify different submissions"
51361
+ );
51362
+ }
51363
+ if (run.status === "completed") return currentStatus(definition, run);
51364
+ const state = await readRunState(definition, store, key, [
51365
+ submission.itemId
51366
+ ]);
51367
+ if (submission.status !== "complete") {
51368
+ const record = await collectSubmission(definition, state, submission);
51369
+ await writeCaseRecords(store, key, [record]);
51370
+ submission.status = "complete";
51371
+ }
51372
+ await writeSubmissionRecords(store, key, [submission]);
51373
+ return advanceWorkflowEval(
49440
51374
  definition,
49441
- await readRunState(definition, store, key),
51375
+ await readRunState(definition, store, key, [submission.itemId]),
49442
51376
  store,
49443
51377
  key
49444
51378
  );
49445
51379
  }
49446
- async function pollDurableEval(definition, options) {
51380
+ async function pollWorkflowEval(definition, options) {
49447
51381
  const store = definition.evaluator.store;
49448
51382
  const key = runKey(
49449
51383
  definition.projectName,
@@ -49451,39 +51385,53 @@ async function pollDurableEval(definition, options) {
49451
51385
  options.runId
49452
51386
  );
49453
51387
  const state = await readRunState(definition, store, key);
49454
- if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
49455
- const batches = state.batches.filter((batch) => {
49456
- if (batch.status === "complete") return false;
49457
- return processorForStage(definition, batch.kind, batch.scorerName).completion.mode === "poll";
49458
- });
49459
- const results = await Promise.all(
49460
- batches.map(async (batch) => ({
49461
- batch,
49462
- result: await processorForStage(definition, batch.kind, batch.scorerName).completion.poll(batch.submissionData, {
49463
- runId: state.runId,
49464
- batchId: batch.id
49465
- })
49466
- }))
49467
- );
49468
- const changedCases = /* @__PURE__ */ new Map();
49469
- const changedBatches = [];
49470
- for (const { batch, result } of results) {
51388
+ if (!state) throw new Error(`Workflow eval run ${options.runId} is missing`);
51389
+ const submissions = state.submissions.filter((submission) => {
51390
+ if (submission.status === "complete") return false;
51391
+ return processorForStage(definition, submission.kind, submission.scorerName).completion.mode === "poll";
51392
+ });
51393
+ const workers = queue(async (submission) => {
51394
+ const completion = processorForStage(
51395
+ definition,
51396
+ submission.kind,
51397
+ submission.scorerName
51398
+ ).completion;
51399
+ if (completion.mode !== "poll") return;
51400
+ const result = await completion.poll(submission.submissionData, {
51401
+ runId: state.runId,
51402
+ submissionId: submission.id
51403
+ });
49471
51404
  if (result.status === "failed") throw asError(result.error);
49472
- if (result.status !== "complete") continue;
49473
- for (const record of await collectBatch(definition, state, batch)) {
49474
- changedCases.set(record.id, record);
49475
- }
49476
- batch.status = "complete";
49477
- changedBatches.push(batch);
49478
- }
49479
- if (changedBatches.length > 0) {
49480
- await writeCaseRecords(store, key, [...changedCases.values()]);
49481
- await writeBatchRecords(store, key, changedBatches);
51405
+ if (result.status === "complete") {
51406
+ const record = await collectSubmission(definition, state, submission);
51407
+ await writeCaseRecords(store, key, [record]);
51408
+ submission.status = "complete";
51409
+ await writeSubmissionRecords(store, key, [submission]);
51410
+ }
51411
+ }, definition.evaluator.maxConcurrency ?? 10);
51412
+ const results = await Promise.allSettled(
51413
+ submissions.map((submission) => workers.pushAsync(submission))
51414
+ );
51415
+ let status;
51416
+ const errors = results.flatMap(
51417
+ (result) => result.status === "rejected" ? [asError(result.reason)] : []
51418
+ );
51419
+ try {
51420
+ status = await advanceWorkflowEval(
51421
+ definition,
51422
+ await readRunState(definition, store, key),
51423
+ store,
51424
+ key
51425
+ );
51426
+ } catch (error) {
51427
+ errors.push(asError(error));
49482
51428
  }
49483
- const currentState = changedBatches.length > 0 ? await readRunState(definition, store, key) : state;
49484
- return advanceDurableEval(definition, currentState, store, key);
51429
+ if (errors.length === 1) throw errors[0];
51430
+ if (errors.length > 1)
51431
+ throw new AggregateError(errors, "Workflow submission callbacks failed");
51432
+ return status;
49485
51433
  }
49486
- async function openDurableExperiment(definition, state) {
51434
+ async function openWorkflowExperiment(definition, state) {
49487
51435
  const data = [];
49488
51436
  return await _internalInitEvaluatorExperiment(
49489
51437
  definition.projectName,
@@ -49496,45 +51444,49 @@ async function openDurableExperiment(definition, state) {
49496
51444
  }
49497
51445
  );
49498
51446
  }
49499
- async function advanceDurableEval(definition, state, store, key, existingExperiment) {
51447
+ async function advanceWorkflowEval(definition, state, store, key, existingExperiment) {
49500
51448
  if (state.status === "completed") return currentStatus(definition, state);
49501
- const experiment = existingExperiment === void 0 ? await openDurableExperiment(definition, state) : existingExperiment;
51449
+ const experiment = existingExperiment === void 0 ? await openWorkflowExperiment(definition, state) : existingExperiment;
51450
+ const caseIds = state.cases.map(({ id }) => id);
49502
51451
  await runTaskStage(definition, state, store, key, experiment);
49503
51452
  await logCompletedTasks(definition, state, store, key, experiment);
49504
- state = await readRunState(definition, store, key) ?? state;
49505
- if (state.cases.some((record) => !record.taskComplete || !record.taskLogged)) {
49506
- return currentStatus(definition, state);
49507
- }
51453
+ state = await readRunState(definition, store, key, caseIds) ?? state;
49508
51454
  await runScoreStages(definition, state, store, key, experiment);
49509
- state = await readRunState(definition, store, key) ?? state;
51455
+ state = await readRunState(definition, store, key, caseIds) ?? state;
49510
51456
  const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
49511
51457
  ({ name }) => name
49512
51458
  );
49513
51459
  const classifierNames = (definition.evaluator.classifiers ?? []).map(
49514
51460
  classifierName
49515
51461
  );
49516
- if (state.cases.some(
49517
- (record) => scorerNames.some(
49518
- (name) => !Object.hasOwn(record.scores, name) || !Object.hasOwn(record.loggedScores, name)
49519
- ) || classifierNames.some(
49520
- (name) => !Object.hasOwn(record.loggedClassifications, name)
49521
- )
49522
- )) {
51462
+ await Promise.all(
51463
+ state.cases.map(async (record) => {
51464
+ if (record.taskComplete && record.taskLogged && scorerNames.every(
51465
+ (name) => Object.hasOwn(record.scores, name) && Object.hasOwn(record.loggedScores, name)
51466
+ ) && classifierNames.every(
51467
+ (name) => Object.hasOwn(record.loggedClassifications, name)
51468
+ )) {
51469
+ await store.addToSet(`${key}/progress/cases`, record.id);
51470
+ }
51471
+ })
51472
+ );
51473
+ if (await store.getSetSize(`${key}/progress/cases`) !== state.caseCount) {
49523
51474
  return currentStatus(definition, state);
49524
51475
  }
49525
51476
  if (!await claimAction(store, key, "finish")) {
49526
- const latest = await readRunState(definition, store, key);
51477
+ const latest = await readJson(store, key);
49527
51478
  return currentStatus(definition, latest ?? state);
49528
51479
  }
51480
+ state = await readRunState(definition, store, key);
49529
51481
  state.summary = await finishExperiment(definition, state, experiment);
49530
51482
  state.status = "completed";
49531
51483
  await writeRunRecord(store, key, state);
49532
51484
  return currentStatus(definition, state);
49533
51485
  }
49534
- function currentStatus(definition, state) {
51486
+ async function currentStatus(definition, state) {
49535
51487
  if (state.status === "completed") {
49536
51488
  if (!state.summary) {
49537
- throw new Error(`Durable eval run ${state.runId} has no saved summary`);
51489
+ throw new Error(`Workflow eval run ${state.runId} has no saved summary`);
49538
51490
  }
49539
51491
  return {
49540
51492
  status: "completed",
@@ -49543,11 +51495,20 @@ function currentStatus(definition, state) {
49543
51495
  summary: state.summary
49544
51496
  };
49545
51497
  }
51498
+ const key = runKey(definition.projectName, definition.evalName, state.runId);
51499
+ const store = definition.evaluator.store;
49546
51500
  const pending = { poll: 0, webhook: 0 };
49547
- for (const batch of state.batches) {
49548
- if (batch.status === "complete") continue;
49549
- pending[processorForStage(definition, batch.kind, batch.scorerName).completion.mode]++;
49550
- }
51501
+ await Promise.all(
51502
+ ["poll", "webhook"].map(async (mode) => {
51503
+ const completed = await store.getSetSize(
51504
+ `${key}/progress/${mode}/complete`
51505
+ );
51506
+ const submitted = await store.getSetSize(
51507
+ `${key}/progress/${mode}/submitted`
51508
+ );
51509
+ pending[mode] = submitted - completed;
51510
+ })
51511
+ );
49551
51512
  return { status: "waiting", runId: state.runId, pending };
49552
51513
  }
49553
51514
  async function startCaseRoot(definition, state, record, experiment) {
@@ -49608,7 +51569,7 @@ async function logTaskResult(definition, state, record, experiment, task) {
49608
51569
  expected: "expected" in datum ? datum.expected : void 0,
49609
51570
  metadata: {
49610
51571
  ...record.metadata,
49611
- durable_eval: {
51572
+ workflow_eval: {
49612
51573
  run_id: state.runId,
49613
51574
  case_id: record.caseId,
49614
51575
  trial_index: record.trialIndex
@@ -49639,8 +51600,8 @@ async function logCompletedTasks(definition, state, store, key, experiment) {
49639
51600
  }
49640
51601
  }
49641
51602
  async function runTaskStage(definition, state, store, key, experiment) {
49642
- if (isBatchTask(definition.evaluator.task)) {
49643
- await ensureBatches(definition, state, store, key, "task");
51603
+ if (isWorkflowTask(definition.evaluator.task)) {
51604
+ await ensureSubmissions(definition, state, store, key, "task");
49644
51605
  return;
49645
51606
  }
49646
51607
  const task = definition.evaluator.task;
@@ -49666,8 +51627,9 @@ async function runScoreStages(definition, state, store, key, experiment) {
49666
51627
  changed.clear();
49667
51628
  };
49668
51629
  for (const { name, scorer } of scorers) {
49669
- if (isBatchScorer(scorer)) {
51630
+ if (isWorkflowScorer(scorer)) {
49670
51631
  for (const record of state.cases) {
51632
+ if (!record.taskComplete || !record.taskLogged) continue;
49671
51633
  if (Object.hasOwn(record.scores, name) && !Object.hasOwn(record.loggedScores, name)) {
49672
51634
  if (!await claimAction(store, key, "score-log", record.id, name)) {
49673
51635
  continue;
@@ -49683,10 +51645,11 @@ async function runScoreStages(definition, state, store, key, experiment) {
49683
51645
  }
49684
51646
  }
49685
51647
  await persistChangedCases();
49686
- await ensureBatches(definition, state, store, key, "score", name);
51648
+ await ensureSubmissions(definition, state, store, key, "score", name);
49687
51649
  continue;
49688
51650
  }
49689
51651
  for (const record of state.cases) {
51652
+ if (!record.taskComplete || !record.taskLogged) continue;
49690
51653
  if (Object.hasOwn(record.loggedScores, name)) continue;
49691
51654
  if (!await claimAction(store, key, "score", record.id, name)) continue;
49692
51655
  await evaluateAndLogScore(
@@ -49703,6 +51666,7 @@ async function runScoreStages(definition, state, store, key, experiment) {
49703
51666
  for (const [index, classifier] of (definition.evaluator.classifiers ?? []).entries()) {
49704
51667
  const name = classifierName(classifier, index);
49705
51668
  for (const record of state.cases) {
51669
+ if (!record.taskComplete || !record.taskLogged) continue;
49706
51670
  if (Object.hasOwn(record.loggedClassifications, name)) continue;
49707
51671
  if (!await claimAction(store, key, "classification", record.id, name)) {
49708
51672
  continue;
@@ -49725,13 +51689,14 @@ function scorerArgs(record) {
49725
51689
  return {
49726
51690
  ...datum,
49727
51691
  metadata: record.metadata,
51692
+ tags: record.tags,
49728
51693
  output: record.output
49729
51694
  };
49730
51695
  }
49731
51696
  function resumeCaseRoot(definition, record, experiment) {
49732
51697
  if (!experiment) return NOOP_SPAN;
49733
51698
  if (!record.rootSpan) {
49734
- throw new Error(`Durable eval case ${record.caseId} has no root span`);
51699
+ throw new Error(`Workflow eval case ${record.caseId} has no root span`);
49735
51700
  }
49736
51701
  return _internalResumeSpan({
49737
51702
  exported: record.rootSpan,
@@ -49819,117 +51784,110 @@ async function evaluateAndLogClassification(definition, state, record, name, cla
49819
51784
  root.end();
49820
51785
  }
49821
51786
  }
49822
- async function ensureBatches(definition, state, store, key, kind, scorerName2) {
51787
+ async function ensureSubmissions(definition, state, store, key, kind, scorerName2) {
49823
51788
  const processor = processorForStage(definition, kind, scorerName2);
49824
- const plans = plannedBatches(
51789
+ const plans = plannedSubmissions(
49825
51790
  definition,
49826
51791
  state.runId,
49827
51792
  state.cases.map(({ id }) => id)
49828
51793
  );
49829
51794
  const casesById = new Map(state.cases.map((record) => [record.id, record]));
49830
- for (const plan of plans) {
49831
- if (plan.kind !== kind || plan.scorerName !== scorerName2) continue;
49832
- if (state.batches.some(({ id }) => id === plan.id)) continue;
49833
- const records = plan.itemIds.map((id) => casesById.get(id));
49834
- const ready = records.every(
49835
- (record) => kind === "task" ? !record.taskComplete : !Object.hasOwn(record.scores, scorerName2)
49836
- );
49837
- if (!ready) continue;
49838
- const batchId = plan.id;
51795
+ const existingIds = new Set(state.submissions.map(({ id }) => id));
51796
+ const workers = queue(async (plan) => {
51797
+ if (plan.kind !== kind || plan.scorerName !== scorerName2) return;
51798
+ if (existingIds.has(plan.id)) return;
51799
+ const record = casesById.get(plan.itemId);
51800
+ const ready = kind === "task" ? !record.taskComplete : record.taskComplete && record.taskLogged && !Object.hasOwn(record.scores, scorerName2);
51801
+ if (!ready) return;
51802
+ const submissionId = plan.id;
49839
51803
  const claim = await store.getOrSet(
49840
- claimRecordKey(key, "batch", batchId),
49841
- encoder.encode(batchId)
49842
- );
49843
- if (!claim.created) continue;
49844
- const context = { runId: state.runId, batchId };
49845
- const items = records.map(
49846
- (record) => kind === "task" ? taskBatchItem(record, state.parameters) : scorerBatchItem(record)
51804
+ claimRecordKey(key, "submission", submissionId),
51805
+ encoder.encode(submissionId)
49847
51806
  );
51807
+ if (!claim.created) return;
51808
+ const context = { runId: state.runId, submissionId };
51809
+ const item = kind === "task" ? taskSubmissionItem(record, state.parameters) : scorerSubmissionItem(record);
49848
51810
  const submissionData = assertJsonValue(
49849
- await processor.submit(items, context),
49850
- `submission data for batch ${batchId}`
51811
+ await processor.submit(item, context),
51812
+ `submission data for submission ${submissionId}`
49851
51813
  );
49852
51814
  const externalId = processor.completion.mode === "webhook" ? processor.completion.getExternalId(submissionData, context) : void 0;
49853
51815
  if (externalId !== void 0 && !externalId.trim()) {
49854
- throw new Error(`Batch ${batchId} produced an empty externalId`);
51816
+ throw new Error(
51817
+ `Submission ${submissionId} produced an empty externalId`
51818
+ );
49855
51819
  }
49856
- const batch = {
49857
- id: batchId,
51820
+ const submission = {
51821
+ id: submissionId,
49858
51822
  kind,
49859
51823
  scorerName: scorerName2,
49860
- itemIds: records.map((record) => record.id),
51824
+ itemId: record.id,
49861
51825
  submissionData,
49862
51826
  externalId,
49863
- status: "submitted"
49864
- };
49865
- state.batches.push(batch);
49866
- await writeBatchRecords(store, key, [batch]);
49867
- }
51827
+ status: "submitted",
51828
+ completionMode: processor.completion.mode
51829
+ };
51830
+ state.submissions.push(submission);
51831
+ await writeSubmissionRecords(store, key, [submission]);
51832
+ }, definition.evaluator.maxConcurrency ?? 10);
51833
+ const results = await Promise.allSettled(
51834
+ plans.map((plan) => workers.pushAsync(plan))
51835
+ );
51836
+ const errors = results.flatMap(
51837
+ (result) => result.status === "rejected" ? [asError(result.reason)] : []
51838
+ );
51839
+ if (errors.length === 1) throw errors[0];
51840
+ if (errors.length > 1)
51841
+ throw new AggregateError(errors, "Workflow submissions failed");
49868
51842
  }
49869
- async function collectBatch(definition, state, batch) {
49870
- const processor = processorForStage(definition, batch.kind, batch.scorerName);
49871
- const context = { runId: state.runId, batchId: batch.id };
49872
- const results = await processor.collect(batch.submissionData, context);
49873
- if (!Array.isArray(results)) {
49874
- throw new Error(`collect for batch ${batch.id} must return an array`);
51843
+ async function collectSubmission(definition, state, submission) {
51844
+ const processor = processorForStage(
51845
+ definition,
51846
+ submission.kind,
51847
+ submission.scorerName
51848
+ );
51849
+ const context = { runId: state.runId, submissionId: submission.id };
51850
+ const result = await processor.collect(submission.submissionData, context);
51851
+ if (typeof result !== "object" || result === null || Array.isArray(result)) {
51852
+ throw new Error(
51853
+ `collect for submission ${submission.id} must return a result object`
51854
+ );
49875
51855
  }
49876
- const expectedIds = new Set(batch.itemIds);
49877
- const seen = /* @__PURE__ */ new Set();
49878
- const records = [];
49879
- for (const result of results) {
49880
- const id = resultItemId(result);
49881
- if (!expectedIds.has(id)) {
49882
- throw new Error(`Batch ${batch.id} returned unknown item ${id}`);
49883
- }
49884
- if (seen.has(id)) {
49885
- throw new Error(`Batch ${batch.id} returned item ${id} more than once`);
49886
- }
49887
- seen.add(id);
49888
- const record = state.cases.find((candidate) => candidate.id === id);
49889
- records.push(record);
49890
- if (batch.kind === "task") {
49891
- record.output = assertJsonValue(
49892
- result.output,
49893
- `task output for item ${id}`
49894
- );
49895
- if ("metadata" in result && result.metadata !== void 0) {
49896
- record.metadata = assertJsonValue(
49897
- {
49898
- ...record.metadata,
49899
- ...result.metadata
49900
- },
49901
- `metadata for ${id}`
49902
- );
49903
- }
49904
- if ("tags" in result && result.tags !== void 0)
49905
- record.tags = result.tags;
49906
- record.taskComplete = true;
49907
- } else {
49908
- record.scores[batch.scorerName] = assertJsonValue(
49909
- result.score,
49910
- `score output for item ${id}`
51856
+ const record = state.cases.find(
51857
+ (candidate) => candidate.id === submission.itemId
51858
+ );
51859
+ if (submission.kind === "task") {
51860
+ record.output = assertJsonValue(
51861
+ result.output,
51862
+ `task output for item ${record.id}`
51863
+ );
51864
+ if (result.metadata !== void 0) {
51865
+ record.metadata = assertJsonValue(
51866
+ { ...record.metadata, ...result.metadata },
51867
+ `metadata for ${record.id}`
49911
51868
  );
49912
51869
  }
49913
- }
49914
- const missing = batch.itemIds.filter((id) => !seen.has(id));
49915
- if (missing.length > 0) {
49916
- throw new Error(
49917
- `Batch ${batch.id} did not return results for: ${missing.join(", ")}`
51870
+ if (result.tags !== void 0) record.tags = result.tags;
51871
+ record.taskComplete = true;
51872
+ } else {
51873
+ record.scores[submission.scorerName] = assertJsonValue(
51874
+ result.score,
51875
+ `score output for item ${record.id}`
49918
51876
  );
49919
51877
  }
49920
- return records;
51878
+ return record;
49921
51879
  }
49922
51880
  function processorForStage(definition, kind, scorerName2) {
49923
51881
  if (kind === "task") {
49924
- if (!isBatchTask(definition.evaluator.task)) {
49925
- throw new Error("Definition no longer contains the batch task");
51882
+ if (!isWorkflowTask(definition.evaluator.task)) {
51883
+ throw new Error("Definition no longer contains the submission task");
49926
51884
  }
49927
51885
  return definition.evaluator.task.processor;
49928
51886
  }
49929
51887
  const scorer = resolveScorers(definition.evaluator.scores ?? []).find(
49930
51888
  ({ name }) => name === scorerName2
49931
51889
  )?.scorer;
49932
- if (!isBatchScorer(scorer)) {
51890
+ if (!isWorkflowScorer(scorer)) {
49933
51891
  throw new Error(`Definition no longer contains scorer ${scorerName2}`);
49934
51892
  }
49935
51893
  return scorer.processor;
@@ -49951,15 +51909,15 @@ async function materializeCases(definition, data, experiment) {
49951
51909
  const caseId = datum.id ?? datum.upsert_id ?? (evaluator.caseId ? await evaluator.caseId(datum) : void 0);
49952
51910
  if (!caseId) {
49953
51911
  throw new Error(
49954
- "Every durable eval case requires id, upsert_id, or caseId"
51912
+ "Every workflow eval case requires id, upsert_id, or caseId"
49955
51913
  );
49956
51914
  }
49957
51915
  if (seen.has(caseId))
49958
- throw new Error(`Duplicate durable eval case id: ${caseId}`);
51916
+ throw new Error(`Duplicate workflow eval case id: ${caseId}`);
49959
51917
  seen.add(caseId);
49960
51918
  const trialCount = datum.trialCount ?? evaluator.trialCount ?? 1;
49961
51919
  if (!Number.isInteger(trialCount) || trialCount < 1) {
49962
- throw new Error(`Invalid trialCount for durable eval case ${caseId}`);
51920
+ throw new Error(`Invalid trialCount for workflow eval case ${caseId}`);
49963
51921
  }
49964
51922
  for (let trialIndex = 0; trialIndex < trialCount; trialIndex++) {
49965
51923
  records.push({
@@ -49983,7 +51941,7 @@ async function materializeCases(definition, data, experiment) {
49983
51941
  }
49984
51942
  return records;
49985
51943
  }
49986
- function taskBatchItem(record, parameters) {
51944
+ function taskSubmissionItem(record, parameters) {
49987
51945
  const datum = record.datum;
49988
51946
  return {
49989
51947
  id: record.id,
@@ -49995,7 +51953,7 @@ function taskBatchItem(record, parameters) {
49995
51953
  trialIndex: record.trialIndex
49996
51954
  };
49997
51955
  }
49998
- function scorerBatchItem(record) {
51956
+ function scorerSubmissionItem(record) {
49999
51957
  const datum = record.datum;
50000
51958
  return {
50001
51959
  id: record.id,
@@ -50066,12 +52024,12 @@ async function finishExperiment(definition, state, experiment) {
50066
52024
  }
50067
52025
  function resolveScorers(scorers) {
50068
52026
  return scorers.map((scorer, index) => ({
50069
- name: isBatchScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
52027
+ name: isWorkflowScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
50070
52028
  scorer
50071
52029
  }));
50072
52030
  }
50073
52031
  function runKey(projectName, evalName, runId) {
50074
- return `durable-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
52032
+ return `workflow-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
50075
52033
  }
50076
52034
  function encodedKeyPart(value) {
50077
52035
  return uint8ArrayToBase64(encoder.encode(value)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
@@ -50080,8 +52038,8 @@ function caseRecordKey(key, caseId, kind, ...names) {
50080
52038
  const suffix = names.map(encodedKeyPart).join("/");
50081
52039
  return `${key}/cases/${encodedKeyPart(caseId)}/${kind}${suffix ? `/${suffix}` : ""}`;
50082
52040
  }
50083
- function batchRecordKey(key, batchId) {
50084
- return `${key}/batches/${encodedKeyPart(batchId)}`;
52041
+ function submissionRecordKey(key, submissionId) {
52042
+ return `${key}/submissions/${encodedKeyPart(submissionId)}`;
50085
52043
  }
50086
52044
  function claimRecordKey(key, kind, ...parts) {
50087
52045
  const identity = stableStringify([kind, parts]);
@@ -50093,33 +52051,24 @@ async function claimAction(store, key, kind, ...parts) {
50093
52051
  encoder.encode("claimed")
50094
52052
  )).created;
50095
52053
  }
50096
- function plannedBatches(definition, runId, caseIds) {
52054
+ function plannedSubmissions(definition, runId, caseIds) {
50097
52055
  const stages = [];
50098
- if (isBatchTask(definition.evaluator.task)) stages.push({ kind: "task" });
52056
+ if (isWorkflowTask(definition.evaluator.task)) stages.push({ kind: "task" });
50099
52057
  for (const { name, scorer } of resolveScorers(
50100
52058
  definition.evaluator.scores ?? []
50101
52059
  )) {
50102
- if (isBatchScorer(scorer)) {
52060
+ if (isWorkflowScorer(scorer)) {
50103
52061
  stages.push({ kind: "score", scorerName: name });
50104
52062
  }
50105
52063
  }
50106
52064
  const plans = [];
50107
52065
  for (const { kind, scorerName: scorerName2 } of stages) {
50108
- const batchSize = processorForStage(definition, kind, scorerName2).batchSize ?? DEFAULT_BATCH_SIZE;
50109
- if (!Number.isInteger(batchSize) || batchSize < 1) {
50110
- throw new Error(
50111
- `Invalid batchSize for ${scorerName2 ?? "task"}: ${batchSize}`
50112
- );
50113
- }
50114
- for (let offset = 0; offset < caseIds.length; offset += batchSize) {
50115
- const itemIds = caseIds.slice(offset, offset + batchSize);
52066
+ for (const itemId of caseIds) {
50116
52067
  plans.push({
50117
- id: deterministicId(
50118
- stableStringify([runId, kind, scorerName2, itemIds])
50119
- ),
52068
+ id: deterministicId(stableStringify([runId, kind, scorerName2, itemId])),
50120
52069
  kind,
50121
52070
  scorerName: scorerName2,
50122
- itemIds
52071
+ itemId
50123
52072
  });
50124
52073
  }
50125
52074
  }
@@ -50179,7 +52128,7 @@ async function readCaseRecord(definition, store, key, id) {
50179
52128
  }))
50180
52129
  )
50181
52130
  ]);
50182
- if (!base) throw new Error(`Durable eval case ${id} is missing`);
52131
+ if (!base) throw new Error(`Workflow eval case ${id} is missing`);
50183
52132
  const scores = /* @__PURE__ */ Object.create(null);
50184
52133
  for (const { name, value } of scoreValues) {
50185
52134
  if (value !== void 0) scores[name] = value;
@@ -50210,32 +52159,34 @@ async function readCaseRecord(definition, store, key, id) {
50210
52159
  loggedClassifications
50211
52160
  };
50212
52161
  }
50213
- async function readRunState(definition, store, key) {
52162
+ async function readRunState(definition, store, key, caseIds) {
50214
52163
  const record = await readJson(store, key);
50215
52164
  if (!record) return void 0;
50216
- const plans = plannedBatches(definition, record.runId, record.caseIds);
50217
- const [cases, batchRecords] = await Promise.all([
52165
+ const selectedIds = caseIds ?? (record.caseCount === 0 ? [] : await readJson(store, `${key}/case-ids`));
52166
+ if (!selectedIds)
52167
+ throw new Error(`Workflow eval run ${record.runId} has no case index`);
52168
+ const plans = plannedSubmissions(definition, record.runId, selectedIds);
52169
+ const [cases, submissionRecords] = await Promise.all([
50218
52170
  Promise.all(
50219
- record.caseIds.map((id) => readCaseRecord(definition, store, key, id))
52171
+ selectedIds.map((id) => readCaseRecord(definition, store, key, id))
50220
52172
  ),
50221
52173
  Promise.all(
50222
52174
  plans.map(async ({ id }) => {
50223
- return readJson(store, batchRecordKey(key, id));
52175
+ return readJson(
52176
+ store,
52177
+ submissionRecordKey(key, id)
52178
+ );
50224
52179
  })
50225
52180
  )
50226
52181
  ]);
50227
- const batches = batchRecords.filter(
52182
+ const submissions = submissionRecords.filter(
50228
52183
  (value) => value !== void 0
50229
52184
  );
50230
- const { caseIds: _caseIds, ...state } = record;
50231
- return { ...state, cases, batches };
52185
+ return { ...record, cases, submissions };
50232
52186
  }
50233
52187
  async function writeRunRecord(store, key, state) {
50234
- const { cases, batches: _batches, ...record } = state;
50235
- await writeJson(store, key, {
50236
- ...record,
50237
- caseIds: cases.map(({ id }) => id)
50238
- });
52188
+ const { cases: _cases, submissions: _submissions, ...record } = state;
52189
+ await writeJson(store, key, record);
50239
52190
  }
50240
52191
  async function writeCaseBaseRecords(store, key, records) {
50241
52192
  await Promise.all(
@@ -50307,11 +52258,25 @@ async function writeCaseRecords(store, key, records) {
50307
52258
  }
50308
52259
  await Promise.all(writes);
50309
52260
  }
50310
- async function writeBatchRecords(store, key, records) {
52261
+ async function writeSubmissionRecords(store, key, records) {
50311
52262
  await Promise.all(
50312
- records.map(
50313
- (record) => writeJson(store, batchRecordKey(key, record.id), record)
50314
- )
52263
+ records.map(async (record) => {
52264
+ if (record.externalId !== void 0) {
52265
+ const locator = await store.getOrSet(
52266
+ `${key}/external/${encodedKeyPart(record.externalId)}`,
52267
+ encoder.encode(JSON.stringify(record.id))
52268
+ );
52269
+ if (JSON.parse(decoder.decode(locator.value)) !== record.id) {
52270
+ throw new Error(`Duplicate externalId: ${record.externalId}`);
52271
+ }
52272
+ }
52273
+ const progressKey = `${key}/progress/${record.completionMode}`;
52274
+ await store.addToSet(`${progressKey}/submitted`, record.id);
52275
+ if (record.status === "complete") {
52276
+ await store.addToSet(`${progressKey}/complete`, record.id);
52277
+ }
52278
+ await writeJson(store, submissionRecordKey(key, record.id), record);
52279
+ })
50315
52280
  );
50316
52281
  }
50317
52282
  function deterministicId(value) {
@@ -50356,17 +52321,11 @@ function assertJsonValue(value, label) {
50356
52321
  throw new Error(`${label} must be JSON serializable`, { cause: error });
50357
52322
  }
50358
52323
  }
50359
- function resultItemId(value) {
50360
- if (typeof value !== "object" || value === null || !("id" in value) || typeof value.id !== "string") {
50361
- throw new Error("Batch results must contain a string id");
50362
- }
50363
- return value.id;
50364
- }
50365
- function isBatchTask(value) {
50366
- return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_TASK_KIND;
52324
+ function isWorkflowTask(value) {
52325
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === WORKFLOW_TASK_KIND;
50367
52326
  }
50368
- function isBatchScorer(value) {
50369
- return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_SCORER_KIND;
52327
+ function isWorkflowScorer(value) {
52328
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === WORKFLOW_SCORER_KIND;
50370
52329
  }
50371
52330
  function asError(error) {
50372
52331
  return error instanceof Error ? error : new Error(String(error));
@@ -51294,13 +53253,13 @@ var evaluatorDefinitionsSchema = z13.record(
51294
53253
  );
51295
53254
 
51296
53255
  // src/wrappers/elevenlabs.ts
51297
- var clients = /* @__PURE__ */ new WeakMap();
53256
+ var clients2 = /* @__PURE__ */ new WeakMap();
51298
53257
  function wrapElevenLabs(client) {
51299
53258
  if (!isObject(client) || !isObject(client.textToSpeech) || typeof client.textToSpeech.convert !== "function") {
51300
53259
  debugLogger.warn("Unsupported ElevenLabs client. Not wrapping.");
51301
53260
  return client;
51302
53261
  }
51303
- const cached = clients.get(client);
53262
+ const cached = clients2.get(client);
51304
53263
  if (cached) return cached;
51305
53264
  const sdk = client;
51306
53265
  const speech = new Proxy(sdk.textToSpeech, {
@@ -51347,8 +53306,8 @@ function wrapElevenLabs(client) {
51347
53306
  return Reflect.get(target, prop, receiver);
51348
53307
  }
51349
53308
  });
51350
- clients.set(client, proxy);
51351
- clients.set(proxy, proxy);
53309
+ clients2.set(client, proxy);
53310
+ clients2.set(proxy, proxy);
51352
53311
  return proxy;
51353
53312
  }
51354
53313
 
@@ -51363,8 +53322,6 @@ export {
51363
53322
  BRAINTRUST_PARENT_KEY,
51364
53323
  BaseAttachment,
51365
53324
  BaseExperiment,
51366
- BatchScorer,
51367
- BatchTask,
51368
53325
  BraintrustLangChainCallbackHandler,
51369
53326
  BraintrustMiddleware,
51370
53327
  BraintrustObservabilityExporter,
@@ -51378,8 +53335,6 @@ export {
51378
53335
  DEFAULT_MAX_REQUEST_SIZE,
51379
53336
  Dataset2 as Dataset,
51380
53337
  DatasetPipeline,
51381
- DurableEvalMemoryStore,
51382
- DurableEvalRedisStore,
51383
53338
  ERR_PERMALINK,
51384
53339
  Eval,
51385
53340
  EvalResultWithSummary,
@@ -51414,6 +53369,10 @@ export {
51414
53369
  TestBackgroundLogger,
51415
53370
  ToolBuilder,
51416
53371
  UUIDGenerator,
53372
+ WorkflowEvalMemoryStore,
53373
+ WorkflowEvalRedisStore,
53374
+ WorkflowScorer,
53375
+ WorkflowTask,
51417
53376
  X_CACHED_HEADER,
51418
53377
  _exportsForTestingOnly,
51419
53378
  _internalGetGlobalState,
@@ -51439,12 +53398,13 @@ export {
51439
53398
  deepCopyEvent,
51440
53399
  exports_exports as default,
51441
53400
  defaultErrorScoreHandler,
51442
- defineDurableEval,
53401
+ defineWorkflowEval,
51443
53402
  deserializePlainStringAsJSON,
51444
53403
  devNullWritableStream,
51445
53404
  evaluatorDefinitionSchema,
51446
53405
  evaluatorDefinitionsSchema,
51447
53406
  extractTraceContextFromHeaders,
53407
+ failOpenAIAgentsTrace,
51448
53408
  flush,
51449
53409
  getContextManager,
51450
53410
  getIdGenerator,
@@ -51491,12 +53451,14 @@ export {
51491
53451
  setFetch,
51492
53452
  setMaskingFunction,
51493
53453
  spanComponentsToObjectId,
53454
+ startOpenAIAgentsTrace,
51494
53455
  startSpan,
51495
53456
  summarize,
51496
53457
  templateRegistry,
51497
53458
  ToolFunctionDefinition as toolFunctionDefinitionSchema,
51498
53459
  traceable,
51499
53460
  traced,
53461
+ updateOpenAIAgentsTrace,
51500
53462
  updateSpan,
51501
53463
  uploadLogs3OverflowPayload,
51502
53464
  utf8ByteLength2 as utf8ByteLength,
@@ -51525,6 +53487,7 @@ export {
51525
53487
  wrapGroq,
51526
53488
  wrapHuggingFace,
51527
53489
  wrapHuggingFaceTransformers,
53490
+ wrapLangGraphSDK,
51528
53491
  wrapLangSmithClient,
51529
53492
  wrapLangSmithRunTrees,
51530
53493
  wrapLangSmithTraceable,