@brizz/sdk 0.1.26 → 0.1.28

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, MUTE_INPUT, MUTE_OUTPUT, SESSION_TITLE_SPAN_NAME, SESSION_TITLE_GENERATION, SESSION_TITLE, INTERRUPT_TOOLS, INTERNAL_EVENT_PREFIX, EXTERNAL_LINK_EVENT_NAME, EXTERNAL_LINK_URL, EXTERNAL_LINK_TITLE, EXTERNAL_LINK_TYPE;
309
309
  var init_semantic_conventions2 = __esm({
310
310
  "src/internal/semantic-conventions.ts"() {
311
311
  "use strict";
@@ -320,9 +320,17 @@ var init_semantic_conventions2 = __esm({
320
320
  SESSION_INPUT_CONTEXT = "brizz.session.input.context";
321
321
  SESSION_OUTPUT_CONTEXT = "brizz.session.output.context";
322
322
  SESSION_SPAN_NAME = "brizz.start_session";
323
+ MUTE_INPUT = "mute.input";
324
+ MUTE_OUTPUT = "mute.output";
323
325
  SESSION_TITLE_SPAN_NAME = "brizz.session_title";
324
326
  SESSION_TITLE_GENERATION = "session.title_generation";
325
327
  SESSION_TITLE = "brizz.session.title";
328
+ INTERRUPT_TOOLS = "brizz.internal.interrupt";
329
+ INTERNAL_EVENT_PREFIX = "brizz.internal.";
330
+ EXTERNAL_LINK_EVENT_NAME = "brizz.internal.external_link";
331
+ EXTERNAL_LINK_URL = "brizz.internal.external_link.url";
332
+ EXTERNAL_LINK_TITLE = "brizz.internal.external_link.title";
333
+ EXTERNAL_LINK_TYPE = "brizz.internal.external_link.type";
326
334
  }
327
335
  });
328
336
 
@@ -790,7 +798,7 @@ var init_protocol = __esm({
790
798
 
791
799
  // src/internal/version.ts
792
800
  function getSDKVersion() {
793
- return "0.1.26";
801
+ return "0.1.28";
794
802
  }
795
803
  var init_version = __esm({
796
804
  "src/internal/version.ts"() {
@@ -972,6 +980,100 @@ var init_mcp = __esm({
972
980
  }
973
981
  });
974
982
 
983
+ // src/internal/instrumentation/vercel-ai/interrupt.ts
984
+ var interrupt_exports = {};
985
+ __export(interrupt_exports, {
986
+ InterruptPropagator: () => InterruptPropagator,
987
+ _resetInterruptState: () => _resetInterruptState,
988
+ createInterruptIntegration: () => createInterruptIntegration
989
+ });
990
+ function isInnerLLMSpan(span) {
991
+ if (INNER_OPERATION_IDS.has(span.name)) {
992
+ return true;
993
+ }
994
+ const opId = span.attributes["ai.operationId"];
995
+ return typeof opId === "string" && INNER_OPERATION_IDS.has(opId);
996
+ }
997
+ function setPending(parentSpanId, value) {
998
+ pendingByParentSpanId.set(parentSpanId, value);
999
+ while (pendingByParentSpanId.size > MAX_PENDING_ENTRIES) {
1000
+ const oldest = pendingByParentSpanId.keys().next().value;
1001
+ if (oldest === void 0) {
1002
+ break;
1003
+ }
1004
+ pendingByParentSpanId.delete(oldest);
1005
+ }
1006
+ }
1007
+ function extractInterruptTools(tools) {
1008
+ if (!tools || typeof tools !== "object") {
1009
+ return [];
1010
+ }
1011
+ return Object.entries(tools).filter(
1012
+ ([, t]) => !!t && typeof t === "object" && t.needsApproval
1013
+ ).map(([name]) => name);
1014
+ }
1015
+ function createInterruptIntegration() {
1016
+ const onStepStart = (event) => {
1017
+ const names = extractInterruptTools(event.tools);
1018
+ if (names.length === 0) {
1019
+ return;
1020
+ }
1021
+ const value = JSON.stringify(names);
1022
+ const span = import_api8.trace.getActiveSpan();
1023
+ if (!span) {
1024
+ return;
1025
+ }
1026
+ span.setAttribute(INTERRUPT_TOOLS, value);
1027
+ setPending(span.spanContext().spanId, value);
1028
+ };
1029
+ return {
1030
+ onStepStart
1031
+ };
1032
+ }
1033
+ function _resetInterruptState() {
1034
+ if (process.env["NODE_ENV"] !== "test") {
1035
+ return;
1036
+ }
1037
+ pendingByParentSpanId.clear();
1038
+ }
1039
+ var import_api8, INNER_OPERATION_IDS, MAX_PENDING_ENTRIES, pendingByParentSpanId, InterruptPropagator;
1040
+ var init_interrupt = __esm({
1041
+ "src/internal/instrumentation/vercel-ai/interrupt.ts"() {
1042
+ "use strict";
1043
+ import_api8 = require("@opentelemetry/api");
1044
+ init_semantic_conventions2();
1045
+ INNER_OPERATION_IDS = /* @__PURE__ */ new Set([
1046
+ "ai.generateText.doGenerate",
1047
+ "ai.streamText.doStream"
1048
+ ]);
1049
+ MAX_PENDING_ENTRIES = 1024;
1050
+ pendingByParentSpanId = /* @__PURE__ */ new Map();
1051
+ InterruptPropagator = class {
1052
+ onStart(span, _parentContext) {
1053
+ if (!isInnerLLMSpan(span)) {
1054
+ return;
1055
+ }
1056
+ const parentSpanId = span.parentSpanContext?.spanId;
1057
+ if (!parentSpanId) {
1058
+ return;
1059
+ }
1060
+ const value = pendingByParentSpanId.get(parentSpanId);
1061
+ if (!value) {
1062
+ return;
1063
+ }
1064
+ span.setAttribute(INTERRUPT_TOOLS, value);
1065
+ pendingByParentSpanId.delete(parentSpanId);
1066
+ }
1067
+ onEnd() {
1068
+ }
1069
+ async shutdown() {
1070
+ }
1071
+ async forceFlush() {
1072
+ }
1073
+ };
1074
+ }
1075
+ });
1076
+
975
1077
  // src/index.ts
976
1078
  var src_exports = {};
977
1079
  __export(src_exports, {
@@ -981,10 +1083,13 @@ __export(src_exports, {
981
1083
  Session: () => Session,
982
1084
  SessionTitle: () => SessionTitle,
983
1085
  SeverityNumber: () => import_api_logs2.SeverityNumber,
1086
+ addExternalLink: () => addExternalLink,
1087
+ callWithMute: () => callWithMute,
984
1088
  callWithProperties: () => callWithProperties,
985
1089
  callWithSessionId: () => callWithSessionId,
986
1090
  detectRuntime: () => detectRuntime,
987
1091
  emitEvent: () => emitEvent,
1092
+ emitEventWithSessionId: () => emitEventWithSessionId,
988
1093
  getActiveSession: () => getActiveSession,
989
1094
  getLogLevel: () => getLogLevel,
990
1095
  getMetricsExporter: () => getMetricsExporter,
@@ -999,6 +1104,7 @@ __export(src_exports, {
999
1104
  setLogLevel: () => setLogLevel,
1000
1105
  startSession: () => startSession,
1001
1106
  startSessionTitle: () => startSessionTitle,
1107
+ withMute: () => withMute,
1002
1108
  withProperties: () => withProperties,
1003
1109
  withSessionId: () => withSessionId
1004
1110
  });
@@ -1084,6 +1190,26 @@ function loadMCPInstrumentation() {
1084
1190
  }
1085
1191
  })();
1086
1192
  }
1193
+ function loadVercelAIInterruptIntegration() {
1194
+ void (async () => {
1195
+ try {
1196
+ const ai = await import("ai");
1197
+ if (typeof ai.registerTelemetryIntegration !== "function") {
1198
+ logger.debug(
1199
+ "AI SDK present but lacks registerTelemetryIntegration (needs ai@>=6); skipping interrupt bridge"
1200
+ );
1201
+ return;
1202
+ }
1203
+ const { createInterruptIntegration: createInterruptIntegration2 } = await Promise.resolve().then(() => (init_interrupt(), interrupt_exports));
1204
+ ai.registerTelemetryIntegration(createInterruptIntegration2());
1205
+ logger.debug("Auto-loaded Vercel AI interrupt bridge");
1206
+ } catch (error) {
1207
+ logger.debug(
1208
+ `Vercel AI interrupt bridge not loaded (install ai@>=6 if you want HITL attribution): ${String(error)}`
1209
+ );
1210
+ }
1211
+ })();
1212
+ }
1087
1213
  function autoInitializeInstrumentations() {
1088
1214
  if (autoInstrumentationsLoaded) {
1089
1215
  return;
@@ -1092,6 +1218,7 @@ function autoInitializeInstrumentations() {
1092
1218
  const nodeInstrumentations = loadNodeAutoInstrumentations();
1093
1219
  const genAIInstrumentations = loadGenAIInstrumentations();
1094
1220
  loadMCPInstrumentation();
1221
+ loadVercelAIInterruptIntegration();
1095
1222
  autoInstrumentationsLoaded = true;
1096
1223
  logger.info(
1097
1224
  `Auto-initialization complete: ${nodeInstrumentations.length} node + ${genAIInstrumentations.length} GenAI instrumentations`
@@ -1406,16 +1533,291 @@ var InstrumentationRegistry = class _InstrumentationRegistry {
1406
1533
  }
1407
1534
  };
1408
1535
 
1536
+ // src/internal/sdk.ts
1537
+ init_interrupt();
1538
+
1409
1539
  // src/internal/log/logging.ts
1410
1540
  var import_api_logs = require("@opentelemetry/api-logs");
1411
1541
  var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
1412
1542
  var import_resources = require("@opentelemetry/resources");
1413
1543
  var import_sdk_logs2 = require("@opentelemetry/sdk-logs");
1414
1544
  init_logger();
1545
+
1546
+ // src/internal/trace/session.ts
1547
+ var import_api9 = require("@opentelemetry/api");
1548
+ init_logger();
1549
+ init_semantic_conventions2();
1550
+ function setCurrentSpanCustomProperties(properties) {
1551
+ const current = import_api9.trace.getActiveSpan();
1552
+ if (!current || !current.isRecording()) {
1553
+ return;
1554
+ }
1555
+ for (const [key, value] of Object.entries(properties)) {
1556
+ try {
1557
+ current.setAttribute(`${BRIZZ}.${key}`, value);
1558
+ } catch {
1559
+ }
1560
+ }
1561
+ }
1562
+ function callWithProperties(properties, fn, thisArg, ...args) {
1563
+ const base = import_api9.context.active();
1564
+ const prev = base.getValue(PROPERTIES_CONTEXT_KEY);
1565
+ const merged = prev ? { ...prev, ...properties } : properties;
1566
+ const next = base.setValue(PROPERTIES_CONTEXT_KEY, merged);
1567
+ return import_api9.context.with(next, fn, thisArg, ...args);
1568
+ }
1569
+ function withProperties(properties, fn, thisArg) {
1570
+ return function wrapped(...args) {
1571
+ return callWithProperties(
1572
+ properties,
1573
+ fn,
1574
+ thisArg !== void 0 ? thisArg : this,
1575
+ ...args
1576
+ );
1577
+ };
1578
+ }
1579
+ function muteProperties(options) {
1580
+ const { input = true, output = true } = options;
1581
+ const properties = {};
1582
+ if (input) {
1583
+ properties[MUTE_INPUT] = "true";
1584
+ }
1585
+ if (output) {
1586
+ properties[MUTE_OUTPUT] = "true";
1587
+ }
1588
+ return properties;
1589
+ }
1590
+ function callWithMute(options, fn, thisArg, ...args) {
1591
+ return callWithProperties(muteProperties(options), fn, thisArg, ...args);
1592
+ }
1593
+ function withMute(options, fn, thisArg) {
1594
+ return withProperties(muteProperties(options), fn, thisArg);
1595
+ }
1596
+ function withSessionId(sessionId, fn, thisArg, extraProperties) {
1597
+ const properties = { [SESSION_ID]: sessionId, ...extraProperties };
1598
+ return withProperties(properties, fn, thisArg);
1599
+ }
1600
+ function callWithSessionId(sessionId, fn, thisArg, ...args) {
1601
+ return callWithProperties({ [SESSION_ID]: sessionId }, fn, thisArg, ...args);
1602
+ }
1603
+ var Session = class {
1604
+ sessionId;
1605
+ span;
1606
+ inputs = [];
1607
+ outputs = [];
1608
+ inputContexts = [];
1609
+ outputContexts = [];
1610
+ constructor(sessionId, span) {
1611
+ this.sessionId = sessionId;
1612
+ this.span = span;
1613
+ }
1614
+ /**
1615
+ * Append a user turn to session input tracking.
1616
+ *
1617
+ * Each call appends one element to `brizz.session.input` (the text) AND one
1618
+ * element to `brizz.session.input.context` (the per-turn context bag). The
1619
+ * two arrays stay index-aligned — the ingestion pipeline zips them together
1620
+ * so the i-th context bag lands on the i-th user_display conversation item's
1621
+ * `span_attributes` map.
1622
+ *
1623
+ * @param text - Text to append (null becomes a null/"hide marker")
1624
+ * @param context - Optional per-turn context bag to attach to this turn
1625
+ */
1626
+ setInput(text, context6) {
1627
+ this.inputs.push(text);
1628
+ this.inputContexts.push(context6 ?? {});
1629
+ this.span.setAttribute(SESSION_INPUT, JSON.stringify(this.inputs));
1630
+ this.span.setAttribute(SESSION_INPUT_CONTEXT, JSON.stringify(this.inputContexts));
1631
+ }
1632
+ /**
1633
+ * Append an assistant turn to session output tracking.
1634
+ *
1635
+ * Symmetric to {@link setInput} — appends one text element and one
1636
+ * context-bag element to the index-aligned `brizz.session.output` /
1637
+ * `brizz.session.output.context` arrays.
1638
+ *
1639
+ * @param text - Text to append (null becomes a null/"hide marker")
1640
+ * @param context - Optional per-turn context bag to attach to this turn
1641
+ */
1642
+ setOutput(text, context6) {
1643
+ this.outputs.push(text);
1644
+ this.outputContexts.push(context6 ?? {});
1645
+ this.span.setAttribute(SESSION_OUTPUT, JSON.stringify(this.outputs));
1646
+ this.span.setAttribute(SESSION_OUTPUT_CONTEXT, JSON.stringify(this.outputContexts));
1647
+ }
1648
+ /**
1649
+ * Set the session title on the span.
1650
+ *
1651
+ * @param title - The generated title string
1652
+ */
1653
+ setTitle(title) {
1654
+ this.span.setAttribute(SESSION_TITLE, title);
1655
+ }
1656
+ /**
1657
+ * Update custom properties on the session span.
1658
+ * Properties are prefixed with 'brizz.'.
1659
+ *
1660
+ * @param properties - Key-value properties to set on the session
1661
+ */
1662
+ updateProperties(properties) {
1663
+ for (const [key, value] of Object.entries(properties)) {
1664
+ this.span.setAttribute(`${BRIZZ}.${key}`, value);
1665
+ }
1666
+ }
1667
+ /**
1668
+ * Attach an external link (URL) to this session.
1669
+ *
1670
+ * The link surfaces on the session's detail panel in Brizz — use it to
1671
+ * correlate a session with an external record such as a Datadog trace,
1672
+ * Sentry issue, or internal dashboard. Re-sending the same URL is idempotent;
1673
+ * distinct URLs add separate links.
1674
+ *
1675
+ * @param url - The link target
1676
+ * @param options - Optional `title` (defaults to the URL host) and `linkType`
1677
+ * (free-form category, defaults to `'generic'`)
1678
+ */
1679
+ addExternalLink(url, options) {
1680
+ emitExternalLink(this.sessionId, url, options?.title, options?.linkType);
1681
+ }
1682
+ };
1683
+ var SessionTitle = class {
1684
+ span;
1685
+ constructor(span) {
1686
+ this.span = span;
1687
+ }
1688
+ /**
1689
+ * Set the generated title on the wrapper span.
1690
+ *
1691
+ * @param title - The generated title string
1692
+ */
1693
+ setTitle(title) {
1694
+ this.span.setAttribute(SESSION_TITLE, title);
1695
+ }
1696
+ };
1697
+ function getActiveSession() {
1698
+ return import_api9.context.active().getValue(SESSION_OBJECT_CONTEXT_KEY);
1699
+ }
1700
+ function resolveSessionIdFromContext() {
1701
+ const active = getActiveSession();
1702
+ if (active) {
1703
+ return active.sessionId;
1704
+ }
1705
+ const props = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1706
+ return props?.[SESSION_ID];
1707
+ }
1708
+ function emitExternalLink(sessionId, url, title, linkType) {
1709
+ try {
1710
+ emitEventWithSessionId(sessionId, EXTERNAL_LINK_EVENT_NAME, {
1711
+ [EXTERNAL_LINK_URL]: url,
1712
+ [EXTERNAL_LINK_TITLE]: title ?? "",
1713
+ [EXTERNAL_LINK_TYPE]: linkType ?? "generic"
1714
+ });
1715
+ } catch (error) {
1716
+ logger.warn("addExternalLink: failed to emit external link", error);
1717
+ }
1718
+ }
1719
+ function addExternalLink(url, options) {
1720
+ const sessionId = options?.sessionId ?? resolveSessionIdFromContext();
1721
+ if (!sessionId) {
1722
+ logger.warn(
1723
+ "addExternalLink called without a resolvable session id; link dropped. Pass options.sessionId or call inside a startSession/callWithSessionId scope."
1724
+ );
1725
+ return;
1726
+ }
1727
+ emitExternalLink(sessionId, url, options?.title, options?.linkType);
1728
+ }
1729
+ function startSession(sessionId, callback, extraProperties, options) {
1730
+ const isTitle = options?.mode === "title";
1731
+ const spanName = isTitle ? SESSION_TITLE_SPAN_NAME : SESSION_SPAN_NAME;
1732
+ const tracer = import_api9.trace.getTracer("@brizz/sdk");
1733
+ return tracer.startActiveSpan(spanName, (span) => {
1734
+ span.setAttribute(`${BRIZZ}.${SESSION_ID}`, sessionId);
1735
+ if (extraProperties) {
1736
+ for (const [key, value] of Object.entries(extraProperties)) {
1737
+ span.setAttribute(`${BRIZZ}.${key}`, value);
1738
+ }
1739
+ }
1740
+ const session = new Session(sessionId, span);
1741
+ const contextProperties = { [SESSION_ID]: sessionId };
1742
+ if (isTitle) {
1743
+ contextProperties[SESSION_TITLE_GENERATION] = "true";
1744
+ }
1745
+ if (extraProperties) {
1746
+ for (const [key, value] of Object.entries(extraProperties)) {
1747
+ contextProperties[key] = String(value);
1748
+ }
1749
+ }
1750
+ return callWithProperties(contextProperties, () => {
1751
+ const sessionCtx = import_api9.context.active().setValue(SESSION_OBJECT_CONTEXT_KEY, session);
1752
+ return import_api9.context.with(sessionCtx, () => {
1753
+ try {
1754
+ const result = callback(session);
1755
+ if (result && typeof result.then === "function") {
1756
+ return result.then((value) => {
1757
+ span.end();
1758
+ return value;
1759
+ }).catch((error) => {
1760
+ span.recordException(error);
1761
+ span.setStatus({ code: import_api9.SpanStatusCode.ERROR });
1762
+ span.end();
1763
+ throw error;
1764
+ });
1765
+ }
1766
+ span.end();
1767
+ return result;
1768
+ } catch (error) {
1769
+ span.recordException(error);
1770
+ span.setStatus({ code: import_api9.SpanStatusCode.ERROR });
1771
+ span.end();
1772
+ throw error;
1773
+ }
1774
+ });
1775
+ });
1776
+ });
1777
+ }
1778
+ function startSessionTitle(callback, options) {
1779
+ const resolvedSessionId = options?.sessionId ?? getActiveSession()?.sessionId;
1780
+ const tracer = import_api9.trace.getTracer("@brizz/sdk");
1781
+ return tracer.startActiveSpan(SESSION_TITLE_SPAN_NAME, (span) => {
1782
+ if (resolvedSessionId) {
1783
+ span.setAttribute(`${BRIZZ}.${SESSION_ID}`, resolvedSessionId);
1784
+ }
1785
+ const sessionTitle = new SessionTitle(span);
1786
+ const properties = { [SESSION_TITLE_GENERATION]: "true" };
1787
+ if (resolvedSessionId) {
1788
+ properties[SESSION_ID] = resolvedSessionId;
1789
+ }
1790
+ return callWithProperties(properties, () => {
1791
+ try {
1792
+ const result = callback(sessionTitle);
1793
+ if (result && typeof result.then === "function") {
1794
+ return result.then((value) => {
1795
+ span.end();
1796
+ return value;
1797
+ }).catch((error) => {
1798
+ span.recordException(error);
1799
+ span.setStatus({ code: import_api9.SpanStatusCode.ERROR });
1800
+ span.end();
1801
+ throw error;
1802
+ });
1803
+ }
1804
+ span.end();
1805
+ return result;
1806
+ } catch (error) {
1807
+ span.recordException(error);
1808
+ span.setStatus({ code: import_api9.SpanStatusCode.ERROR });
1809
+ span.end();
1810
+ throw error;
1811
+ }
1812
+ });
1813
+ });
1814
+ }
1815
+
1816
+ // src/internal/log/logging.ts
1415
1817
  init_version();
1416
1818
 
1417
1819
  // src/internal/log/processors/log-processor.ts
1418
- var import_api8 = require("@opentelemetry/api");
1820
+ var import_api10 = require("@opentelemetry/api");
1419
1821
  var import_sdk_logs = require("@opentelemetry/sdk-logs");
1420
1822
  init_logger();
1421
1823
 
@@ -1847,7 +2249,7 @@ var BrizzSimpleLogRecordProcessor = class extends import_sdk_logs.SimpleLogRecor
1847
2249
  if (maskingConfig) {
1848
2250
  maskLog(logRecord, maskingConfig);
1849
2251
  }
1850
- const associationProperties = import_api8.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2252
+ const associationProperties = import_api10.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1851
2253
  if (associationProperties) {
1852
2254
  for (const [key, value] of Object.entries(associationProperties)) {
1853
2255
  logRecord.setAttribute(`${BRIZZ}.${key}`, value);
@@ -1867,7 +2269,7 @@ var BrizzBatchLogRecordProcessor = class extends import_sdk_logs.BatchLogRecordP
1867
2269
  if (maskingConfig) {
1868
2270
  maskLog(logRecord, maskingConfig);
1869
2271
  }
1870
- const associationProperties = import_api8.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2272
+ const associationProperties = import_api10.context.active().getValue(PROPERTIES_CONTEXT_KEY);
1871
2273
  if (associationProperties) {
1872
2274
  for (const [key, value] of Object.entries(associationProperties)) {
1873
2275
  logRecord.setAttribute(`${BRIZZ}.${key}`, value);
@@ -1896,6 +2298,11 @@ function maskLog(logRecord, config) {
1896
2298
  for (const [key, value] of Object.entries(maskedAttributes)) {
1897
2299
  newAttributes[key] = value;
1898
2300
  }
2301
+ for (const [key, value] of Object.entries(logRecord.attributes)) {
2302
+ if (key.startsWith(INTERNAL_EVENT_PREFIX)) {
2303
+ newAttributes[key] = value;
2304
+ }
2305
+ }
1899
2306
  logRecord.setAttributes(newAttributes);
1900
2307
  }
1901
2308
  }
@@ -2085,6 +2492,11 @@ var LoggingModule = class _LoggingModule {
2085
2492
  function emitEvent(name, attributes, body, severityNumber = import_api_logs.SeverityNumber.INFO) {
2086
2493
  return LoggingModule.getInstance().emitEvent(name, attributes, body, severityNumber);
2087
2494
  }
2495
+ function emitEventWithSessionId(sessionId, name, attributes, body, severityNumber = import_api_logs.SeverityNumber.INFO) {
2496
+ return callWithSessionId(sessionId, () => {
2497
+ LoggingModule.getInstance().emitEvent(name, attributes, body, severityNumber);
2498
+ });
2499
+ }
2088
2500
 
2089
2501
  // src/internal/sdk.ts
2090
2502
  init_logger();
@@ -2267,12 +2679,12 @@ var BrizzSpanExporter = class {
2267
2679
  };
2268
2680
 
2269
2681
  // src/internal/trace/processors/span-processor.ts
2270
- var import_api9 = require("@opentelemetry/api");
2682
+ var import_api11 = require("@opentelemetry/api");
2271
2683
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
2272
2684
  init_logger();
2273
2685
  init_semantic_conventions2();
2274
2686
  function applyContextAttributes(span) {
2275
- const sessionProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2687
+ const sessionProperties = import_api11.context.active().getValue(PROPERTIES_CONTEXT_KEY);
2276
2688
  if (sessionProperties) {
2277
2689
  for (const [key, value] of Object.entries(sessionProperties)) {
2278
2690
  span.setAttribute(`${BRIZZ}.${key}`, value);
@@ -2457,214 +2869,6 @@ function getSpanProcessor() {
2457
2869
  return TracingModule.getInstance().getSpanProcessor();
2458
2870
  }
2459
2871
 
2460
- // src/internal/trace/session.ts
2461
- var import_api10 = require("@opentelemetry/api");
2462
- init_semantic_conventions2();
2463
- function setCurrentSpanCustomProperties(properties) {
2464
- const current = import_api10.trace.getActiveSpan();
2465
- if (!current || !current.isRecording()) {
2466
- return;
2467
- }
2468
- for (const [key, value] of Object.entries(properties)) {
2469
- try {
2470
- current.setAttribute(`${BRIZZ}.${key}`, value);
2471
- } catch {
2472
- }
2473
- }
2474
- }
2475
- function callWithProperties(properties, fn, thisArg, ...args) {
2476
- const base = import_api10.context.active();
2477
- const prev = base.getValue(PROPERTIES_CONTEXT_KEY);
2478
- const merged = prev ? { ...prev, ...properties } : properties;
2479
- const next = base.setValue(PROPERTIES_CONTEXT_KEY, merged);
2480
- return import_api10.context.with(next, fn, thisArg, ...args);
2481
- }
2482
- function withProperties(properties, fn, thisArg) {
2483
- return function wrapped(...args) {
2484
- return callWithProperties(
2485
- properties,
2486
- fn,
2487
- thisArg !== void 0 ? thisArg : this,
2488
- ...args
2489
- );
2490
- };
2491
- }
2492
- function withSessionId(sessionId, fn, thisArg, extraProperties) {
2493
- const properties = { [SESSION_ID]: sessionId, ...extraProperties };
2494
- return withProperties(properties, fn, thisArg);
2495
- }
2496
- function callWithSessionId(sessionId, fn, thisArg, ...args) {
2497
- return callWithProperties({ [SESSION_ID]: sessionId }, fn, thisArg, ...args);
2498
- }
2499
- var Session = class {
2500
- sessionId;
2501
- span;
2502
- inputs = [];
2503
- outputs = [];
2504
- inputContexts = [];
2505
- outputContexts = [];
2506
- constructor(sessionId, span) {
2507
- this.sessionId = sessionId;
2508
- this.span = span;
2509
- }
2510
- /**
2511
- * Append a user turn to session input tracking.
2512
- *
2513
- * Each call appends one element to `brizz.session.input` (the text) AND one
2514
- * element to `brizz.session.input.context` (the per-turn context bag). The
2515
- * two arrays stay index-aligned — the ingestion pipeline zips them together
2516
- * so the i-th context bag lands on the i-th user_display conversation item's
2517
- * `span_attributes` map.
2518
- *
2519
- * @param text - Text to append (null becomes a null/"hide marker")
2520
- * @param context - Optional per-turn context bag to attach to this turn
2521
- */
2522
- setInput(text, context6) {
2523
- this.inputs.push(text);
2524
- this.inputContexts.push(context6 ?? {});
2525
- this.span.setAttribute(SESSION_INPUT, JSON.stringify(this.inputs));
2526
- this.span.setAttribute(SESSION_INPUT_CONTEXT, JSON.stringify(this.inputContexts));
2527
- }
2528
- /**
2529
- * Append an assistant turn to session output tracking.
2530
- *
2531
- * Symmetric to {@link setInput} — appends one text element and one
2532
- * context-bag element to the index-aligned `brizz.session.output` /
2533
- * `brizz.session.output.context` arrays.
2534
- *
2535
- * @param text - Text to append (null becomes a null/"hide marker")
2536
- * @param context - Optional per-turn context bag to attach to this turn
2537
- */
2538
- setOutput(text, context6) {
2539
- this.outputs.push(text);
2540
- this.outputContexts.push(context6 ?? {});
2541
- this.span.setAttribute(SESSION_OUTPUT, JSON.stringify(this.outputs));
2542
- this.span.setAttribute(SESSION_OUTPUT_CONTEXT, JSON.stringify(this.outputContexts));
2543
- }
2544
- /**
2545
- * Set the session title on the span.
2546
- *
2547
- * @param title - The generated title string
2548
- */
2549
- setTitle(title) {
2550
- this.span.setAttribute(SESSION_TITLE, title);
2551
- }
2552
- /**
2553
- * Update custom properties on the session span.
2554
- * Properties are prefixed with 'brizz.'.
2555
- *
2556
- * @param properties - Key-value properties to set on the session
2557
- */
2558
- updateProperties(properties) {
2559
- for (const [key, value] of Object.entries(properties)) {
2560
- this.span.setAttribute(`${BRIZZ}.${key}`, value);
2561
- }
2562
- }
2563
- };
2564
- var SessionTitle = class {
2565
- span;
2566
- constructor(span) {
2567
- this.span = span;
2568
- }
2569
- /**
2570
- * Set the generated title on the wrapper span.
2571
- *
2572
- * @param title - The generated title string
2573
- */
2574
- setTitle(title) {
2575
- this.span.setAttribute(SESSION_TITLE, title);
2576
- }
2577
- };
2578
- function getActiveSession() {
2579
- return import_api10.context.active().getValue(SESSION_OBJECT_CONTEXT_KEY);
2580
- }
2581
- function startSession(sessionId, callback, extraProperties, options) {
2582
- const isTitle = options?.mode === "title";
2583
- const spanName = isTitle ? SESSION_TITLE_SPAN_NAME : SESSION_SPAN_NAME;
2584
- const tracer = import_api10.trace.getTracer("@brizz/sdk");
2585
- return tracer.startActiveSpan(spanName, (span) => {
2586
- span.setAttribute(`${BRIZZ}.${SESSION_ID}`, sessionId);
2587
- if (extraProperties) {
2588
- for (const [key, value] of Object.entries(extraProperties)) {
2589
- span.setAttribute(`${BRIZZ}.${key}`, value);
2590
- }
2591
- }
2592
- const session = new Session(sessionId, span);
2593
- const contextProperties = { [SESSION_ID]: sessionId };
2594
- if (isTitle) {
2595
- contextProperties[SESSION_TITLE_GENERATION] = "true";
2596
- }
2597
- if (extraProperties) {
2598
- for (const [key, value] of Object.entries(extraProperties)) {
2599
- contextProperties[key] = String(value);
2600
- }
2601
- }
2602
- return callWithProperties(contextProperties, () => {
2603
- const sessionCtx = import_api10.context.active().setValue(SESSION_OBJECT_CONTEXT_KEY, session);
2604
- return import_api10.context.with(sessionCtx, () => {
2605
- try {
2606
- const result = callback(session);
2607
- if (result && typeof result.then === "function") {
2608
- return result.then((value) => {
2609
- span.end();
2610
- return value;
2611
- }).catch((error) => {
2612
- span.recordException(error);
2613
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2614
- span.end();
2615
- throw error;
2616
- });
2617
- }
2618
- span.end();
2619
- return result;
2620
- } catch (error) {
2621
- span.recordException(error);
2622
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2623
- span.end();
2624
- throw error;
2625
- }
2626
- });
2627
- });
2628
- });
2629
- }
2630
- function startSessionTitle(callback, options) {
2631
- const resolvedSessionId = options?.sessionId ?? getActiveSession()?.sessionId;
2632
- const tracer = import_api10.trace.getTracer("@brizz/sdk");
2633
- return tracer.startActiveSpan(SESSION_TITLE_SPAN_NAME, (span) => {
2634
- if (resolvedSessionId) {
2635
- span.setAttribute(`${BRIZZ}.${SESSION_ID}`, resolvedSessionId);
2636
- }
2637
- const sessionTitle = new SessionTitle(span);
2638
- const properties = { [SESSION_TITLE_GENERATION]: "true" };
2639
- if (resolvedSessionId) {
2640
- properties[SESSION_ID] = resolvedSessionId;
2641
- }
2642
- return callWithProperties(properties, () => {
2643
- try {
2644
- const result = callback(sessionTitle);
2645
- if (result && typeof result.then === "function") {
2646
- return result.then((value) => {
2647
- span.end();
2648
- return value;
2649
- }).catch((error) => {
2650
- span.recordException(error);
2651
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2652
- span.end();
2653
- throw error;
2654
- });
2655
- }
2656
- span.end();
2657
- return result;
2658
- } catch (error) {
2659
- span.recordException(error);
2660
- span.setStatus({ code: import_api10.SpanStatusCode.ERROR });
2661
- span.end();
2662
- throw error;
2663
- }
2664
- });
2665
- });
2666
- }
2667
-
2668
2872
  // src/internal/sdk.ts
2669
2873
  init_version();
2670
2874
  var _Brizz = class __Brizz {
@@ -2749,7 +2953,7 @@ var _Brizz = class __Brizz {
2749
2953
  resourceAttributes["service.version"] = resolvedConfig.appVersion;
2750
2954
  }
2751
2955
  this._sdk = new import_sdk_node.NodeSDK({
2752
- spanProcessors: resolvedConfig.disableSpanExporter ? [] : [getSpanProcessor()],
2956
+ spanProcessors: resolvedConfig.disableSpanExporter ? [] : [new InterruptPropagator(), getSpanProcessor()],
2753
2957
  metricReader: getMetricsReader(),
2754
2958
  resource: (0, import_resources3.resourceFromAttributes)(resourceAttributes),
2755
2959
  instrumentations: manualInstrumentations
@@ -2924,10 +3128,13 @@ var init_exports = {};
2924
3128
  Session,
2925
3129
  SessionTitle,
2926
3130
  SeverityNumber,
3131
+ addExternalLink,
3132
+ callWithMute,
2927
3133
  callWithProperties,
2928
3134
  callWithSessionId,
2929
3135
  detectRuntime,
2930
3136
  emitEvent,
3137
+ emitEventWithSessionId,
2931
3138
  getActiveSession,
2932
3139
  getLogLevel,
2933
3140
  getMetricsExporter,
@@ -2942,6 +3149,7 @@ var init_exports = {};
2942
3149
  setLogLevel,
2943
3150
  startSession,
2944
3151
  startSessionTitle,
3152
+ withMute,
2945
3153
  withProperties,
2946
3154
  withSessionId
2947
3155
  });