@brizz/sdk 0.1.26 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -305,7 +305,7 @@ var init_schemas = __esm({
305
305
  });
306
306
 
307
307
  // src/internal/semantic-conventions.ts
308
- var import_api3, BRIZZ, PROPERTIES, SESSION_ID, PROPERTIES_CONTEXT_KEY, SESSION_OBJECT_CONTEXT_KEY, SESSION_INPUT, SESSION_OUTPUT, SESSION_INPUT_CONTEXT, SESSION_OUTPUT_CONTEXT, SESSION_SPAN_NAME, SESSION_TITLE_SPAN_NAME, SESSION_TITLE_GENERATION, SESSION_TITLE;
308
+ var import_api3, BRIZZ, PROPERTIES, SESSION_ID, PROPERTIES_CONTEXT_KEY, SESSION_OBJECT_CONTEXT_KEY, SESSION_INPUT, SESSION_OUTPUT, SESSION_INPUT_CONTEXT, SESSION_OUTPUT_CONTEXT, SESSION_SPAN_NAME, SESSION_TITLE_SPAN_NAME, SESSION_TITLE_GENERATION, SESSION_TITLE, INTERRUPT_TOOLS;
309
309
  var init_semantic_conventions2 = __esm({
310
310
  "src/internal/semantic-conventions.ts"() {
311
311
  "use strict";
@@ -323,6 +323,7 @@ var init_semantic_conventions2 = __esm({
323
323
  SESSION_TITLE_SPAN_NAME = "brizz.session_title";
324
324
  SESSION_TITLE_GENERATION = "session.title_generation";
325
325
  SESSION_TITLE = "brizz.session.title";
326
+ INTERRUPT_TOOLS = "brizz.internal.interrupt";
326
327
  }
327
328
  });
328
329
 
@@ -790,7 +791,7 @@ var init_protocol = __esm({
790
791
 
791
792
  // src/internal/version.ts
792
793
  function getSDKVersion() {
793
- return "0.1.26";
794
+ return "0.1.27";
794
795
  }
795
796
  var init_version = __esm({
796
797
  "src/internal/version.ts"() {
@@ -972,6 +973,100 @@ var init_mcp = __esm({
972
973
  }
973
974
  });
974
975
 
976
+ // src/internal/instrumentation/vercel-ai/interrupt.ts
977
+ var interrupt_exports = {};
978
+ __export(interrupt_exports, {
979
+ InterruptPropagator: () => InterruptPropagator,
980
+ _resetInterruptState: () => _resetInterruptState,
981
+ createInterruptIntegration: () => createInterruptIntegration
982
+ });
983
+ function isInnerLLMSpan(span) {
984
+ if (INNER_OPERATION_IDS.has(span.name)) {
985
+ return true;
986
+ }
987
+ const opId = span.attributes["ai.operationId"];
988
+ return typeof opId === "string" && INNER_OPERATION_IDS.has(opId);
989
+ }
990
+ function setPending(parentSpanId, value) {
991
+ pendingByParentSpanId.set(parentSpanId, value);
992
+ while (pendingByParentSpanId.size > MAX_PENDING_ENTRIES) {
993
+ const oldest = pendingByParentSpanId.keys().next().value;
994
+ if (oldest === void 0) {
995
+ break;
996
+ }
997
+ pendingByParentSpanId.delete(oldest);
998
+ }
999
+ }
1000
+ function extractInterruptTools(tools) {
1001
+ if (!tools || typeof tools !== "object") {
1002
+ return [];
1003
+ }
1004
+ return Object.entries(tools).filter(
1005
+ ([, t]) => !!t && typeof t === "object" && t.needsApproval
1006
+ ).map(([name]) => name);
1007
+ }
1008
+ function createInterruptIntegration() {
1009
+ const onStepStart = (event) => {
1010
+ const names = extractInterruptTools(event.tools);
1011
+ if (names.length === 0) {
1012
+ return;
1013
+ }
1014
+ const value = JSON.stringify(names);
1015
+ const span = import_api8.trace.getActiveSpan();
1016
+ if (!span) {
1017
+ return;
1018
+ }
1019
+ span.setAttribute(INTERRUPT_TOOLS, value);
1020
+ setPending(span.spanContext().spanId, value);
1021
+ };
1022
+ return {
1023
+ onStepStart
1024
+ };
1025
+ }
1026
+ function _resetInterruptState() {
1027
+ if (process.env["NODE_ENV"] !== "test") {
1028
+ return;
1029
+ }
1030
+ pendingByParentSpanId.clear();
1031
+ }
1032
+ var import_api8, INNER_OPERATION_IDS, MAX_PENDING_ENTRIES, pendingByParentSpanId, InterruptPropagator;
1033
+ var init_interrupt = __esm({
1034
+ "src/internal/instrumentation/vercel-ai/interrupt.ts"() {
1035
+ "use strict";
1036
+ import_api8 = require("@opentelemetry/api");
1037
+ init_semantic_conventions2();
1038
+ INNER_OPERATION_IDS = /* @__PURE__ */ new Set([
1039
+ "ai.generateText.doGenerate",
1040
+ "ai.streamText.doStream"
1041
+ ]);
1042
+ MAX_PENDING_ENTRIES = 1024;
1043
+ pendingByParentSpanId = /* @__PURE__ */ new Map();
1044
+ InterruptPropagator = class {
1045
+ onStart(span, _parentContext) {
1046
+ if (!isInnerLLMSpan(span)) {
1047
+ return;
1048
+ }
1049
+ const parentSpanId = span.parentSpanContext?.spanId;
1050
+ if (!parentSpanId) {
1051
+ return;
1052
+ }
1053
+ const value = pendingByParentSpanId.get(parentSpanId);
1054
+ if (!value) {
1055
+ return;
1056
+ }
1057
+ span.setAttribute(INTERRUPT_TOOLS, value);
1058
+ pendingByParentSpanId.delete(parentSpanId);
1059
+ }
1060
+ onEnd() {
1061
+ }
1062
+ async shutdown() {
1063
+ }
1064
+ async forceFlush() {
1065
+ }
1066
+ };
1067
+ }
1068
+ });
1069
+
975
1070
  // src/index.ts
976
1071
  var src_exports = {};
977
1072
  __export(src_exports, {
@@ -1084,6 +1179,26 @@ function loadMCPInstrumentation() {
1084
1179
  }
1085
1180
  })();
1086
1181
  }
1182
+ function loadVercelAIInterruptIntegration() {
1183
+ void (async () => {
1184
+ try {
1185
+ const ai = await import("ai");
1186
+ if (typeof ai.registerTelemetryIntegration !== "function") {
1187
+ logger.debug(
1188
+ "AI SDK present but lacks registerTelemetryIntegration (needs ai@>=6); skipping interrupt bridge"
1189
+ );
1190
+ return;
1191
+ }
1192
+ const { createInterruptIntegration: createInterruptIntegration2 } = await Promise.resolve().then(() => (init_interrupt(), interrupt_exports));
1193
+ ai.registerTelemetryIntegration(createInterruptIntegration2());
1194
+ logger.debug("Auto-loaded Vercel AI interrupt bridge");
1195
+ } catch (error) {
1196
+ logger.debug(
1197
+ `Vercel AI interrupt bridge not loaded (install ai@>=6 if you want HITL attribution): ${String(error)}`
1198
+ );
1199
+ }
1200
+ })();
1201
+ }
1087
1202
  function autoInitializeInstrumentations() {
1088
1203
  if (autoInstrumentationsLoaded) {
1089
1204
  return;
@@ -1092,6 +1207,7 @@ function autoInitializeInstrumentations() {
1092
1207
  const nodeInstrumentations = loadNodeAutoInstrumentations();
1093
1208
  const genAIInstrumentations = loadGenAIInstrumentations();
1094
1209
  loadMCPInstrumentation();
1210
+ loadVercelAIInterruptIntegration();
1095
1211
  autoInstrumentationsLoaded = true;
1096
1212
  logger.info(
1097
1213
  `Auto-initialization complete: ${nodeInstrumentations.length} node + ${genAIInstrumentations.length} GenAI instrumentations`
@@ -1406,6 +1522,9 @@ var InstrumentationRegistry = class _InstrumentationRegistry {
1406
1522
  }
1407
1523
  };
1408
1524
 
1525
+ // src/internal/sdk.ts
1526
+ init_interrupt();
1527
+
1409
1528
  // src/internal/log/logging.ts
1410
1529
  var import_api_logs = require("@opentelemetry/api-logs");
1411
1530
  var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
@@ -1415,7 +1534,7 @@ init_logger();
1415
1534
  init_version();
1416
1535
 
1417
1536
  // src/internal/log/processors/log-processor.ts
1418
- var import_api8 = require("@opentelemetry/api");
1537
+ var import_api9 = require("@opentelemetry/api");
1419
1538
  var import_sdk_logs = require("@opentelemetry/sdk-logs");
1420
1539
  init_logger();
1421
1540
 
@@ -1847,7 +1966,7 @@ var BrizzSimpleLogRecordProcessor = class extends import_sdk_logs.SimpleLogRecor
1847
1966
  if (maskingConfig) {
1848
1967
  maskLog(logRecord, maskingConfig);
1849
1968
  }
1850
- const associationProperties = import_api8.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1969
+ const associationProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1851
1970
  if (associationProperties) {
1852
1971
  for (const [key, value] of Object.entries(associationProperties)) {
1853
1972
  logRecord.setAttribute(`${BRIZZ}.${key}`, value);
@@ -1867,7 +1986,7 @@ var BrizzBatchLogRecordProcessor = class extends import_sdk_logs.BatchLogRecordP
1867
1986
  if (maskingConfig) {
1868
1987
  maskLog(logRecord, maskingConfig);
1869
1988
  }
1870
- const associationProperties = import_api8.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1989
+ const associationProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1871
1990
  if (associationProperties) {
1872
1991
  for (const [key, value] of Object.entries(associationProperties)) {
1873
1992
  logRecord.setAttribute(`${BRIZZ}.${key}`, value);
@@ -2267,12 +2386,12 @@ var BrizzSpanExporter = class {
2267
2386
  };
2268
2387
 
2269
2388
  // src/internal/trace/processors/span-processor.ts
2270
- var import_api9 = require("@opentelemetry/api");
2389
+ var import_api10 = require("@opentelemetry/api");
2271
2390
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
2272
2391
  init_logger();
2273
2392
  init_semantic_conventions2();
2274
2393
  function applyContextAttributes(span) {
2275
- const sessionProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2394
+ const sessionProperties = import_api10.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2276
2395
  if (sessionProperties) {
2277
2396
  for (const [key, value] of Object.entries(sessionProperties)) {
2278
2397
  span.setAttribute(`${BRIZZ}.${key}`, value);
@@ -2458,10 +2577,10 @@ function getSpanProcessor() {
2458
2577
  }
2459
2578
 
2460
2579
  // src/internal/trace/session.ts
2461
- var import_api10 = require("@opentelemetry/api");
2580
+ var import_api11 = require("@opentelemetry/api");
2462
2581
  init_semantic_conventions2();
2463
2582
  function setCurrentSpanCustomProperties(properties) {
2464
- const current = import_api10.trace.getActiveSpan();
2583
+ const current = import_api11.trace.getActiveSpan();
2465
2584
  if (!current || !current.isRecording()) {
2466
2585
  return;
2467
2586
  }
@@ -2473,11 +2592,11 @@ function setCurrentSpanCustomProperties(properties) {
2473
2592
  }
2474
2593
  }
2475
2594
  function callWithProperties(properties, fn, thisArg, ...args) {
2476
- const base = import_api10.context.active();
2595
+ const base = import_api11.context.active();
2477
2596
  const prev = base.getValue(PROPERTIES_CONTEXT_KEY);
2478
2597
  const merged = prev ? { ...prev, ...properties } : properties;
2479
2598
  const next = base.setValue(PROPERTIES_CONTEXT_KEY, merged);
2480
- return import_api10.context.with(next, fn, thisArg, ...args);
2599
+ return import_api11.context.with(next, fn, thisArg, ...args);
2481
2600
  }
2482
2601
  function withProperties(properties, fn, thisArg) {
2483
2602
  return function wrapped(...args) {
@@ -2576,12 +2695,12 @@ var SessionTitle = class {
2576
2695
  }
2577
2696
  };
2578
2697
  function getActiveSession() {
2579
- return import_api10.context.active().getValue(SESSION_OBJECT_CONTEXT_KEY);
2698
+ return import_api11.context.active().getValue(SESSION_OBJECT_CONTEXT_KEY);
2580
2699
  }
2581
2700
  function startSession(sessionId, callback, extraProperties, options) {
2582
2701
  const isTitle = options?.mode === "title";
2583
2702
  const spanName = isTitle ? SESSION_TITLE_SPAN_NAME : SESSION_SPAN_NAME;
2584
- const tracer = import_api10.trace.getTracer("@brizz/sdk");
2703
+ const tracer = import_api11.trace.getTracer("@brizz/sdk");
2585
2704
  return tracer.startActiveSpan(spanName, (span) => {
2586
2705
  span.setAttribute(`${BRIZZ}.${SESSION_ID}`, sessionId);
2587
2706
  if (extraProperties) {
@@ -2600,8 +2719,8 @@ function startSession(sessionId, callback, extraProperties, options) {
2600
2719
  }
2601
2720
  }
2602
2721
  return callWithProperties(contextProperties, () => {
2603
- const sessionCtx = import_api10.context.active().setValue(SESSION_OBJECT_CONTEXT_KEY, session);
2604
- return import_api10.context.with(sessionCtx, () => {
2722
+ const sessionCtx = import_api11.context.active().setValue(SESSION_OBJECT_CONTEXT_KEY, session);
2723
+ return import_api11.context.with(sessionCtx, () => {
2605
2724
  try {
2606
2725
  const result = callback(session);
2607
2726
  if (result && typeof result.then === "function") {
@@ -2610,7 +2729,7 @@ function startSession(sessionId, callback, extraProperties, options) {
2610
2729
  return value;
2611
2730
  }).catch((error) => {
2612
2731
  span.recordException(error);
2613
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2732
+ span.setStatus({ code: import_api11.SpanStatusCode.ERROR });
2614
2733
  span.end();
2615
2734
  throw error;
2616
2735
  });
@@ -2619,7 +2738,7 @@ function startSession(sessionId, callback, extraProperties, options) {
2619
2738
  return result;
2620
2739
  } catch (error) {
2621
2740
  span.recordException(error);
2622
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2741
+ span.setStatus({ code: import_api11.SpanStatusCode.ERROR });
2623
2742
  span.end();
2624
2743
  throw error;
2625
2744
  }
@@ -2629,7 +2748,7 @@ function startSession(sessionId, callback, extraProperties, options) {
2629
2748
  }
2630
2749
  function startSessionTitle(callback, options) {
2631
2750
  const resolvedSessionId = options?.sessionId ?? getActiveSession()?.sessionId;
2632
- const tracer = import_api10.trace.getTracer("@brizz/sdk");
2751
+ const tracer = import_api11.trace.getTracer("@brizz/sdk");
2633
2752
  return tracer.startActiveSpan(SESSION_TITLE_SPAN_NAME, (span) => {
2634
2753
  if (resolvedSessionId) {
2635
2754
  span.setAttribute(`${BRIZZ}.${SESSION_ID}`, resolvedSessionId);
@@ -2648,7 +2767,7 @@ function startSessionTitle(callback, options) {
2648
2767
  return value;
2649
2768
  }).catch((error) => {
2650
2769
  span.recordException(error);
2651
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2770
+ span.setStatus({ code: import_api11.SpanStatusCode.ERROR });
2652
2771
  span.end();
2653
2772
  throw error;
2654
2773
  });
@@ -2657,7 +2776,7 @@ function startSessionTitle(callback, options) {
2657
2776
  return result;
2658
2777
  } catch (error) {
2659
2778
  span.recordException(error);
2660
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2779
+ span.setStatus({ code: import_api11.SpanStatusCode.ERROR });
2661
2780
  span.end();
2662
2781
  throw error;
2663
2782
  }
@@ -2749,7 +2868,7 @@ var _Brizz = class __Brizz {
2749
2868
  resourceAttributes["service.version"] = resolvedConfig.appVersion;
2750
2869
  }
2751
2870
  this._sdk = new import_sdk_node.NodeSDK({
2752
- spanProcessors: resolvedConfig.disableSpanExporter ? [] : [getSpanProcessor()],
2871
+ spanProcessors: resolvedConfig.disableSpanExporter ? [] : [new InterruptPropagator(), getSpanProcessor()],
2753
2872
  metricReader: getMetricsReader(),
2754
2873
  resource: (0, import_resources3.resourceFromAttributes)(resourceAttributes),
2755
2874
  instrumentations: manualInstrumentations
package/dist/index.js CHANGED
@@ -290,7 +290,7 @@ var init_schemas = __esm({
290
290
 
291
291
  // src/internal/semantic-conventions.ts
292
292
  import { createContextKey } from "@opentelemetry/api";
293
- var BRIZZ, PROPERTIES, SESSION_ID, PROPERTIES_CONTEXT_KEY, SESSION_OBJECT_CONTEXT_KEY, SESSION_INPUT, SESSION_OUTPUT, SESSION_INPUT_CONTEXT, SESSION_OUTPUT_CONTEXT, SESSION_SPAN_NAME, SESSION_TITLE_SPAN_NAME, SESSION_TITLE_GENERATION, SESSION_TITLE;
293
+ var BRIZZ, PROPERTIES, SESSION_ID, PROPERTIES_CONTEXT_KEY, SESSION_OBJECT_CONTEXT_KEY, SESSION_INPUT, SESSION_OUTPUT, SESSION_INPUT_CONTEXT, SESSION_OUTPUT_CONTEXT, SESSION_SPAN_NAME, SESSION_TITLE_SPAN_NAME, SESSION_TITLE_GENERATION, SESSION_TITLE, INTERRUPT_TOOLS;
294
294
  var init_semantic_conventions2 = __esm({
295
295
  "src/internal/semantic-conventions.ts"() {
296
296
  "use strict";
@@ -307,6 +307,7 @@ var init_semantic_conventions2 = __esm({
307
307
  SESSION_TITLE_SPAN_NAME = "brizz.session_title";
308
308
  SESSION_TITLE_GENERATION = "session.title_generation";
309
309
  SESSION_TITLE = "brizz.session.title";
310
+ INTERRUPT_TOOLS = "brizz.internal.interrupt";
310
311
  }
311
312
  });
312
313
 
@@ -772,7 +773,7 @@ var init_protocol = __esm({
772
773
 
773
774
  // src/internal/version.ts
774
775
  function getSDKVersion() {
775
- return "0.1.26";
776
+ return "0.1.27";
776
777
  }
777
778
  var init_version = __esm({
778
779
  "src/internal/version.ts"() {
@@ -954,6 +955,100 @@ var init_mcp = __esm({
954
955
  }
955
956
  });
956
957
 
958
+ // src/internal/instrumentation/vercel-ai/interrupt.ts
959
+ var interrupt_exports = {};
960
+ __export(interrupt_exports, {
961
+ InterruptPropagator: () => InterruptPropagator,
962
+ _resetInterruptState: () => _resetInterruptState,
963
+ createInterruptIntegration: () => createInterruptIntegration
964
+ });
965
+ import { trace as trace3 } from "@opentelemetry/api";
966
+ function isInnerLLMSpan(span) {
967
+ if (INNER_OPERATION_IDS.has(span.name)) {
968
+ return true;
969
+ }
970
+ const opId = span.attributes["ai.operationId"];
971
+ return typeof opId === "string" && INNER_OPERATION_IDS.has(opId);
972
+ }
973
+ function setPending(parentSpanId, value) {
974
+ pendingByParentSpanId.set(parentSpanId, value);
975
+ while (pendingByParentSpanId.size > MAX_PENDING_ENTRIES) {
976
+ const oldest = pendingByParentSpanId.keys().next().value;
977
+ if (oldest === void 0) {
978
+ break;
979
+ }
980
+ pendingByParentSpanId.delete(oldest);
981
+ }
982
+ }
983
+ function extractInterruptTools(tools) {
984
+ if (!tools || typeof tools !== "object") {
985
+ return [];
986
+ }
987
+ return Object.entries(tools).filter(
988
+ ([, t]) => !!t && typeof t === "object" && t.needsApproval
989
+ ).map(([name]) => name);
990
+ }
991
+ function createInterruptIntegration() {
992
+ const onStepStart = (event) => {
993
+ const names = extractInterruptTools(event.tools);
994
+ if (names.length === 0) {
995
+ return;
996
+ }
997
+ const value = JSON.stringify(names);
998
+ const span = trace3.getActiveSpan();
999
+ if (!span) {
1000
+ return;
1001
+ }
1002
+ span.setAttribute(INTERRUPT_TOOLS, value);
1003
+ setPending(span.spanContext().spanId, value);
1004
+ };
1005
+ return {
1006
+ onStepStart
1007
+ };
1008
+ }
1009
+ function _resetInterruptState() {
1010
+ if (process.env["NODE_ENV"] !== "test") {
1011
+ return;
1012
+ }
1013
+ pendingByParentSpanId.clear();
1014
+ }
1015
+ var INNER_OPERATION_IDS, MAX_PENDING_ENTRIES, pendingByParentSpanId, InterruptPropagator;
1016
+ var init_interrupt = __esm({
1017
+ "src/internal/instrumentation/vercel-ai/interrupt.ts"() {
1018
+ "use strict";
1019
+ init_semantic_conventions2();
1020
+ INNER_OPERATION_IDS = /* @__PURE__ */ new Set([
1021
+ "ai.generateText.doGenerate",
1022
+ "ai.streamText.doStream"
1023
+ ]);
1024
+ MAX_PENDING_ENTRIES = 1024;
1025
+ pendingByParentSpanId = /* @__PURE__ */ new Map();
1026
+ InterruptPropagator = class {
1027
+ onStart(span, _parentContext) {
1028
+ if (!isInnerLLMSpan(span)) {
1029
+ return;
1030
+ }
1031
+ const parentSpanId = span.parentSpanContext?.spanId;
1032
+ if (!parentSpanId) {
1033
+ return;
1034
+ }
1035
+ const value = pendingByParentSpanId.get(parentSpanId);
1036
+ if (!value) {
1037
+ return;
1038
+ }
1039
+ span.setAttribute(INTERRUPT_TOOLS, value);
1040
+ pendingByParentSpanId.delete(parentSpanId);
1041
+ }
1042
+ onEnd() {
1043
+ }
1044
+ async shutdown() {
1045
+ }
1046
+ async forceFlush() {
1047
+ }
1048
+ };
1049
+ }
1050
+ });
1051
+
957
1052
  // src/internal/instrumentation/auto-init.ts
958
1053
  init_logger();
959
1054
  import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
@@ -1034,6 +1129,26 @@ function loadMCPInstrumentation() {
1034
1129
  }
1035
1130
  })();
1036
1131
  }
1132
+ function loadVercelAIInterruptIntegration() {
1133
+ void (async () => {
1134
+ try {
1135
+ const ai = await import("ai");
1136
+ if (typeof ai.registerTelemetryIntegration !== "function") {
1137
+ logger.debug(
1138
+ "AI SDK present but lacks registerTelemetryIntegration (needs ai@>=6); skipping interrupt bridge"
1139
+ );
1140
+ return;
1141
+ }
1142
+ const { createInterruptIntegration: createInterruptIntegration2 } = await Promise.resolve().then(() => (init_interrupt(), interrupt_exports));
1143
+ ai.registerTelemetryIntegration(createInterruptIntegration2());
1144
+ logger.debug("Auto-loaded Vercel AI interrupt bridge");
1145
+ } catch (error) {
1146
+ logger.debug(
1147
+ `Vercel AI interrupt bridge not loaded (install ai@>=6 if you want HITL attribution): ${String(error)}`
1148
+ );
1149
+ }
1150
+ })();
1151
+ }
1037
1152
  function autoInitializeInstrumentations() {
1038
1153
  if (autoInstrumentationsLoaded) {
1039
1154
  return;
@@ -1042,6 +1157,7 @@ function autoInitializeInstrumentations() {
1042
1157
  const nodeInstrumentations = loadNodeAutoInstrumentations();
1043
1158
  const genAIInstrumentations = loadGenAIInstrumentations();
1044
1159
  loadMCPInstrumentation();
1160
+ loadVercelAIInterruptIntegration();
1045
1161
  autoInstrumentationsLoaded = true;
1046
1162
  logger.info(
1047
1163
  `Auto-initialization complete: ${nodeInstrumentations.length} node + ${genAIInstrumentations.length} GenAI instrumentations`
@@ -1356,6 +1472,9 @@ var InstrumentationRegistry = class _InstrumentationRegistry {
1356
1472
  }
1357
1473
  };
1358
1474
 
1475
+ // src/internal/sdk.ts
1476
+ init_interrupt();
1477
+
1359
1478
  // src/internal/log/logging.ts
1360
1479
  import { SeverityNumber } from "@opentelemetry/api-logs";
1361
1480
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
@@ -2414,9 +2533,9 @@ function getSpanProcessor() {
2414
2533
 
2415
2534
  // src/internal/trace/session.ts
2416
2535
  init_semantic_conventions2();
2417
- import { context as context5, trace as trace3, SpanStatusCode as SpanStatusCode3 } from "@opentelemetry/api";
2536
+ import { context as context5, trace as trace4, SpanStatusCode as SpanStatusCode3 } from "@opentelemetry/api";
2418
2537
  function setCurrentSpanCustomProperties(properties) {
2419
- const current = trace3.getActiveSpan();
2538
+ const current = trace4.getActiveSpan();
2420
2539
  if (!current || !current.isRecording()) {
2421
2540
  return;
2422
2541
  }
@@ -2536,7 +2655,7 @@ function getActiveSession() {
2536
2655
  function startSession(sessionId, callback, extraProperties, options) {
2537
2656
  const isTitle = options?.mode === "title";
2538
2657
  const spanName = isTitle ? SESSION_TITLE_SPAN_NAME : SESSION_SPAN_NAME;
2539
- const tracer = trace3.getTracer("@brizz/sdk");
2658
+ const tracer = trace4.getTracer("@brizz/sdk");
2540
2659
  return tracer.startActiveSpan(spanName, (span) => {
2541
2660
  span.setAttribute(`${BRIZZ}.${SESSION_ID}`, sessionId);
2542
2661
  if (extraProperties) {
@@ -2584,7 +2703,7 @@ function startSession(sessionId, callback, extraProperties, options) {
2584
2703
  }
2585
2704
  function startSessionTitle(callback, options) {
2586
2705
  const resolvedSessionId = options?.sessionId ?? getActiveSession()?.sessionId;
2587
- const tracer = trace3.getTracer("@brizz/sdk");
2706
+ const tracer = trace4.getTracer("@brizz/sdk");
2588
2707
  return tracer.startActiveSpan(SESSION_TITLE_SPAN_NAME, (span) => {
2589
2708
  if (resolvedSessionId) {
2590
2709
  span.setAttribute(`${BRIZZ}.${SESSION_ID}`, resolvedSessionId);
@@ -2704,7 +2823,7 @@ var _Brizz = class __Brizz {
2704
2823
  resourceAttributes["service.version"] = resolvedConfig.appVersion;
2705
2824
  }
2706
2825
  this._sdk = new NodeSDK({
2707
- spanProcessors: resolvedConfig.disableSpanExporter ? [] : [getSpanProcessor()],
2826
+ spanProcessors: resolvedConfig.disableSpanExporter ? [] : [new InterruptPropagator(), getSpanProcessor()],
2708
2827
  metricReader: getMetricsReader(),
2709
2828
  resource: resourceFromAttributes3(resourceAttributes),
2710
2829
  instrumentations: manualInstrumentations
package/dist/preload.cjs CHANGED
@@ -471,6 +471,7 @@ var PROPERTIES = "properties";
471
471
  var SESSION_ID = "session.id";
472
472
  var PROPERTIES_CONTEXT_KEY = (0, import_api3.createContextKey)(PROPERTIES);
473
473
  var SESSION_OBJECT_CONTEXT_KEY = (0, import_api3.createContextKey)("brizz.session.object");
474
+ var INTERRUPT_TOOLS = "brizz.internal.interrupt";
474
475
 
475
476
  // src/internal/instrumentation/mcp/session.ts
476
477
  function stampAndPropagateSession(span, sessionId, baseContext = import_api4.context.active()) {
@@ -908,7 +909,7 @@ function safeEnd(span) {
908
909
 
909
910
  // src/internal/version.ts
910
911
  function getSDKVersion() {
911
- return "0.1.26";
912
+ return "0.1.27";
912
913
  }
913
914
 
914
915
  // src/internal/instrumentation/mcp/version.ts
@@ -1166,6 +1167,44 @@ var InstrumentationRegistry = class _InstrumentationRegistry {
1166
1167
  }
1167
1168
  };
1168
1169
 
1170
+ // src/internal/instrumentation/vercel-ai/interrupt.ts
1171
+ var import_api8 = require("@opentelemetry/api");
1172
+ var INNER_OPERATION_IDS = /* @__PURE__ */ new Set([
1173
+ "ai.generateText.doGenerate",
1174
+ "ai.streamText.doStream"
1175
+ ]);
1176
+ function isInnerLLMSpan(span) {
1177
+ if (INNER_OPERATION_IDS.has(span.name)) {
1178
+ return true;
1179
+ }
1180
+ const opId = span.attributes["ai.operationId"];
1181
+ return typeof opId === "string" && INNER_OPERATION_IDS.has(opId);
1182
+ }
1183
+ var pendingByParentSpanId = /* @__PURE__ */ new Map();
1184
+ var InterruptPropagator = class {
1185
+ onStart(span, _parentContext) {
1186
+ if (!isInnerLLMSpan(span)) {
1187
+ return;
1188
+ }
1189
+ const parentSpanId = span.parentSpanContext?.spanId;
1190
+ if (!parentSpanId) {
1191
+ return;
1192
+ }
1193
+ const value = pendingByParentSpanId.get(parentSpanId);
1194
+ if (!value) {
1195
+ return;
1196
+ }
1197
+ span.setAttribute(INTERRUPT_TOOLS, value);
1198
+ pendingByParentSpanId.delete(parentSpanId);
1199
+ }
1200
+ onEnd() {
1201
+ }
1202
+ async shutdown() {
1203
+ }
1204
+ async forceFlush() {
1205
+ }
1206
+ };
1207
+
1169
1208
  // src/internal/log/logging.ts
1170
1209
  var import_api_logs = require("@opentelemetry/api-logs");
1171
1210
  var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
@@ -1173,7 +1212,7 @@ var import_resources = require("@opentelemetry/resources");
1173
1212
  var import_sdk_logs2 = require("@opentelemetry/sdk-logs");
1174
1213
 
1175
1214
  // src/internal/log/processors/log-processor.ts
1176
- var import_api8 = require("@opentelemetry/api");
1215
+ var import_api9 = require("@opentelemetry/api");
1177
1216
  var import_sdk_logs = require("@opentelemetry/sdk-logs");
1178
1217
 
1179
1218
  // src/internal/masking/patterns.ts
@@ -1602,7 +1641,7 @@ var BrizzSimpleLogRecordProcessor = class extends import_sdk_logs.SimpleLogRecor
1602
1641
  if (maskingConfig) {
1603
1642
  maskLog(logRecord, maskingConfig);
1604
1643
  }
1605
- const associationProperties = import_api8.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1644
+ const associationProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1606
1645
  if (associationProperties) {
1607
1646
  for (const [key, value] of Object.entries(associationProperties)) {
1608
1647
  logRecord.setAttribute(`${BRIZZ}.${key}`, value);
@@ -1622,7 +1661,7 @@ var BrizzBatchLogRecordProcessor = class extends import_sdk_logs.BatchLogRecordP
1622
1661
  if (maskingConfig) {
1623
1662
  maskLog(logRecord, maskingConfig);
1624
1663
  }
1625
- const associationProperties = import_api8.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1664
+ const associationProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1626
1665
  if (associationProperties) {
1627
1666
  for (const [key, value] of Object.entries(associationProperties)) {
1628
1667
  logRecord.setAttribute(`${BRIZZ}.${key}`, value);
@@ -2009,10 +2048,10 @@ var BrizzSpanExporter = class {
2009
2048
  };
2010
2049
 
2011
2050
  // src/internal/trace/processors/span-processor.ts
2012
- var import_api9 = require("@opentelemetry/api");
2051
+ var import_api10 = require("@opentelemetry/api");
2013
2052
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
2014
2053
  function applyContextAttributes(span) {
2015
- const sessionProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2054
+ const sessionProperties = import_api10.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2016
2055
  if (sessionProperties) {
2017
2056
  for (const [key, value] of Object.entries(sessionProperties)) {
2018
2057
  span.setAttribute(`${BRIZZ}.${key}`, value);
@@ -2195,7 +2234,7 @@ function getSpanProcessor() {
2195
2234
  }
2196
2235
 
2197
2236
  // src/internal/trace/session.ts
2198
- var import_api10 = require("@opentelemetry/api");
2237
+ var import_api11 = require("@opentelemetry/api");
2199
2238
 
2200
2239
  // src/internal/sdk.ts
2201
2240
  var _Brizz = class __Brizz {
@@ -2280,7 +2319,7 @@ var _Brizz = class __Brizz {
2280
2319
  resourceAttributes["service.version"] = resolvedConfig.appVersion;
2281
2320
  }
2282
2321
  this._sdk = new import_sdk_node.NodeSDK({
2283
- spanProcessors: resolvedConfig.disableSpanExporter ? [] : [getSpanProcessor()],
2322
+ spanProcessors: resolvedConfig.disableSpanExporter ? [] : [new InterruptPropagator(), getSpanProcessor()],
2284
2323
  metricReader: getMetricsReader(),
2285
2324
  resource: (0, import_resources3.resourceFromAttributes)(resourceAttributes),
2286
2325
  instrumentations: manualInstrumentations
package/dist/preload.js CHANGED
@@ -454,6 +454,7 @@ var PROPERTIES = "properties";
454
454
  var SESSION_ID = "session.id";
455
455
  var PROPERTIES_CONTEXT_KEY = createContextKey(PROPERTIES);
456
456
  var SESSION_OBJECT_CONTEXT_KEY = createContextKey("brizz.session.object");
457
+ var INTERRUPT_TOOLS = "brizz.internal.interrupt";
457
458
 
458
459
  // src/internal/instrumentation/mcp/session.ts
459
460
  function stampAndPropagateSession(span, sessionId, baseContext = context.active()) {
@@ -891,7 +892,7 @@ function safeEnd(span) {
891
892
 
892
893
  // src/internal/version.ts
893
894
  function getSDKVersion() {
894
- return "0.1.26";
895
+ return "0.1.27";
895
896
  }
896
897
 
897
898
  // src/internal/instrumentation/mcp/version.ts
@@ -1149,6 +1150,44 @@ var InstrumentationRegistry = class _InstrumentationRegistry {
1149
1150
  }
1150
1151
  };
1151
1152
 
1153
+ // src/internal/instrumentation/vercel-ai/interrupt.ts
1154
+ import { trace as trace3 } from "@opentelemetry/api";
1155
+ var INNER_OPERATION_IDS = /* @__PURE__ */ new Set([
1156
+ "ai.generateText.doGenerate",
1157
+ "ai.streamText.doStream"
1158
+ ]);
1159
+ function isInnerLLMSpan(span) {
1160
+ if (INNER_OPERATION_IDS.has(span.name)) {
1161
+ return true;
1162
+ }
1163
+ const opId = span.attributes["ai.operationId"];
1164
+ return typeof opId === "string" && INNER_OPERATION_IDS.has(opId);
1165
+ }
1166
+ var pendingByParentSpanId = /* @__PURE__ */ new Map();
1167
+ var InterruptPropagator = class {
1168
+ onStart(span, _parentContext) {
1169
+ if (!isInnerLLMSpan(span)) {
1170
+ return;
1171
+ }
1172
+ const parentSpanId = span.parentSpanContext?.spanId;
1173
+ if (!parentSpanId) {
1174
+ return;
1175
+ }
1176
+ const value = pendingByParentSpanId.get(parentSpanId);
1177
+ if (!value) {
1178
+ return;
1179
+ }
1180
+ span.setAttribute(INTERRUPT_TOOLS, value);
1181
+ pendingByParentSpanId.delete(parentSpanId);
1182
+ }
1183
+ onEnd() {
1184
+ }
1185
+ async shutdown() {
1186
+ }
1187
+ async forceFlush() {
1188
+ }
1189
+ };
1190
+
1152
1191
  // src/internal/log/logging.ts
1153
1192
  import { SeverityNumber } from "@opentelemetry/api-logs";
1154
1193
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
@@ -2183,7 +2222,7 @@ function getSpanProcessor() {
2183
2222
  }
2184
2223
 
2185
2224
  // src/internal/trace/session.ts
2186
- import { context as context5, trace as trace3, SpanStatusCode as SpanStatusCode3 } from "@opentelemetry/api";
2225
+ import { context as context5, trace as trace4, SpanStatusCode as SpanStatusCode3 } from "@opentelemetry/api";
2187
2226
 
2188
2227
  // src/internal/sdk.ts
2189
2228
  var _Brizz = class __Brizz {
@@ -2268,7 +2307,7 @@ var _Brizz = class __Brizz {
2268
2307
  resourceAttributes["service.version"] = resolvedConfig.appVersion;
2269
2308
  }
2270
2309
  this._sdk = new NodeSDK({
2271
- spanProcessors: resolvedConfig.disableSpanExporter ? [] : [getSpanProcessor()],
2310
+ spanProcessors: resolvedConfig.disableSpanExporter ? [] : [new InterruptPropagator(), getSpanProcessor()],
2272
2311
  metricReader: getMetricsReader(),
2273
2312
  resource: resourceFromAttributes3(resourceAttributes),
2274
2313
  instrumentations: manualInstrumentations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brizz/sdk",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "type": "module",
5
5
  "description": "OpenTelemetry-based observability SDK for AI applications",
6
6
  "keywords": [
@@ -114,12 +114,16 @@
114
114
  },
115
115
  "peerDependencies": {
116
116
  "@langchain/core": "^0.3.0 || ^1.0.0",
117
+ "ai": "*",
117
118
  "typescript": ">=5.0.0"
118
119
  },
119
120
  "peerDependenciesMeta": {
120
121
  "@langchain/core": {
121
122
  "optional": true
122
123
  },
124
+ "ai": {
125
+ "optional": true
126
+ },
123
127
  "typescript": {
124
128
  "optional": true
125
129
  }