@lmnr-ai/lmnr 0.8.20 → 0.8.21

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 (39) hide show
  1. package/dist/cli/worker/build.cjs +1 -1
  2. package/dist/cli/worker/build.mjs +1 -1
  3. package/dist/cli/worker/index.cjs +1 -1
  4. package/dist/cli/worker/index.mjs +1 -1
  5. package/dist/cli.cjs +3 -3
  6. package/dist/cli.d.cts +1 -1
  7. package/dist/cli.d.mts +1 -1
  8. package/dist/cli.mjs +3 -3
  9. package/dist/{decorators-Cf0xs-v_.mjs → decorators-BDFgXfgI.mjs} +820 -139
  10. package/dist/decorators-BDFgXfgI.mjs.map +1 -0
  11. package/dist/{decorators-u7xFb_9W.cjs → decorators-CaTC0lJq.cjs} +831 -138
  12. package/dist/decorators-CaTC0lJq.cjs.map +1 -0
  13. package/dist/{dist-BwllJ__m.mjs → dist-B5CmOQ4s.mjs} +3 -3
  14. package/dist/{dist-BwllJ__m.mjs.map → dist-B5CmOQ4s.mjs.map} +1 -1
  15. package/dist/{dist-zDtQ_gVq.cjs → dist-B5cKzRzq.cjs} +3 -3
  16. package/dist/{dist-zDtQ_gVq.cjs.map → dist-B5cKzRzq.cjs.map} +1 -1
  17. package/dist/{evaluations-D2duRqbG.d.cts → evaluations-BJkIwpmH.d.cts} +15 -1
  18. package/dist/{evaluations-DEbBIXng.d.mts → evaluations-tqpNgp0P.d.mts} +15 -1
  19. package/dist/{file-utils-C-auksVC.mjs → file-utils-CHoR9VB8.mjs} +2 -2
  20. package/dist/{file-utils-C-auksVC.mjs.map → file-utils-CHoR9VB8.mjs.map} +1 -1
  21. package/dist/file-utils-IBEBwZxq.cjs +2 -0
  22. package/dist/{file-utils-0mVr0eIv.cjs → file-utils-yJ5ephze.cjs} +2 -2
  23. package/dist/{file-utils-0mVr0eIv.cjs.map → file-utils-yJ5ephze.cjs.map} +1 -1
  24. package/dist/index.cjs +563 -9
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +125 -3
  27. package/dist/index.d.mts +125 -3
  28. package/dist/index.mjs +564 -11
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/{utils-BmWNkeX5.cjs → utils-C8Tl1vKD.cjs} +23 -1
  31. package/dist/utils-C8Tl1vKD.cjs.map +1 -0
  32. package/dist/{utils-0WC6BVqs.mjs → utils-CHJ0KZUR.mjs} +12 -2
  33. package/dist/utils-CHJ0KZUR.mjs.map +1 -0
  34. package/package.json +4 -3
  35. package/dist/decorators-Cf0xs-v_.mjs.map +0 -1
  36. package/dist/decorators-u7xFb_9W.cjs.map +0 -1
  37. package/dist/file-utils-2hY2DP65.cjs +0 -2
  38. package/dist/utils-0WC6BVqs.mjs.map +0 -1
  39. package/dist/utils-BmWNkeX5.cjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { t as LaminarClient } from "./dist-BwllJ__m.mjs";
2
- import { a as getFrontendUrl, c as loadEnv, d as otelSpanIdToUUID, f as otelTraceIdToUUID, j as SPAN_TYPE, n as Semaphore, s as initializeLogger, u as newUUID, v as HUMAN_EVALUATOR_OPTIONS, y as LaminarAttributes } from "./utils-0WC6BVqs.mjs";
3
- import { a as getTracer, c as initializeLaminarInstrumentations, d as LaminarContextManager, f as TracingLevel, i as withTracingLevel, l as Laminar, m as stringifyPromptForTelemetry, n as observeDecorator, o as getTracerProvider, r as observeExperimentalDecorator, s as LaminarSpanProcessor, t as observe, u as instrumentClaudeAgentQuery } from "./decorators-Cf0xs-v_.mjs";
4
- import { trace } from "@opentelemetry/api";
1
+ import { n as version, t as LaminarClient } from "./dist-B5CmOQ4s.mjs";
2
+ import { A as SPAN_OUTPUT, D as SPAN_INPUT, E as SPAN_IDS_PATH, I as USER_ID, M as SPAN_SDK_VERSION, N as SPAN_TYPE, O as SPAN_INSTRUMENTATION_SOURCE, T as SESSION_ID, a as getFrontendUrl, b as HUMAN_EVALUATOR_OPTIONS, c as loadEnv, d as normalizeOtelSpanId, f as normalizeOtelTraceId, j as SPAN_PATH, k as SPAN_LANGUAGE_VERSION, m as otelTraceIdToUUID, n as Semaphore, p as otelSpanIdToUUID, s as initializeLogger, u as newUUID, v as ASSOCIATION_PROPERTIES, x as LaminarAttributes } from "./utils-CHJ0KZUR.mjs";
3
+ import { a as getSpanProcessor, c as LaminarSpanProcessor, d as Laminar, f as instrumentClaudeAgentQuery, g as stringifyPromptForTelemetry, i as withTracingLevel, l as getLangVersion, m as TracingLevel, n as observeDecorator, o as getTracer, p as LaminarContextManager, r as observeExperimentalDecorator, s as getTracerProvider, t as observe, u as initializeLaminarInstrumentations } from "./decorators-BDFgXfgI.mjs";
4
+ import { SpanKind, SpanStatusCode, TraceFlags, context, trace } from "@opentelemetry/api";
5
5
  import * as cliProgress from "cli-progress";
6
6
  //#region src/datasets.ts
7
7
  const DEFAULT_FETCH_SIZE = 25;
@@ -56,7 +56,7 @@ var LaminarDataset = class extends EvaluationDataset {
56
56
  */
57
57
  async push(paths, recursive = false) {
58
58
  if (!this.client) throw new Error("Client not set");
59
- const { loadFromPaths } = await import("./file-utils-C-auksVC.mjs").then((n) => n.t);
59
+ const { loadFromPaths } = await import("./file-utils-CHoR9VB8.mjs").then((n) => n.t);
60
60
  const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
61
61
  if (data.length === 0) {
62
62
  console.warn("No data to push. Skipping");
@@ -75,7 +75,7 @@ var LaminarDataset = class extends EvaluationDataset {
75
75
  loadEnv();
76
76
  const DEFAULT_CONCURRENCY = 5;
77
77
  const MAX_EXPORT_BATCH_SIZE = 64;
78
- const logger = initializeLogger();
78
+ const logger$1 = initializeLogger();
79
79
  const getEvaluationUrl = (projectId, evaluationId, baseUrl, frontendPort) => {
80
80
  return `${getFrontendUrl(baseUrl, frontendPort)}/project/${projectId}/evaluations/${evaluationId}`;
81
81
  };
@@ -148,7 +148,7 @@ var Evaluation = class {
148
148
  this.name = name;
149
149
  if (config) {
150
150
  if (config.concurrencyLimit !== void 0 && config.concurrencyLimit < 1) {
151
- logger.warn(`concurrencyLimit must be greater than 0. Setting to default of ${DEFAULT_CONCURRENCY}`);
151
+ logger$1.warn(`concurrencyLimit must be greater than 0. Setting to default of ${DEFAULT_CONCURRENCY}`);
152
152
  this.concurrencyLimit = DEFAULT_CONCURRENCY;
153
153
  } else this.concurrencyLimit = config.concurrencyLimit ?? DEFAULT_CONCURRENCY;
154
154
  this.traceDisableBatch = config.traceDisableBatch ?? false;
@@ -160,7 +160,7 @@ var Evaluation = class {
160
160
  baseUrl: Laminar.getHttpUrl(),
161
161
  projectApiKey: Laminar.getProjectApiKey()
162
162
  });
163
- if (config?.projectApiKey && config.projectApiKey !== Laminar.getProjectApiKey()) logger.warn("Laminar was already initialized with a different project API key. Ignoring the project API key from the evaluation config.");
163
+ if (config?.projectApiKey && config.projectApiKey !== Laminar.getProjectApiKey()) logger$1.warn("Laminar was already initialized with a different project API key. Ignoring the project API key from the evaluation config.");
164
164
  return;
165
165
  }
166
166
  const key = config?.projectApiKey ?? process.env.LMNR_PROJECT_API_KEY;
@@ -192,9 +192,9 @@ var Evaluation = class {
192
192
  if (!this.data.id) try {
193
193
  const datasets = await this.client.datasets.getDatasetByName(this.data.name);
194
194
  if (datasets.length > 0) this.data.id = datasets[0].id;
195
- else logger.warn(`Dataset ${this.data.name} not found`);
195
+ else logger$1.warn(`Dataset ${this.data.name} not found`);
196
196
  } catch (error) {
197
- logger.warn(`Error getting dataset ${this.data.name}: ${error instanceof Error ? error.message : String(error)}`);
197
+ logger$1.warn(`Error getting dataset ${this.data.name}: ${error instanceof Error ? error.message : String(error)}`);
198
198
  }
199
199
  }
200
200
  let resultDatapoints;
@@ -862,6 +862,559 @@ function wrapLanguageModel(languageModel) {
862
862
  return new LaminarLanguageModelV2(languageModel);
863
863
  }
864
864
  //#endregion
865
- export { EvaluationDataset as Dataset, HumanEvaluator, Laminar, LaminarAttributes, LaminarClient, LaminarDataset, LaminarSpanProcessor, TracingLevel, evaluate, getTracer, getTracerProvider, initializeLaminarInstrumentations, instrumentClaudeAgentQuery, observe, observeDecorator, observeExperimentalDecorator, withTracingLevel, wrapAISDK, wrapLanguageModel };
865
+ //#region src/opentelemetry-lib/instrumentation/mastra/types.ts
866
+ const MastraSpanType = {
867
+ MODEL_GENERATION: "model_generation",
868
+ MODEL_STEP: "model_step",
869
+ MODEL_CHUNK: "model_chunk",
870
+ TOOL_CALL: "tool_call",
871
+ MCP_TOOL_CALL: "mcp_tool_call"
872
+ };
873
+ //#endregion
874
+ //#region src/opentelemetry-lib/instrumentation/mastra/utils.ts
875
+ const dateToHrTime = (date) => {
876
+ const ms = date.getTime();
877
+ return [Math.floor(ms / 1e3), ms % 1e3 * 1e6];
878
+ };
879
+ const normalizeProvider = (provider) => provider.split(".").shift()?.toLowerCase().trim() || provider.toLowerCase().trim();
880
+ const mapLaminarSpanType = (spanType) => {
881
+ switch (spanType) {
882
+ case MastraSpanType.MODEL_STEP: return "LLM";
883
+ case MastraSpanType.TOOL_CALL:
884
+ case MastraSpanType.MCP_TOOL_CALL: return "TOOL";
885
+ default: return "DEFAULT";
886
+ }
887
+ };
888
+ const serializeJSON = (value) => {
889
+ if (typeof value === "string") return value;
890
+ try {
891
+ return JSON.stringify(value);
892
+ } catch {
893
+ return "[unserializable]";
894
+ }
895
+ };
896
+ const toAttributeValue = (value) => {
897
+ if (value === void 0 || value === null) return void 0;
898
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
899
+ if (Array.isArray(value)) {
900
+ if (value.every((v) => typeof v === "string")) return value;
901
+ if (value.every((v) => typeof v === "number")) return value;
902
+ if (value.every((v) => typeof v === "boolean")) return value;
903
+ }
904
+ return serializeJSON(value);
905
+ };
906
+ const extractMessages = (input) => {
907
+ if (!input) return void 0;
908
+ if (Array.isArray(input)) return input;
909
+ if (typeof input === "object") {
910
+ const asObj = input;
911
+ if (Array.isArray(asObj.messages)) return asObj.messages;
912
+ if (Array.isArray(asObj.prompt)) return asObj.prompt;
913
+ if (Array.isArray(asObj.input)) return asObj.input;
914
+ }
915
+ };
916
+ const normalizeInputMessages = (raw) => {
917
+ const out = [];
918
+ for (const m of raw) {
919
+ if (m == null) continue;
920
+ if (typeof m === "object") {
921
+ out.push(m);
922
+ continue;
923
+ }
924
+ out.push({
925
+ role: "user",
926
+ content: typeof m === "string" ? m : serializeJSON(m)
927
+ });
928
+ }
929
+ return out;
930
+ };
931
+ const buildAssistantMessageFromStepOutput = (output) => {
932
+ if (!output || typeof output !== "object") return null;
933
+ const outObj = output;
934
+ const parts = [];
935
+ if (typeof outObj.text === "string" && outObj.text.length > 0) parts.push({
936
+ type: "text",
937
+ text: outObj.text
938
+ });
939
+ if (Array.isArray(outObj.toolCalls)) for (const tc of outObj.toolCalls) {
940
+ if (!tc) continue;
941
+ parts.push({
942
+ type: "tool-call",
943
+ toolCallId: tc.toolCallId,
944
+ toolName: tc.toolName,
945
+ input: tc.input ?? tc.args
946
+ });
947
+ }
948
+ if (parts.length === 0) return null;
949
+ return {
950
+ role: "assistant",
951
+ content: parts
952
+ };
953
+ };
954
+ const extractToolCallId = (span) => {
955
+ const v = span.attributes?.toolCallId;
956
+ return typeof v === "string" ? v : void 0;
957
+ };
958
+ const cleanMastraToolName = (name) => name?.replace(/^(?:mcp_tool|tool):\s*'?(.*?)'?(?:\s+on\s+'[^']*')?$/, "$1");
959
+ const stringifyArgs = (raw) => {
960
+ if (raw === void 0) return void 0;
961
+ if (typeof raw === "string") return raw;
962
+ try {
963
+ return JSON.stringify(raw);
964
+ } catch {
965
+ return "[unserializable]";
966
+ }
967
+ };
968
+ const formatUsage = (usage) => {
969
+ if (!usage) return {};
970
+ const out = {};
971
+ if (typeof usage.inputTokens === "number") out[LaminarAttributes.INPUT_TOKEN_COUNT] = usage.inputTokens;
972
+ if (typeof usage.outputTokens === "number") out[LaminarAttributes.OUTPUT_TOKEN_COUNT] = usage.outputTokens;
973
+ const total = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
974
+ if (total > 0) out[LaminarAttributes.TOTAL_TOKEN_COUNT] = total;
975
+ if (typeof usage.inputDetails?.cacheWrite === "number") out["gen_ai.usage.cache_creation_input_tokens"] = usage.inputDetails.cacheWrite;
976
+ if (typeof usage.inputDetails?.cacheRead === "number") out["gen_ai.usage.cache_read_input_tokens"] = usage.inputDetails.cacheRead;
977
+ if (typeof usage.outputDetails?.reasoning === "number") out["gen_ai.usage.reasoning_tokens"] = usage.outputDetails.reasoning;
978
+ return out;
979
+ };
980
+ //#endregion
981
+ //#region src/opentelemetry-lib/instrumentation/mastra/exporter.ts
982
+ const logger = initializeLogger();
983
+ /**
984
+ * Bridges Mastra's ObservabilityExporter contract to Laminar's OTLP ingestion.
985
+ *
986
+ * Span-type mapping:
987
+ * - `model_step` → LLM (atomic LLM call; rendered with message history).
988
+ * - `tool_call`, `mcp_tool_call` → TOOL.
989
+ * - `model_chunk` → dropped (per-delta, noise).
990
+ * - everything else → DEFAULT.
991
+ *
992
+ * Tool-call reconstruction: Mastra's `extractStepInput` collapses prior tool
993
+ * calls/results into empty user messages on MODEL_STEP inputs, so we
994
+ * reconstruct the full conversation by accumulating (baseMessages → step0's
995
+ * assistant message → tool-result message(s) → step1's assistant message →
996
+ * …) using the parent MODEL_GENERATION's input and the children TOOL_CALL
997
+ * spans paired by arrival order with each step's declared toolCalls.
998
+ *
999
+ * For LLM spans we emit `ai.prompt.messages` (stringified AI SDK messages
1000
+ * with tool-call / tool-result content parts) and `ai.response.text` +
1001
+ * `ai.response.toolCalls` so Laminar's backend parser threads them into
1002
+ * the LLM message history view.
1003
+ */
1004
+ var MastraExporter = class {
1005
+ constructor(options = {}) {
1006
+ this.name = "laminar";
1007
+ this.traceMap = /* @__PURE__ */ new Map();
1008
+ this.generationStateById = /* @__PURE__ */ new Map();
1009
+ this.generationAttrsById = /* @__PURE__ */ new Map();
1010
+ this.generationIdByStepId = /* @__PURE__ */ new Map();
1011
+ this.stepIndexBySpanId = /* @__PURE__ */ new Map();
1012
+ this.liveOtelSpanByMastraId = /* @__PURE__ */ new Map();
1013
+ this.warnedNotInitialized = false;
1014
+ this.config = {
1015
+ realtime: options.realtime ?? false,
1016
+ linkToActiveContext: options.linkToActiveContext ?? true
1017
+ };
1018
+ }
1019
+ init(_options) {}
1020
+ async exportTracingEvent(event) {
1021
+ const span = event.exportedSpan;
1022
+ if (span.isEvent) return;
1023
+ if (span.type === MastraSpanType.MODEL_GENERATION && span.attributes) {
1024
+ const existing = this.generationAttrsById.get(span.id);
1025
+ this.generationAttrsById.set(span.id, existing ? {
1026
+ ...existing,
1027
+ ...span.attributes
1028
+ } : { ...span.attributes });
1029
+ }
1030
+ if (event.type === "span_started") {
1031
+ this.handleSpanStarted(span);
1032
+ return;
1033
+ }
1034
+ if (event.type !== "span_ended") return;
1035
+ await this.handleSpanEnded(span);
1036
+ }
1037
+ async onTracingEvent(event) {
1038
+ await this.exportTracingEvent(event);
1039
+ }
1040
+ async flush() {
1041
+ const processor = getSpanProcessor();
1042
+ if (!processor) return;
1043
+ try {
1044
+ await processor.forceFlush();
1045
+ } catch (err) {
1046
+ logger.error(`[MastraExporter] forceFlush failed: ${err instanceof Error ? err.message : String(err)}`);
1047
+ }
1048
+ }
1049
+ shutdown() {
1050
+ this.traceMap.clear();
1051
+ this.generationStateById.clear();
1052
+ this.generationAttrsById.clear();
1053
+ this.generationIdByStepId.clear();
1054
+ this.stepIndexBySpanId.clear();
1055
+ this.liveOtelSpanByMastraId.clear();
1056
+ return Promise.resolve();
1057
+ }
1058
+ handleSpanStarted(span) {
1059
+ if (span.type === MastraSpanType.MODEL_CHUNK) return;
1060
+ const traceState = this.getOrCreateTraceState(span.traceId);
1061
+ const parentId = span.parentSpanId;
1062
+ this.recordSpanPath(span, traceState);
1063
+ traceState.activeSpanIds.add(span.id);
1064
+ if (span.type === MastraSpanType.MODEL_GENERATION) this.initGenerationState(span);
1065
+ else if (span.type === MastraSpanType.MODEL_STEP && parentId) {
1066
+ this.generationIdByStepId.set(span.id, parentId);
1067
+ const stepIndex = typeof span.attributes?.stepIndex === "number" ? span.attributes.stepIndex : 0;
1068
+ this.stepIndexBySpanId.set(span.id, stepIndex);
1069
+ }
1070
+ this.startOtelSpan(span, traceState);
1071
+ }
1072
+ recordSpanPath(span, traceState) {
1073
+ const parentId = span.parentSpanId;
1074
+ const parentPath = parentId ? traceState.spanPathById.get(parentId) : traceState.otelParentSpanPath;
1075
+ const parentIdsPath = parentId ? traceState.spanIdsPathById.get(parentId) : traceState.otelParentSpanIdsPath;
1076
+ const spanUuid = otelSpanIdToUUID(normalizeOtelSpanId(span.id));
1077
+ const spanPath = parentPath ? [...parentPath, span.name] : [span.name];
1078
+ const spanIdsPath = parentIdsPath ? [...parentIdsPath, spanUuid] : [spanUuid];
1079
+ traceState.spanPathById.set(span.id, spanPath);
1080
+ traceState.spanIdsPathById.set(span.id, spanIdsPath);
1081
+ }
1082
+ async handleSpanEnded(span) {
1083
+ if (span.type === MastraSpanType.MODEL_CHUNK) {
1084
+ this.captureReasoningChunk(span);
1085
+ return;
1086
+ }
1087
+ const traceState = this.getOrCreateTraceState(span.traceId);
1088
+ try {
1089
+ if (!traceState.spanPathById.has(span.id)) {
1090
+ this.recordSpanPath(span, traceState);
1091
+ traceState.activeSpanIds.add(span.id);
1092
+ }
1093
+ if (span.type === MastraSpanType.MODEL_GENERATION && !this.generationStateById.has(span.id)) this.initGenerationState(span);
1094
+ if (span.type === MastraSpanType.MODEL_STEP && !this.generationIdByStepId.has(span.id) && span.parentSpanId) this.generationIdByStepId.set(span.id, span.parentSpanId);
1095
+ if (!this.liveOtelSpanByMastraId.has(span.id)) this.startOtelSpan(span, traceState);
1096
+ this.updateGenerationStateOnSpanEnd(span);
1097
+ const otelSpan = this.liveOtelSpanByMastraId.get(span.id);
1098
+ if (!otelSpan) return;
1099
+ this.applyEndAttributes(span, otelSpan, traceState);
1100
+ if (span.errorInfo) {
1101
+ otelSpan.setStatus({
1102
+ code: SpanStatusCode.ERROR,
1103
+ message: span.errorInfo.message
1104
+ });
1105
+ otelSpan.recordException({
1106
+ name: span.errorInfo.name ?? "Error",
1107
+ message: span.errorInfo.message,
1108
+ stack: span.errorInfo.stack
1109
+ });
1110
+ }
1111
+ const endTime = span.endTime ? dateToHrTime(span.endTime) : dateToHrTime(span.startTime);
1112
+ otelSpan.end(endTime);
1113
+ if (this.config.realtime) await getSpanProcessor()?.forceFlush();
1114
+ } catch (err) {
1115
+ logger.error(`[MastraExporter] failed to export span ${span.id}: ${err instanceof Error ? err.message : String(err)}`);
1116
+ } finally {
1117
+ traceState.activeSpanIds.delete(span.id);
1118
+ if (traceState.activeSpanIds.size === 0) this.traceMap.delete(span.traceId);
1119
+ if (span.type === MastraSpanType.MODEL_GENERATION) {
1120
+ this.generationStateById.delete(span.id);
1121
+ this.generationAttrsById.delete(span.id);
1122
+ }
1123
+ if (span.type === MastraSpanType.MODEL_STEP) {
1124
+ this.generationIdByStepId.delete(span.id);
1125
+ this.stepIndexBySpanId.delete(span.id);
1126
+ }
1127
+ this.liveOtelSpanByMastraId.delete(span.id);
1128
+ }
1129
+ }
1130
+ initGenerationState(span) {
1131
+ const rawMessages = extractMessages(span.input);
1132
+ const baseMessages = rawMessages ? normalizeInputMessages(rawMessages) : [];
1133
+ this.generationStateById.set(span.id, {
1134
+ baseMessages,
1135
+ turnsByStepIndex: /* @__PURE__ */ new Map(),
1136
+ toolCallChildrenByStepIndex: /* @__PURE__ */ new Map(),
1137
+ reasoningTextByStepIndex: /* @__PURE__ */ new Map()
1138
+ });
1139
+ }
1140
+ captureReasoningChunk(span) {
1141
+ if ((span.attributes ?? {}).chunkType !== "reasoning") return;
1142
+ const output = span.output;
1143
+ if (!output || typeof output !== "object") return;
1144
+ const text = output.text;
1145
+ if (typeof text !== "string" || text.length === 0) return;
1146
+ const stepSpanId = span.parentSpanId;
1147
+ if (!stepSpanId) return;
1148
+ const generationId = this.generationIdByStepId.get(stepSpanId);
1149
+ if (!generationId) return;
1150
+ const gen = this.generationStateById.get(generationId);
1151
+ if (!gen) return;
1152
+ const stepIndex = this.stepIndexBySpanId.get(stepSpanId);
1153
+ if (stepIndex === void 0) return;
1154
+ const existing = gen.reasoningTextByStepIndex.get(stepIndex);
1155
+ gen.reasoningTextByStepIndex.set(stepIndex, existing ? existing + text : text);
1156
+ }
1157
+ updateGenerationStateOnSpanEnd(span) {
1158
+ if (span.type === MastraSpanType.MODEL_STEP) {
1159
+ const generationId = this.generationIdByStepId.get(span.id);
1160
+ if (!generationId) return;
1161
+ const gen = this.generationStateById.get(generationId);
1162
+ if (!gen) return;
1163
+ const stepIndex = this.stepIndexBySpanId.get(span.id) ?? (typeof span.attributes?.stepIndex === "number" ? span.attributes.stepIndex : 0);
1164
+ this.stepIndexBySpanId.set(span.id, stepIndex);
1165
+ const output = span.output;
1166
+ const declaredToolCalls = Array.isArray(output?.toolCalls) ? output.toolCalls : [];
1167
+ const children = gen.toolCallChildrenByStepIndex.get(stepIndex) ?? [];
1168
+ const childrenById = /* @__PURE__ */ new Map();
1169
+ for (const c of children) if (c.toolCallId) childrenById.set(c.toolCallId, c);
1170
+ const consumed = /* @__PURE__ */ new Set();
1171
+ const turnMessages = [];
1172
+ const assistantMsg = buildAssistantMessageFromStepOutput(output);
1173
+ if (assistantMsg) turnMessages.push(assistantMsg);
1174
+ for (const dec of declaredToolCalls) {
1175
+ const toolCallId = dec?.toolCallId ?? dec?.id;
1176
+ let child = toolCallId ? childrenById.get(toolCallId) : void 0;
1177
+ if (child && consumed.has(child)) child = void 0;
1178
+ if (!child) child = children.find((c) => !consumed.has(c));
1179
+ if (!child) continue;
1180
+ consumed.add(child);
1181
+ const resolvedToolCallId = toolCallId ?? child.toolCallId;
1182
+ const toolName = dec?.toolName ?? dec?.name ?? child.toolName;
1183
+ turnMessages.push({
1184
+ role: "tool",
1185
+ tool_call_id: resolvedToolCallId,
1186
+ content: [{
1187
+ type: "tool-result",
1188
+ toolCallId: resolvedToolCallId,
1189
+ toolName,
1190
+ output: child.output
1191
+ }]
1192
+ });
1193
+ }
1194
+ gen.turnsByStepIndex.set(stepIndex, turnMessages);
1195
+ } else if (span.type === MastraSpanType.TOOL_CALL || span.type === MastraSpanType.MCP_TOOL_CALL) {
1196
+ const parentId = span.parentSpanId;
1197
+ if (!parentId) return;
1198
+ const generationId = this.generationIdByStepId.get(parentId);
1199
+ if (!generationId) return;
1200
+ const gen = this.generationStateById.get(generationId);
1201
+ if (!gen) return;
1202
+ const stepIndex = this.stepIndexBySpanId.get(parentId);
1203
+ if (stepIndex === void 0) return;
1204
+ const list = gen.toolCallChildrenByStepIndex.get(stepIndex) ?? [];
1205
+ list.push({
1206
+ toolCallId: extractToolCallId(span),
1207
+ toolName: cleanMastraToolName(span.name) || "tool",
1208
+ input: span.input,
1209
+ output: span.output
1210
+ });
1211
+ gen.toolCallChildrenByStepIndex.set(stepIndex, list);
1212
+ }
1213
+ }
1214
+ getOrCreateTraceState(traceId) {
1215
+ const existing = this.traceMap.get(traceId);
1216
+ if (existing) return existing;
1217
+ const created = {
1218
+ spanPathById: /* @__PURE__ */ new Map(),
1219
+ spanIdsPathById: /* @__PURE__ */ new Map(),
1220
+ activeSpanIds: /* @__PURE__ */ new Set()
1221
+ };
1222
+ if (this.config?.linkToActiveContext) {
1223
+ const activeSpan = trace.getSpan(LaminarContextManager.getContext()) ?? trace.getActiveSpan();
1224
+ const ctx = activeSpan?.spanContext();
1225
+ if (ctx && ctx.traceId && ctx.spanId) {
1226
+ created.otelTraceId = normalizeOtelTraceId(ctx.traceId);
1227
+ created.otelRootParentSpanId = normalizeOtelSpanId(ctx.spanId);
1228
+ const attrs = activeSpan.attributes;
1229
+ if (attrs) {
1230
+ const parentPath = attrs[SPAN_PATH];
1231
+ if (Array.isArray(parentPath) && parentPath.every((p) => typeof p === "string")) created.otelParentSpanPath = parentPath;
1232
+ const parentIdsPath = attrs[SPAN_IDS_PATH];
1233
+ if (Array.isArray(parentIdsPath) && parentIdsPath.every((p) => typeof p === "string")) created.otelParentSpanIdsPath = parentIdsPath;
1234
+ }
1235
+ }
1236
+ }
1237
+ this.traceMap.set(traceId, created);
1238
+ return created;
1239
+ }
1240
+ startOtelSpan(span, traceState) {
1241
+ const tracer = getTracerProvider().getTracer("@lmnr-ai/lmnr", version);
1242
+ const parentCtx = this.buildParentContext(span, traceState);
1243
+ const otelSpan = tracer.startSpan(span.name, {
1244
+ startTime: dateToHrTime(span.startTime),
1245
+ kind: SpanKind.INTERNAL
1246
+ }, parentCtx);
1247
+ if (!otelSpan.isRecording()) {
1248
+ this.warnNotInitializedOnce();
1249
+ return;
1250
+ }
1251
+ const sdkAllocatedSpanId = otelSpan.spanContext().spanId;
1252
+ const mastraSpanId = normalizeOtelSpanId(span.id);
1253
+ const mastraTraceId = traceState.otelTraceId ?? normalizeOtelTraceId(span.traceId);
1254
+ Object.assign(otelSpan.spanContext(), {
1255
+ traceId: mastraTraceId,
1256
+ spanId: mastraSpanId
1257
+ });
1258
+ if (sdkAllocatedSpanId !== mastraSpanId) getSpanProcessor()?.dropPathInfo(sdkAllocatedSpanId);
1259
+ const parentSpanIdNormalized = span.parentSpanId ? normalizeOtelSpanId(span.parentSpanId) : traceState.otelRootParentSpanId;
1260
+ if (parentSpanIdNormalized) {
1261
+ const parentSpanContext = {
1262
+ traceId: mastraTraceId,
1263
+ spanId: parentSpanIdNormalized,
1264
+ traceFlags: TraceFlags.SAMPLED,
1265
+ isRemote: false
1266
+ };
1267
+ Object.assign(otelSpan, {
1268
+ parentSpanId: parentSpanIdNormalized,
1269
+ parentSpanContext
1270
+ });
1271
+ } else Object.assign(otelSpan, {
1272
+ parentSpanId: void 0,
1273
+ parentSpanContext: void 0
1274
+ });
1275
+ const spanPath = traceState.spanPathById.get(span.id);
1276
+ const spanIdsPath = traceState.spanIdsPathById.get(span.id);
1277
+ if (spanPath) otelSpan.setAttribute(SPAN_PATH, spanPath);
1278
+ if (spanIdsPath) otelSpan.setAttribute(SPAN_IDS_PATH, spanIdsPath);
1279
+ this.liveOtelSpanByMastraId.set(span.id, otelSpan);
1280
+ }
1281
+ warnNotInitializedOnce() {
1282
+ if (this.warnedNotInitialized) return;
1283
+ this.warnedNotInitialized = true;
1284
+ logger.warn("[MastraExporter] Laminar tracer is not initialized — Mastra spans will be dropped. Call `Laminar.initialize({ projectApiKey: ... })` before constructing `MastraExporter`.");
1285
+ }
1286
+ buildParentContext(span, traceState) {
1287
+ const baseCtx = LaminarContextManager.getContext() ?? context.active();
1288
+ if (span.parentSpanId) {
1289
+ const parentLive = this.liveOtelSpanByMastraId.get(span.parentSpanId);
1290
+ if (parentLive) return trace.setSpan(baseCtx, parentLive);
1291
+ }
1292
+ if (traceState.otelTraceId && traceState.otelRootParentSpanId) {
1293
+ const wrapped = trace.wrapSpanContext({
1294
+ traceId: traceState.otelTraceId,
1295
+ spanId: traceState.otelRootParentSpanId,
1296
+ traceFlags: TraceFlags.SAMPLED,
1297
+ isRemote: false
1298
+ });
1299
+ return trace.setSpan(baseCtx, wrapped);
1300
+ }
1301
+ return baseCtx;
1302
+ }
1303
+ applyEndAttributes(span, otelSpan, traceState) {
1304
+ const attributes = this.buildLaminarAttributes(span, traceState);
1305
+ delete attributes[SPAN_PATH];
1306
+ delete attributes[SPAN_IDS_PATH];
1307
+ otelSpan.setAttributes(attributes);
1308
+ }
1309
+ buildLaminarAttributes(span, traceState) {
1310
+ const attributes = {};
1311
+ const spanPath = traceState.spanPathById.get(span.id);
1312
+ const spanIdsPath = traceState.spanIdsPathById.get(span.id);
1313
+ if (spanPath) attributes[SPAN_PATH] = spanPath;
1314
+ if (spanIdsPath) attributes[SPAN_IDS_PATH] = spanIdsPath;
1315
+ const laminarSpanType = mapLaminarSpanType(span.type);
1316
+ attributes[SPAN_TYPE] = laminarSpanType;
1317
+ attributes[SPAN_INSTRUMENTATION_SOURCE] = "javascript";
1318
+ attributes[SPAN_SDK_VERSION] = version;
1319
+ const langVersion = getLangVersion();
1320
+ if (langVersion) attributes[SPAN_LANGUAGE_VERSION] = langVersion;
1321
+ attributes["lmnr.internal.mastra.span_type"] = span.type;
1322
+ const metadata = span.metadata ?? {};
1323
+ const sessionId = metadata.sessionId ?? metadata.session_id;
1324
+ if (typeof sessionId === "string" && sessionId.length > 0) attributes[SESSION_ID] = sessionId;
1325
+ const userId = metadata.userId ?? metadata.user_id;
1326
+ if (typeof userId === "string" && userId.length > 0) attributes[USER_ID] = userId;
1327
+ for (const [key, value] of Object.entries(metadata)) {
1328
+ if (key === "sessionId" || key === "session_id" || key === "userId" || key === "user_id" || value === void 0 || value === null) continue;
1329
+ const av = toAttributeValue(value);
1330
+ if (av !== void 0) attributes[`${ASSOCIATION_PROPERTIES}.metadata.${key}`] = av;
1331
+ }
1332
+ if (span.isRootSpan && span.tags?.length) attributes[`${ASSOCIATION_PROPERTIES}.tags`] = span.tags;
1333
+ if (laminarSpanType === "LLM") this.applyLlmAttributes(span, attributes);
1334
+ else if (laminarSpanType === "TOOL") this.applyToolAttributes(span, attributes);
1335
+ else {
1336
+ if (span.input !== void 0) attributes[SPAN_INPUT] = serializeJSON(span.input);
1337
+ if (span.output !== void 0) attributes[SPAN_OUTPUT] = serializeJSON(span.output);
1338
+ }
1339
+ return attributes;
1340
+ }
1341
+ applyLlmAttributes(span, attributes) {
1342
+ const generationId = this.generationIdByStepId.get(span.id) ?? span.parentSpanId;
1343
+ const gen = generationId ? this.generationStateById.get(generationId) : void 0;
1344
+ const generationAttrs = generationId ? this.generationAttrsById.get(generationId) : void 0;
1345
+ const stepAttrs = span.attributes ?? {};
1346
+ const stepIndex = this.stepIndexBySpanId.get(span.id) ?? (typeof stepAttrs.stepIndex === "number" ? stepAttrs.stepIndex : 0);
1347
+ const provider = generationAttrs?.provider;
1348
+ const model = generationAttrs?.model;
1349
+ const responseModel = generationAttrs?.responseModel;
1350
+ if (provider) attributes[LaminarAttributes.PROVIDER] = normalizeProvider(provider);
1351
+ if (model) attributes[LaminarAttributes.REQUEST_MODEL] = model;
1352
+ if (responseModel) attributes[LaminarAttributes.RESPONSE_MODEL] = responseModel;
1353
+ else if (model) attributes[LaminarAttributes.RESPONSE_MODEL] = model;
1354
+ const usage = stepAttrs.usage ?? generationAttrs?.usage;
1355
+ Object.assign(attributes, formatUsage(usage));
1356
+ if (typeof stepAttrs.finishReason === "string") {
1357
+ attributes["gen_ai.response.finish_reason"] = stepAttrs.finishReason;
1358
+ attributes["ai.response.finishReason"] = stepAttrs.finishReason;
1359
+ }
1360
+ const messages = gen ? [...gen.baseMessages] : [];
1361
+ if (gen) for (let i = 0; i < stepIndex; i++) {
1362
+ const turn = gen.turnsByStepIndex.get(i);
1363
+ if (turn) messages.push(...turn);
1364
+ }
1365
+ if (messages.length > 0) attributes["ai.prompt.messages"] = serializeJSON(messages);
1366
+ else if (span.input !== void 0) attributes[SPAN_INPUT] = serializeJSON(span.input);
1367
+ const out = span.output;
1368
+ const reasoningText = gen?.reasoningTextByStepIndex.get(stepIndex);
1369
+ if (out && typeof out === "object") {
1370
+ const outObj = out;
1371
+ if (typeof outObj.text === "string" && outObj.text.length > 0) attributes["ai.response.text"] = outObj.text;
1372
+ const normalizedToolCalls = Array.isArray(outObj.toolCalls) && outObj.toolCalls.length > 0 ? outObj.toolCalls.map((tc) => ({
1373
+ toolCallType: tc.toolCallType ?? "function",
1374
+ toolCallId: tc.toolCallId,
1375
+ toolName: tc.toolName,
1376
+ args: stringifyArgs(tc.args ?? tc.input)
1377
+ })) : [];
1378
+ if (normalizedToolCalls.length > 0) attributes["ai.response.toolCalls"] = JSON.stringify(normalizedToolCalls);
1379
+ if (typeof reasoningText === "string" && reasoningText.length > 0) {
1380
+ const parts = [{
1381
+ type: "thinking",
1382
+ content: reasoningText
1383
+ }];
1384
+ if (typeof outObj.text === "string" && outObj.text.length > 0) parts.push({
1385
+ type: "text",
1386
+ content: outObj.text
1387
+ });
1388
+ for (const tc of normalizedToolCalls) {
1389
+ let argsObj = tc.args;
1390
+ if (typeof argsObj === "string") try {
1391
+ argsObj = JSON.parse(argsObj);
1392
+ } catch {}
1393
+ parts.push({
1394
+ type: "tool_call",
1395
+ id: tc.toolCallId,
1396
+ name: tc.toolName,
1397
+ arguments: argsObj
1398
+ });
1399
+ }
1400
+ attributes["gen_ai.output.messages"] = JSON.stringify([{
1401
+ role: "assistant",
1402
+ parts
1403
+ }]);
1404
+ }
1405
+ } else if (out !== void 0) attributes[SPAN_OUTPUT] = serializeJSON(out);
1406
+ }
1407
+ applyToolAttributes(span, attributes) {
1408
+ if (span.input !== void 0) attributes[SPAN_INPUT] = serializeJSON(span.input);
1409
+ if (span.output !== void 0) attributes[SPAN_OUTPUT] = serializeJSON(span.output);
1410
+ const toolAttrs = span.attributes ?? {};
1411
+ const cleanedName = cleanMastraToolName(span.name) || span.name;
1412
+ if (cleanedName) attributes["ai.toolCall.name"] = cleanedName;
1413
+ if (typeof toolAttrs.toolType === "string") attributes["ai.toolCall.type"] = toolAttrs.toolType;
1414
+ if (typeof toolAttrs.mcpServer === "string") attributes["mcp.server"] = toolAttrs.mcpServer;
1415
+ }
1416
+ };
1417
+ //#endregion
1418
+ export { EvaluationDataset as Dataset, HumanEvaluator, Laminar, LaminarAttributes, LaminarClient, LaminarDataset, LaminarSpanProcessor, MastraExporter, TracingLevel, evaluate, getTracer, getTracerProvider, initializeLaminarInstrumentations, instrumentClaudeAgentQuery, observe, observeDecorator, observeExperimentalDecorator, withTracingLevel, wrapAISDK, wrapLanguageModel };
866
1419
 
867
1420
  //# sourceMappingURL=index.mjs.map