@lmnr-ai/lmnr 0.8.37 → 0.8.38

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 (29) hide show
  1. package/dist/cli.cjs +2 -2
  2. package/dist/cli.d.cts +1 -1
  3. package/dist/cli.d.mts +1 -1
  4. package/dist/cli.mjs +2 -2
  5. package/dist/{dist-muQLQb9o.cjs → dist-DGDsKbQ8.cjs} +17 -3
  6. package/dist/dist-DGDsKbQ8.cjs.map +1 -0
  7. package/dist/{dist-CdR_Phvb.mjs → dist-DVpPVAC5.mjs} +6 -4
  8. package/dist/dist-DVpPVAC5.mjs.map +1 -0
  9. package/dist/{evaluations-DpDwGehc.d.mts → evaluations-CzqDQADS.d.mts} +2 -30
  10. package/dist/{evaluations-D6_c4gW-.d.cts → evaluations-F6Zzae_Y.d.cts} +2 -30
  11. package/dist/{file-utils-BE3NvLX0.mjs → file-utils-D3Jj4yAt.mjs} +2 -2
  12. package/dist/{file-utils-BE3NvLX0.mjs.map → file-utils-D3Jj4yAt.mjs.map} +1 -1
  13. package/dist/{file-utils-C0oHtdus.cjs → file-utils-wA-Z77kv.cjs} +2 -2
  14. package/dist/{file-utils-C0oHtdus.cjs.map → file-utils-wA-Z77kv.cjs.map} +1 -1
  15. package/dist/index.cjs +299 -496
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +13943 -7780
  18. package/dist/index.d.mts +13943 -7780
  19. package/dist/index.mjs +301 -498
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/opentelemetry-lib/instrumentation/temporal/workflow-interceptors.cjs +71 -55
  22. package/dist/opentelemetry-lib/instrumentation/temporal/workflow-interceptors.cjs.map +1 -1
  23. package/dist/opentelemetry-lib/instrumentation/temporal/workflow-interceptors.d.cts +4410 -61
  24. package/dist/opentelemetry-lib/instrumentation/temporal/workflow-interceptors.d.mts +4410 -61
  25. package/dist/opentelemetry-lib/instrumentation/temporal/workflow-interceptors.mjs +71 -55
  26. package/dist/opentelemetry-lib/instrumentation/temporal/workflow-interceptors.mjs.map +1 -1
  27. package/package.json +26 -26
  28. package/dist/dist-CdR_Phvb.mjs.map +0 -1
  29. package/dist/dist-muQLQb9o.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-CVvi-lCc.cjs");
3
- const require_dist = require("./dist-muQLQb9o.cjs");
3
+ const require_dist = require("./dist-DGDsKbQ8.cjs");
4
4
  const require_consts = require("./consts-DV6_Ea-8.cjs");
5
5
  let _opentelemetry_api = require("@opentelemetry/api");
6
6
  let _opentelemetry_context_async_hooks = require("@opentelemetry/context-async-hooks");
@@ -19,7 +19,6 @@ let _traceloop_instrumentation_openai = require("@traceloop/instrumentation-open
19
19
  let _traceloop_instrumentation_pinecone = require("@traceloop/instrumentation-pinecone");
20
20
  let _traceloop_instrumentation_qdrant = require("@traceloop/instrumentation-qdrant");
21
21
  let _traceloop_instrumentation_together = require("@traceloop/instrumentation-together");
22
- let _traceloop_instrumentation_vertexai = require("@traceloop/instrumentation-vertexai");
23
22
  let node_child_process = require("node:child_process");
24
23
  let node_crypto = require("node:crypto");
25
24
  let node_fs = require("node:fs");
@@ -95,7 +94,7 @@ var LaminarDataset = class extends EvaluationDataset {
95
94
  */
96
95
  async push(paths, recursive = false) {
97
96
  if (!this.client) throw new Error("Client not set");
98
- const { loadFromPaths } = await Promise.resolve().then(() => require("./file-utils-C0oHtdus.cjs")).then((n) => n.file_utils_exports);
97
+ const { loadFromPaths } = await Promise.resolve().then(() => require("./file-utils-wA-Z77kv.cjs")).then((n) => n.file_utils_exports);
99
98
  const data = await loadFromPaths(Array.isArray(paths) ? paths : [paths], recursive);
100
99
  if (data.length === 0) {
101
100
  console.warn("No data to push. Skipping");
@@ -167,7 +166,10 @@ const stringifyPromptForTelemetry = (prompt) => JSON.stringify(prompt.map((messa
167
166
  ...message,
168
167
  content: typeof message.content === "string" ? message.content : message.content.map((part) => part.type === "file" ? {
169
168
  ...part,
170
- data: part.data instanceof Uint8Array ? convertDataContentToBase64String(part.data) : part.data
169
+ data: part.data instanceof Uint8Array ? convertDataContentToBase64String(part.data) : part.data && typeof part.data === "object" && part.data.type === "data" && part.data.data instanceof Uint8Array ? {
170
+ ...part.data,
171
+ data: convertDataContentToBase64String(part.data.data)
172
+ } : part.data
171
173
  } : part)
172
174
  })));
173
175
  /**
@@ -6238,8 +6240,6 @@ const initInstrumentations = (client, suppressContentTracing, sessionRecordingOp
6238
6240
  }));
6239
6241
  instrumentations.push(new _traceloop_instrumentation_anthropic.AnthropicInstrumentation({ traceContent: !suppressContentTracing }));
6240
6242
  instrumentations.push(new _traceloop_instrumentation_cohere.CohereInstrumentation({ traceContent: !suppressContentTracing }));
6241
- instrumentations.push(new _traceloop_instrumentation_vertexai.VertexAIInstrumentation({ traceContent: !suppressContentTracing }));
6242
- instrumentations.push(new _traceloop_instrumentation_vertexai.AIPlatformInstrumentation({ traceContent: !suppressContentTracing }));
6243
6243
  instrumentations.push(new _traceloop_instrumentation_bedrock.BedrockInstrumentation({ traceContent: !suppressContentTracing }));
6244
6244
  instrumentations.push(new _traceloop_instrumentation_pinecone.PineconeInstrumentation());
6245
6245
  instrumentations.push(new _traceloop_instrumentation_langchain.LangChainInstrumentation({ traceContent: !suppressContentTracing }));
@@ -6291,16 +6291,6 @@ const manuallyInitInstrumentations = (client, instrumentModules, suppressContent
6291
6291
  instrumentations.push(cohereInstrumentation);
6292
6292
  cohereInstrumentation.manuallyInstrument(instrumentModules.cohere);
6293
6293
  }
6294
- if (instrumentModules?.google_vertexai) {
6295
- const vertexaiInstrumentation = new _traceloop_instrumentation_vertexai.VertexAIInstrumentation({ traceContent: !suppressContentTracing });
6296
- instrumentations.push(vertexaiInstrumentation);
6297
- vertexaiInstrumentation.manuallyInstrument(instrumentModules.google_vertexai);
6298
- }
6299
- if (instrumentModules?.google_aiplatform) {
6300
- const aiplatformInstrumentation = new _traceloop_instrumentation_vertexai.AIPlatformInstrumentation({ traceContent: !suppressContentTracing });
6301
- instrumentations.push(aiplatformInstrumentation);
6302
- aiplatformInstrumentation.manuallyInstrument(instrumentModules.google_aiplatform);
6303
- }
6304
6294
  if (instrumentModules?.bedrock) {
6305
6295
  const bedrockInstrumentation = new _traceloop_instrumentation_bedrock.BedrockInstrumentation({ traceContent: !suppressContentTracing });
6306
6296
  instrumentations.push(bedrockInstrumentation);
@@ -7325,260 +7315,6 @@ async function evaluate({ data, executor, evaluators, groupName, name, metadata,
7325
7315
  else return await evaluation.run();
7326
7316
  }
7327
7317
  //#endregion
7328
- //#region src/debug/aisdk-normalize.ts
7329
- const isRecord = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
7330
- /** Mirror Rust `is_url`. */
7331
- const isUrl = (data) => data.startsWith("http://") || data.startsWith("https://") || data.startsWith("data:");
7332
- /** Mirror Rust `infer_image_type`. */
7333
- const inferImageType = (base64) => {
7334
- if (base64.startsWith("/9j/")) return "image/jpeg";
7335
- if (base64.startsWith("iVBORw0KGgo")) return "image/png";
7336
- if (base64.startsWith("R0lGODlh")) return "image/gif";
7337
- if (base64.startsWith("UklGR")) return "image/webp";
7338
- if (base64.startsWith("PHN2Zz")) return "image/svg+xml";
7339
- return "image/png";
7340
- };
7341
- const base64FromBytes = (bytes) => {
7342
- let latin1 = "";
7343
- for (const b of bytes) latin1 += String.fromCharCode(b & 255);
7344
- return btoa(latin1);
7345
- };
7346
- /**
7347
- * Mirror Rust `json_value_to_string`: a JSON string stays itself; anything else
7348
- * is compact-serialized. With serde `preserve_order` on, `JSON.stringify` matches
7349
- * `serde_json::Value::to_string()` byte-for-byte for object key order.
7350
- */
7351
- const jsonValueToString = (value) => typeof value === "string" ? value : JSON.stringify(value);
7352
- /** First string among the candidates (ports serde field aliases). */
7353
- const firstString = (...candidates) => {
7354
- for (const c of candidates) if (typeof c === "string") return c;
7355
- };
7356
- /**
7357
- * Port of `InstrumentationChatMessageImage` (untagged) →
7358
- * `from_instrumentation_content_part`'s `Image` arm. Returns the output
7359
- * `ChatMessageContentPart` object, or `null` if no untagged variant matches.
7360
- */
7361
- const parseImage = (e) => {
7362
- if (isRecord(e.source)) {
7363
- const src = e.source;
7364
- if (typeof src.media_type === "string" && typeof src.data === "string") return {
7365
- type: "image",
7366
- mediaType: src.media_type,
7367
- data: src.data
7368
- };
7369
- if (typeof src.url === "string") return {
7370
- type: "image_url",
7371
- url: src.url,
7372
- detail: typeof src.detail === "string" ? src.detail : null
7373
- };
7374
- }
7375
- if (Array.isArray(e.image) && e.image.every((n) => typeof n === "number")) {
7376
- const b64 = base64FromBytes(e.image);
7377
- return {
7378
- type: "image_url",
7379
- url: `data:${typeof e.mime_type === "string" ? e.mime_type : inferImageType(b64)};base64,${b64}`,
7380
- detail: null
7381
- };
7382
- }
7383
- if (typeof e.image === "string") {
7384
- if (isUrl(e.image)) return {
7385
- type: "image_url",
7386
- url: e.image,
7387
- detail: null
7388
- };
7389
- return {
7390
- type: "image",
7391
- data: e.image,
7392
- mediaType: typeof e.mime_type === "string" ? e.mime_type : "image/png"
7393
- };
7394
- }
7395
- return null;
7396
- };
7397
- /** Port of the `Document` arm (only the Base64 source shape exists). */
7398
- const parseDocument = (e) => {
7399
- if (!isRecord(e.source) || e.source.type !== "base64") return null;
7400
- const data = e.source.data;
7401
- if (typeof data !== "string") return null;
7402
- return {
7403
- type: "document",
7404
- source: {
7405
- type: "base64",
7406
- media_type: firstString(e.source.media_type, e.source.mediaType) ?? "application/octet-stream",
7407
- data
7408
- }
7409
- };
7410
- };
7411
- const DATA_URL_RE = /^data:((?:application|image)\/[a-zA-Z-]+);base64,/;
7412
- /**
7413
- * Port of the `File` arm (OpenAI file-id / base64, AI SDK v1/v2).
7414
- *
7415
- * Known parity gap (v7 + image-by-URL only): on AI SDK v7 the recording path
7416
- * stores `ai.prompt.messages` from the user-facing `ModelMessage[]` (an image
7417
- * passed by URL is a `{type:"image", image:"https://…"}` part), which the
7418
- * server reshapes via `parseImage` into an `image_url`. Replay instead hashes
7419
- * the LanguageModel-level prompt, where that same image is already a
7420
- * `{type:"file", data:"https://…", mediaType:"image/*"}` part — this arm maps
7421
- * it to `image`, not `image_url`, so the two hashes diverge and the lookup
7422
- * MISSes (degrading safely to a live call). This can't be reconciled here: the
7423
- * arm is a faithful port of the server's Rust `parseFile`, so on v6 (where the
7424
- * server itself reshapes a file part) emitting `image_url` would instead BREAK
7425
- * parity, and the replay wrapper has no signal for which SDK version recorded
7426
- * the span. Plain text, multi-part text, tool calls, and base64 images all hash
7427
- * identically across both paths; only URL-referenced images on v7 are affected.
7428
- */
7429
- const parseFile = (e) => {
7430
- if (isRecord(e.file)) {
7431
- const file = e.file;
7432
- if (typeof file.file_id === "string") return {
7433
- type: "text",
7434
- text: JSON.stringify({ file_id: file.file_id })
7435
- };
7436
- if (typeof file.file_data === "string") {
7437
- const m = DATA_URL_RE.exec(file.file_data.slice(0, 50));
7438
- return {
7439
- type: "document",
7440
- source: {
7441
- type: "base64",
7442
- media_type: m ? m[1] : "application/octet-stream",
7443
- data: m ? file.file_data.slice(file.file_data.indexOf(",") + 1) : file.file_data
7444
- }
7445
- };
7446
- }
7447
- return null;
7448
- }
7449
- if (typeof e.data === "string") {
7450
- const mediaType = firstString(e.media_type, e.mediaType, e.mime_type);
7451
- if (mediaType === void 0) return null;
7452
- if (mediaType.startsWith("image/")) return {
7453
- type: "image",
7454
- data: e.data,
7455
- mediaType
7456
- };
7457
- return {
7458
- type: "document",
7459
- source: {
7460
- type: "base64",
7461
- media_type: mediaType,
7462
- data: e.data
7463
- }
7464
- };
7465
- }
7466
- return null;
7467
- };
7468
- /**
7469
- * Port of `serde_json::from_value::<InstrumentationChatMessageContentPart>` for a
7470
- * single part, returning the mapped output `ChatMessageContentPart` object or
7471
- * `null` when no variant matches (an unrecognized `type`, or a recognized tag
7472
- * whose inner shape fails). `null` propagates to an all-or-nothing Text fallback.
7473
- *
7474
- * Output objects carry serde's serialized field names; `skip_serializing_if` is
7475
- * reproduced by omitting the field (ChatMessage.tool_call_id only), and `Option`
7476
- * fields WITHOUT skip (`detail`, tool-call `id`/`arguments`) always emit `null`.
7477
- */
7478
- const parsePart = (el) => {
7479
- if (!isRecord(el)) return null;
7480
- switch (el.type) {
7481
- case "text": {
7482
- const text = firstString(el.text, el.input_text, el.output_text);
7483
- return text === void 0 ? null : {
7484
- type: "text",
7485
- text
7486
- };
7487
- }
7488
- case "image_url": {
7489
- if (!isRecord(el.image_url) || typeof el.image_url.url !== "string") return null;
7490
- const detail = el.image_url.detail;
7491
- return {
7492
- type: "image_url",
7493
- url: el.image_url.url,
7494
- detail: typeof detail === "string" ? detail : null
7495
- };
7496
- }
7497
- case "image": return parseImage(el);
7498
- case "document": return parseDocument(el);
7499
- case "file": return parseFile(el);
7500
- case "tool-call": {
7501
- if (typeof el.toolName !== "string") return null;
7502
- const rawInput = "input" in el ? el.input : el.args;
7503
- return {
7504
- type: "tool_call",
7505
- name: el.toolName,
7506
- id: typeof el.toolCallId === "string" ? el.toolCallId : null,
7507
- arguments: rawInput === void 0 || rawInput === null ? null : rawInput
7508
- };
7509
- }
7510
- case "tool-result":
7511
- if (typeof el.toolCallId !== "string" || typeof el.toolName !== "string") return null;
7512
- if (!("output" in el || "result" in el)) return null;
7513
- return {
7514
- type: "tool-result",
7515
- toolCallId: el.toolCallId,
7516
- output: "output" in el ? el.output : el.result,
7517
- toolName: el.toolName
7518
- };
7519
- default: return null;
7520
- }
7521
- };
7522
- /**
7523
- * Port of `input_chat_messages_from_json`. `input` is the parsed
7524
- * `ai.prompt.messages` array. Each message's `content` becomes either a
7525
- * `ContentPartList` (when EVERY element parses as an instrumentation part) or a
7526
- * Text blob (`json_value_to_string` of the whole content) otherwise. A message
7527
- * missing `role`/`content` would be a server error; we skip it defensively so the
7528
- * hash is still computed over the well-formed remainder.
7529
- */
7530
- const inputChatMessagesFromJson = (input) => {
7531
- if (!Array.isArray(input)) return [];
7532
- const messages = [];
7533
- for (const message of input) {
7534
- if (!isRecord(message)) continue;
7535
- const role = message.role;
7536
- if (typeof role !== "string" || !("content" in message)) continue;
7537
- const otelContent = message.content;
7538
- let parts = null;
7539
- if (Array.isArray(otelContent)) {
7540
- parts = [];
7541
- for (const el of otelContent) {
7542
- const parsed = parsePart(el);
7543
- if (parsed === null) {
7544
- parts = null;
7545
- break;
7546
- }
7547
- parts.push(parsed);
7548
- }
7549
- }
7550
- const out = {
7551
- role,
7552
- content: parts !== null ? parts : jsonValueToString(otelContent)
7553
- };
7554
- if (typeof message.tool_call_id === "string") out.tool_call_id = message.tool_call_id;
7555
- messages.push(out);
7556
- }
7557
- return messages;
7558
- };
7559
- /**
7560
- * Reshape an AI SDK call's `options.prompt` into the reconstructed message array
7561
- * the server hashes. Version-agnostic: `stringifyPromptForTelemetry` already
7562
- * normalizes V2/V3/V4 prompts (Uint8Array file `data` → base64) into the stored
7563
- * `ai.prompt.messages` JSON, and the reshape operates on that JSON identically
7564
- * across versions.
7565
- *
7566
- * Returns `null` when the prompt cannot be reshaped at all (a `stringify` /
7567
- * `JSON.parse` failure). The caller MUST treat `null` as "can't compute a real
7568
- * key" and degrade to a live call WITHOUT latching: hashing a default/empty
7569
- * payload here would key the lookup off the wrong bytes, force a spurious MISS,
7570
- * and wrongly latch live mode for the rest of the replay.
7571
- */
7572
- const extractInputMessages = (options) => {
7573
- let aiPromptMessages;
7574
- try {
7575
- aiPromptMessages = JSON.parse(stringifyPromptForTelemetry(options.prompt));
7576
- } catch {
7577
- return null;
7578
- }
7579
- return inputChatMessagesFromJson(aiPromptMessages);
7580
- };
7581
- //#endregion
7582
7318
  //#region src/debug/hash.ts
7583
7319
  /**
7584
7320
  * Debug-replay input hashing.
@@ -7586,13 +7322,13 @@ const extractInputMessages = (options) => {
7586
7322
  * Computes the per-LLM-call `input_hash` the server-side debugger cache (v2) is
7587
7323
  * keyed by. The SDK and the Rust app-server MUST produce byte-identical hashes,
7588
7324
  * so this is a faithful port of the app-server primitives:
7589
- * - `canonical_json` — `app-server/src/traces/input_dedup.rs`
7590
- * - `extract_system_message`— `app-server/src/traces/prompt_hash.rs`
7591
- * - `debug_input_hash` — `app-server/src/traces/debug_cache.rs` (plan 01 §3)
7325
+ * - `canonical_json` — `app-server/src/traces/input_dedup.rs`
7326
+ * - `debug_input_hash` — `app-server/src/traces/input_dedup.rs`
7592
7327
  *
7593
- * The whole non-system message array is hashed as ONE blob: strip the first
7594
- * `role === "system"` message (when its text is non-empty), canonicalize the
7595
- * remaining array, then blake3 over its UTF-8 bytes and hex-encode the digest.
7328
+ * The whole non-system message array is hashed as ONE blob: strip EVERY
7329
+ * `role === "system"` message (regardless of content or position), canonicalize
7330
+ * the remaining array, then blake3 over its UTF-8 bytes and hex-encode the
7331
+ * digest.
7596
7332
  *
7597
7333
  * Keep this file line-comparable with the Python `debug/hash.py`.
7598
7334
  */
@@ -7613,53 +7349,25 @@ const canonicalJson = (value) => {
7613
7349
  return JSON.stringify(value);
7614
7350
  };
7615
7351
  /**
7616
- * Extract the system prompt text from a system-role message, or "" when none.
7352
+ * Drop EVERY `role === "system"` message, matching the server.
7617
7353
  *
7618
- * Faithful port of Rust `extract_system_message`'s text resolution: a plain
7619
- * string content, else an array of `{text}` blocks joined by a space (only when
7620
- * the join is non-empty), else `parts[0].text` / `parts[0].content`.
7354
+ * Content and position are irrelevant: an empty system string, a block-array
7355
+ * system, or repeated/trailing system messages are all stripped. The coding
7356
+ * agent may add/remove/edit its own system prompt(s) between iterations and
7357
+ * those edits must not change the cache key.
7621
7358
  */
7622
- const systemMessageText = (sysMsg) => {
7623
- const content = sysMsg.content;
7624
- if (typeof content === "string") return content;
7625
- if (Array.isArray(content)) {
7626
- const joined = content.map((block) => block !== null && typeof block === "object" ? block.text : void 0).filter((t) => typeof t === "string").join(" ");
7627
- if (joined.length > 0) return joined;
7628
- }
7629
- const parts = sysMsg.parts;
7630
- if (Array.isArray(parts) && parts.length > 0) {
7631
- const first = parts[0];
7632
- if (first !== null && typeof first === "object") {
7633
- const f = first;
7634
- const t = typeof f.text === "string" ? f.text : f.content;
7635
- if (typeof t === "string") return t;
7636
- }
7637
- }
7638
- return "";
7639
- };
7359
+ const stripSystemMessages = (messages) => messages.filter((m) => !(m !== null && typeof m === "object" && m.role === "system"));
7640
7360
  /**
7641
- * Drop the first `role === "system"` message, matching the server.
7361
+ * Compute the hex blake3 `input_hash` for a message array.
7642
7362
  *
7643
- * Returns the array unchanged when there is no system message OR when the system
7644
- * message's resolved text is empty (Rust `extract_system_message` returns `None`
7645
- * in both cases, leaving the system message in the hashed array).
7646
- */
7647
- const stripSystemMessage = (messages) => {
7648
- const sysIdx = messages.findIndex((m) => m !== null && typeof m === "object" && m.role === "system");
7649
- if (sysIdx === -1) return messages;
7650
- if (systemMessageText(messages[sysIdx]).length === 0) return messages;
7651
- return messages.filter((_, i) => i !== sysIdx);
7652
- };
7653
- /**
7654
- * Compute the hex blake3 `input_hash` for a reconstructed message array.
7655
- *
7656
- * `messages` must already be the server's reconstructed shape (the SDK reshapes
7657
- * provider-specific prompts via `aisdk-normalize.ts` so the hashed bytes match
7658
- * what `spans_v0` stores). The system message is stripped, the remainder
7659
- * canonicalized, and the digest hex-encoded (64 chars).
7363
+ * `messages` is the verbatim LanguageModel-level prompt
7364
+ * (`JSON.parse(stringifyPromptForTelemetry(options.prompt))`) the same bytes
7365
+ * the SDK records as `gen_ai.input.messages` and the server hashes on ingest.
7366
+ * System messages are stripped, the remainder canonicalized, and the digest
7367
+ * hex-encoded (64 chars).
7660
7368
  */
7661
7369
  const debugInputHash = (messages) => {
7662
- const canonical = canonicalJson(stripSystemMessage(messages));
7370
+ const canonical = canonicalJson(stripSystemMessages(messages));
7663
7371
  return (0, _noble_hashes_utils_js.bytesToHex)((0, _noble_hashes_blake3_js.blake3)(new TextEncoder().encode(canonical)));
7664
7372
  };
7665
7373
  //#endregion
@@ -7719,6 +7427,107 @@ const removeActiveLlmSpan = (span) => {
7719
7427
  /** Most recently pushed still-open LLM span, or undefined if none. */
7720
7428
  const peekActiveLlmSpan = () => openLlmSpans.length > 0 ? openLlmSpans[openLlmSpans.length - 1] : void 0;
7721
7429
  //#endregion
7430
+ //#region src/opentelemetry-lib/instrumentation/aisdk/v7-integration/utils.ts
7431
+ const serializeJSON$1 = (value) => {
7432
+ if (typeof value === "string") return value;
7433
+ try {
7434
+ return JSON.stringify(value);
7435
+ } catch {
7436
+ return "[unserializable]";
7437
+ }
7438
+ };
7439
+ const normalizeProvider$1 = (provider) => {
7440
+ if (!provider) return void 0;
7441
+ return provider.split(".").shift()?.toLowerCase().trim() || provider.toLowerCase().trim() || void 0;
7442
+ };
7443
+ const applyUsage = (attributes, usage) => {
7444
+ if (!usage || typeof usage !== "object") return;
7445
+ if (typeof usage.inputTokens === "number") attributes[require_dist.LaminarAttributes.INPUT_TOKEN_COUNT] = usage.inputTokens;
7446
+ if (typeof usage.outputTokens === "number") attributes[require_dist.LaminarAttributes.OUTPUT_TOKEN_COUNT] = usage.outputTokens;
7447
+ if (typeof usage.totalTokens === "number") attributes[require_dist.LaminarAttributes.TOTAL_TOKEN_COUNT] = usage.totalTokens;
7448
+ else if (typeof usage.inputTokens === "number" || typeof usage.outputTokens === "number") attributes[require_dist.LaminarAttributes.TOTAL_TOKEN_COUNT] = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
7449
+ if (typeof usage.reasoningTokens === "number") attributes["gen_ai.usage.reasoning_tokens"] = usage.reasoningTokens;
7450
+ else if (typeof usage.outputTokenDetails?.reasoningTokens === "number") attributes["gen_ai.usage.reasoning_tokens"] = usage.outputTokenDetails.reasoningTokens;
7451
+ if (typeof usage.cachedInputTokens === "number") attributes["gen_ai.usage.cache_read_input_tokens"] = usage.cachedInputTokens;
7452
+ else if (typeof usage.inputTokenDetails?.cacheReadTokens === "number") attributes["gen_ai.usage.cache_read_input_tokens"] = usage.inputTokenDetails.cacheReadTokens;
7453
+ if (typeof usage.inputTokenDetails?.cacheWriteTokens === "number") attributes["gen_ai.usage.cache_creation_input_tokens"] = usage.inputTokenDetails.cacheWriteTokens;
7454
+ };
7455
+ const verbatimStandardizedMessages = (event) => {
7456
+ const messages = [];
7457
+ const sys = event.instructions || event.system;
7458
+ if (typeof sys === "string" && sys.length > 0) messages.push({
7459
+ role: "system",
7460
+ content: sys
7461
+ });
7462
+ else if (Array.isArray(sys)) for (const m of sys) messages.push(m);
7463
+ else if (sys && typeof sys === "object") messages.push(sys);
7464
+ if (Array.isArray(event.messages)) for (const m of event.messages) messages.push(m);
7465
+ return messages;
7466
+ };
7467
+ const buildVerbatimOutputMessages = (content) => {
7468
+ if (!Array.isArray(content) || content.length === 0) return void 0;
7469
+ try {
7470
+ return JSON.stringify([{
7471
+ role: "assistant",
7472
+ content
7473
+ }]);
7474
+ } catch {
7475
+ return;
7476
+ }
7477
+ };
7478
+ const buildTextOutputMessages = (text) => text.length > 0 ? buildVerbatimOutputMessages([{
7479
+ type: "text",
7480
+ text
7481
+ }]) : void 0;
7482
+ const applyUsageToSpan = (span, usage) => {
7483
+ const attrs = {};
7484
+ applyUsage(attrs, usage);
7485
+ for (const [k, v] of Object.entries(attrs)) if (v !== void 0) span.setAttribute(k, v);
7486
+ };
7487
+ const applyFinishReason = (span, finishReason) => {
7488
+ span.setAttribute("gen_ai.response.finish_reason", finishReason);
7489
+ span.setAttribute("ai.response.finishReason", finishReason);
7490
+ };
7491
+ const applyRequestModelAttributes = (span, event) => {
7492
+ if (typeof event.provider === "string") {
7493
+ const provider = normalizeProvider$1(event.provider);
7494
+ if (provider) span.setAttribute(require_dist.LaminarAttributes.PROVIDER, provider);
7495
+ span.setAttribute("ai.model.provider", event.provider);
7496
+ }
7497
+ if (typeof event.modelId === "string") {
7498
+ span.setAttribute(require_dist.LaminarAttributes.REQUEST_MODEL, event.modelId);
7499
+ span.setAttribute("ai.model.id", event.modelId);
7500
+ }
7501
+ };
7502
+ const compareHrTime = (a, b) => {
7503
+ if (a[0] !== b[0]) return a[0] - b[0];
7504
+ return a[1] - b[1];
7505
+ };
7506
+ const readSpanEndTime = (span) => {
7507
+ const innerEnd = span._span?.endTime;
7508
+ if (innerEnd && (innerEnd[0] !== 0 || innerEnd[1] !== 0)) return innerEnd;
7509
+ const outerEnd = span.endTime;
7510
+ if (outerEnd && (outerEnd[0] !== 0 || outerEnd[1] !== 0)) return outerEnd;
7511
+ };
7512
+ const verbatimPromptString = (prompt) => {
7513
+ try {
7514
+ const serialized = stringifyPromptForTelemetry(prompt);
7515
+ return typeof serialized === "string" ? serialized : null;
7516
+ } catch {
7517
+ return null;
7518
+ }
7519
+ };
7520
+ const verbatimPromptMessages = (prompt) => {
7521
+ const serialized = verbatimPromptString(prompt);
7522
+ if (serialized === null) return null;
7523
+ try {
7524
+ const parsed = JSON.parse(serialized);
7525
+ return Array.isArray(parsed) ? parsed : null;
7526
+ } catch {
7527
+ return null;
7528
+ }
7529
+ };
7530
+ //#endregion
7722
7531
  //#region src/opentelemetry-lib/instrumentation/aisdk/base-language-model.ts
7723
7532
  /**
7724
7533
  * Base class for Laminar language model wrappers.
@@ -7761,7 +7570,7 @@ var BaseLaminarLanguageModel = class {
7761
7570
  async doGenerateOrStreamWithCaching(options, originalFn, buildFromCached) {
7762
7571
  if (!replayEnabled() || Laminar.debugRunLive) return originalFn(options);
7763
7572
  const spanToMark = peekActiveLlmSpan() ?? Laminar.getCurrentSpan();
7764
- const messages = extractInputMessages(options);
7573
+ const messages = verbatimPromptMessages(options.prompt);
7765
7574
  if (messages === null || messages.length === 0) return originalFn(options);
7766
7575
  const inputHash = debugInputHash(messages);
7767
7576
  const outcome = await getRuntime()?.lookupCache(inputHash) ?? { kind: "live" };
@@ -7809,17 +7618,45 @@ var BaseLaminarLanguageModel = class {
7809
7618
  }];
7810
7619
  if (output === null || typeof output !== "object") return [];
7811
7620
  const handleItem = (item) => {
7812
- if (item.type === "text") return [{
7813
- type: "text",
7814
- text: item.text ?? item.content ?? ""
7815
- }];
7816
- if (["tool-call", "tool_call"].includes(item.type)) return [{
7621
+ if (item.type === "text") {
7622
+ if (typeof item.text === "string") return [{
7623
+ ...item,
7624
+ type: "text",
7625
+ text: item.text
7626
+ }];
7627
+ return [{
7628
+ type: "text",
7629
+ text: item.content ?? ""
7630
+ }];
7631
+ }
7632
+ if (item.type === "tool-call") return [{
7633
+ ...item,
7817
7634
  type: "tool-call",
7818
7635
  toolCallId: item.toolCallId ?? item.id,
7819
7636
  toolName: item.toolName ?? item.name,
7820
- input: JSON.stringify(item.input ?? item.arguments)
7637
+ input: typeof item.input === "string" ? item.input : JSON.stringify(item.input ?? item.arguments)
7821
7638
  }];
7822
- if (["reasoning", "thinking"].includes(item.type)) return [{
7639
+ if (item.type === "tool_call") {
7640
+ const rawInput = item.input ?? item.arguments;
7641
+ return [{
7642
+ type: "tool-call",
7643
+ toolCallId: item.toolCallId ?? item.id,
7644
+ toolName: item.toolName ?? item.name,
7645
+ input: typeof rawInput === "string" ? rawInput : JSON.stringify(rawInput)
7646
+ }];
7647
+ }
7648
+ if (item.type === "reasoning") {
7649
+ if (typeof item.text === "string") return [{
7650
+ ...item,
7651
+ type: "reasoning",
7652
+ text: item.text
7653
+ }];
7654
+ return [{
7655
+ type: "reasoning",
7656
+ text: item.content ?? ""
7657
+ }];
7658
+ }
7659
+ if (item.type === "thinking") return [{
7823
7660
  type: "reasoning",
7824
7661
  text: item.text ?? item.content ?? ""
7825
7662
  }];
@@ -7885,7 +7722,8 @@ var LaminarLanguageModelV2 = class extends BaseLaminarLanguageModel {
7885
7722
  const id = `text-${textIndex++}`;
7886
7723
  parts.push({
7887
7724
  type: "text-start",
7888
- id
7725
+ id,
7726
+ providerMetadata: block.providerMetadata
7889
7727
  });
7890
7728
  parts.push({
7891
7729
  type: "text-delta",
@@ -7913,16 +7751,15 @@ var LaminarLanguageModelV2 = class extends BaseLaminarLanguageModel {
7913
7751
  id
7914
7752
  });
7915
7753
  parts.push({
7916
- type: "tool-call",
7917
- toolCallId: block.toolCallId,
7918
- toolName: block.toolName,
7919
- input: block.input
7754
+ ...block,
7755
+ type: "tool-call"
7920
7756
  });
7921
7757
  } else if (block.type === "reasoning") {
7922
7758
  const id = `reasoning-${reasoningIndex++}`;
7923
7759
  parts.push({
7924
7760
  type: "reasoning-start",
7925
- id
7761
+ id,
7762
+ providerMetadata: block.providerMetadata
7926
7763
  });
7927
7764
  parts.push({
7928
7765
  type: "reasoning-delta",
@@ -7987,7 +7824,8 @@ var LaminarLanguageModelV3 = class extends BaseLaminarLanguageModel {
7987
7824
  const id = `text-${textIndex++}`;
7988
7825
  parts.push({
7989
7826
  type: "text-start",
7990
- id
7827
+ id,
7828
+ providerMetadata: block.providerMetadata
7991
7829
  });
7992
7830
  parts.push({
7993
7831
  type: "text-delta",
@@ -8015,16 +7853,15 @@ var LaminarLanguageModelV3 = class extends BaseLaminarLanguageModel {
8015
7853
  id
8016
7854
  });
8017
7855
  parts.push({
8018
- type: "tool-call",
8019
- toolCallId: block.toolCallId,
8020
- toolName: block.toolName,
8021
- input: block.input
7856
+ ...block,
7857
+ type: "tool-call"
8022
7858
  });
8023
7859
  } else if (block.type === "reasoning") {
8024
7860
  const id = `reasoning-${reasoningIndex++}`;
8025
7861
  parts.push({
8026
7862
  type: "reasoning-start",
8027
- id
7863
+ id,
7864
+ providerMetadata: block.providerMetadata
8028
7865
  });
8029
7866
  parts.push({
8030
7867
  type: "reasoning-delta",
@@ -8089,7 +7926,8 @@ var LaminarLanguageModelV4 = class extends BaseLaminarLanguageModel {
8089
7926
  const id = `text-${textIndex++}`;
8090
7927
  parts.push({
8091
7928
  type: "text-start",
8092
- id
7929
+ id,
7930
+ providerMetadata: block.providerMetadata
8093
7931
  });
8094
7932
  parts.push({
8095
7933
  type: "text-delta",
@@ -8117,16 +7955,15 @@ var LaminarLanguageModelV4 = class extends BaseLaminarLanguageModel {
8117
7955
  id
8118
7956
  });
8119
7957
  parts.push({
8120
- type: "tool-call",
8121
- toolCallId: block.toolCallId,
8122
- toolName: block.toolName,
8123
- input: block.input
7958
+ ...block,
7959
+ type: "tool-call"
8124
7960
  });
8125
7961
  } else if (block.type === "reasoning") {
8126
7962
  const id = `reasoning-${reasoningIndex++}`;
8127
7963
  parts.push({
8128
7964
  type: "reasoning-start",
8129
- id
7965
+ id,
7966
+ providerMetadata: block.providerMetadata
8130
7967
  });
8131
7968
  parts.push({
8132
7969
  type: "reasoning-delta",
@@ -8206,136 +8043,94 @@ function wrapLanguageModel(languageModel) {
8206
8043
  return new LaminarLanguageModelV2(languageModel);
8207
8044
  }
8208
8045
  //#endregion
8209
- //#region src/opentelemetry-lib/instrumentation/aisdk/v7-integration/types.ts
8210
- const stepKey = (callId, stepNumber) => `${callId}:${stepNumber}`;
8211
- //#endregion
8212
- //#region src/opentelemetry-lib/instrumentation/aisdk/v7-integration/utils.ts
8213
- const serializeJSON$1 = (value) => {
8214
- if (typeof value === "string") return value;
8046
+ //#region src/opentelemetry-lib/instrumentation/aisdk/v7-integration/package-versions.ts
8047
+ let cached;
8048
+ const readPackageVersion = (specifier) => {
8215
8049
  try {
8216
- return JSON.stringify(value);
8050
+ const pkg = require(`${specifier}/package.json`);
8051
+ return typeof pkg?.version === "string" ? pkg.version : void 0;
8217
8052
  } catch {
8218
- return "[unserializable]";
8053
+ return;
8219
8054
  }
8220
8055
  };
8221
- const normalizeProvider$1 = (provider) => {
8222
- if (!provider) return void 0;
8223
- return provider.split(".").shift()?.toLowerCase().trim() || provider.toLowerCase().trim() || void 0;
8224
- };
8225
- const applyUsage = (attributes, usage) => {
8226
- if (!usage || typeof usage !== "object") return;
8227
- if (typeof usage.inputTokens === "number") attributes[require_dist.LaminarAttributes.INPUT_TOKEN_COUNT] = usage.inputTokens;
8228
- if (typeof usage.outputTokens === "number") attributes[require_dist.LaminarAttributes.OUTPUT_TOKEN_COUNT] = usage.outputTokens;
8229
- if (typeof usage.totalTokens === "number") attributes[require_dist.LaminarAttributes.TOTAL_TOKEN_COUNT] = usage.totalTokens;
8230
- else if (typeof usage.inputTokens === "number" || typeof usage.outputTokens === "number") attributes[require_dist.LaminarAttributes.TOTAL_TOKEN_COUNT] = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
8231
- if (typeof usage.reasoningTokens === "number") attributes["gen_ai.usage.reasoning_tokens"] = usage.reasoningTokens;
8232
- else if (typeof usage.outputTokenDetails?.reasoningTokens === "number") attributes["gen_ai.usage.reasoning_tokens"] = usage.outputTokenDetails.reasoningTokens;
8233
- if (typeof usage.cachedInputTokens === "number") attributes["gen_ai.usage.cache_read_input_tokens"] = usage.cachedInputTokens;
8234
- else if (typeof usage.inputTokenDetails?.cacheReadTokens === "number") attributes["gen_ai.usage.cache_read_input_tokens"] = usage.inputTokenDetails.cacheReadTokens;
8235
- if (typeof usage.inputTokenDetails?.cacheWriteTokens === "number") attributes["gen_ai.usage.cache_creation_input_tokens"] = usage.inputTokenDetails.cacheWriteTokens;
8236
- };
8237
- const standardizedPromptToMessages = (event) => {
8238
- const messages = [];
8239
- const sys = event.instructions || event.system;
8240
- if (typeof sys === "string" && sys.length > 0) messages.push({
8241
- role: "system",
8242
- content: sys
8243
- });
8244
- else if (Array.isArray(sys)) for (const m of sys) messages.push(m);
8245
- else if (sys && typeof sys === "object") messages.push(sys);
8246
- if (Array.isArray(event.messages)) for (const m of event.messages) messages.push(convertRawStringTextToTextBlock(m));
8247
- return messages;
8248
- };
8249
- const convertRawStringTextToTextBlock = (m) => ({
8250
- ...m,
8251
- content: typeof m?.content === "string" ? [{
8252
- type: "text",
8253
- text: m.content
8254
- }] : m?.content
8255
- });
8256
- const normalizeToolCalls = (toolCalls) => {
8257
- if (!Array.isArray(toolCalls)) return [];
8258
- return toolCalls.map((tc) => ({
8259
- toolCallType: "function",
8260
- toolCallId: tc?.toolCallId,
8261
- toolName: tc?.toolName,
8262
- args: typeof tc?.input === "string" ? tc.input : serializeJSON$1(tc?.input ?? {})
8263
- }));
8264
- };
8265
- const buildGenAiOutputMessages = (args) => {
8266
- const parts = [];
8267
- if (args.reasoningText && args.reasoningText.length > 0) parts.push({
8268
- type: "thinking",
8269
- content: args.reasoningText
8270
- });
8271
- if (args.text && args.text.length > 0) parts.push({
8272
- type: "text",
8273
- content: args.text
8274
- });
8275
- for (const tc of args.toolCalls ?? []) {
8276
- let argsObj = tc.args;
8277
- if (typeof argsObj === "string") try {
8278
- argsObj = JSON.parse(argsObj);
8056
+ /**
8057
+ * A `node_modules` search-path entry is a package-manager-internal virtual
8058
+ * store (pnpm's `.pnpm`, yarn's `.yarn`, etc.) if any path segment starts
8059
+ * with `.` — excluding the `.`/`..` relative-path segments themselves, which
8060
+ * are unrelated. Packages resolved from inside such a store are some
8061
+ * dependency's OWN transitive deps (e.g. `ai`'s `@ai-sdk/provider`), not
8062
+ * what the host project declared, so those entries must be skipped.
8063
+ */
8064
+ const isPackageManagerInternalPath = (path) => path.split(node_path.sep).some((segment) => segment.startsWith(".") && segment !== "." && segment !== "..");
8065
+ /**
8066
+ * Given the ordered `node_modules` search-path list Node would use to
8067
+ * resolve a module from this file's location, find the closest directory
8068
+ * that actually has an `@ai-sdk` scope — skipping package-manager-internal
8069
+ * stores and return the packages listed under it. The first path with a
8070
+ * usable `@ai-sdk` directory wins; levels are not merged, so an unrelated
8071
+ * ancestor/monorepo-root's `@ai-sdk` scope is never mixed in once a closer
8072
+ * one has already matched.
8073
+ */
8074
+ const findAiSdkScopeEntries = (searchPaths) => {
8075
+ for (const path of searchPaths) {
8076
+ if (isPackageManagerInternalPath(path)) continue;
8077
+ try {
8078
+ const entries = (0, node_fs.readdirSync)((0, node_path.join)(path, "@ai-sdk"));
8079
+ if (entries.length > 0) return entries;
8279
8080
  } catch {}
8280
- parts.push({
8281
- type: "tool_call",
8282
- id: tc.toolCallId,
8283
- name: tc.toolName,
8284
- arguments: argsObj
8285
- });
8286
8081
  }
8287
- if (parts.length === 0) return void 0;
8288
- return JSON.stringify([{
8289
- role: "assistant",
8290
- parts
8291
- }]);
8082
+ return [];
8292
8083
  };
8293
- const extractTextFromContent = (content) => {
8294
- if (!Array.isArray(content)) return "";
8295
- return content.filter((p) => p && p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
8296
- };
8297
- const extractReasoningFromContent = (content) => {
8298
- if (!Array.isArray(content)) return "";
8299
- return content.filter((p) => p && p.type === "reasoning" && typeof p.text === "string").map((p) => p.text).join("");
8300
- };
8301
- const applyUsageToSpan = (span, usage) => {
8302
- const attrs = {};
8303
- applyUsage(attrs, usage);
8304
- for (const [k, v] of Object.entries(attrs)) if (v !== void 0) span.setAttribute(k, v);
8305
- };
8306
- const applyFinishReason = (span, finishReason) => {
8307
- span.setAttribute("gen_ai.response.finish_reason", finishReason);
8308
- span.setAttribute("ai.response.finishReason", finishReason);
8309
- };
8310
- const applyRequestModelAttributes = (span, event) => {
8311
- if (typeof event.provider === "string") {
8312
- const provider = normalizeProvider$1(event.provider);
8313
- if (provider) span.setAttribute(require_dist.LaminarAttributes.PROVIDER, provider);
8314
- span.setAttribute("ai.model.provider", event.provider);
8084
+ const discoverAiSdkPackages = () => {
8085
+ const packages = {};
8086
+ let searchPaths;
8087
+ try {
8088
+ searchPaths = require.resolve.paths("@ai-sdk/__probe__") ?? [];
8089
+ } catch {
8090
+ searchPaths = [];
8315
8091
  }
8316
- if (typeof event.modelId === "string") {
8317
- span.setAttribute(require_dist.LaminarAttributes.REQUEST_MODEL, event.modelId);
8318
- span.setAttribute("ai.model.id", event.modelId);
8092
+ for (const entry of findAiSdkScopeEntries(searchPaths)) {
8093
+ const specifier = `@ai-sdk/${entry}`;
8094
+ const version = readPackageVersion(specifier);
8095
+ if (version) packages[specifier] = version;
8319
8096
  }
8097
+ return packages;
8320
8098
  };
8321
- const applyPromptMessages = (span, event) => {
8322
- const msgs = standardizedPromptToMessages(event);
8323
- if (msgs.length === 0) return;
8324
- const serialized = serializeJSON$1(msgs);
8325
- span.setAttribute("ai.prompt.messages", serialized);
8326
- span.setAttribute(require_dist.SPAN_INPUT, serialized);
8327
- };
8328
- const compareHrTime = (a, b) => {
8329
- if (a[0] !== b[0]) return a[0] - b[0];
8330
- return a[1] - b[1];
8099
+ /**
8100
+ * Reads installed `ai` / `@ai-sdk/*` package versions once and caches the
8101
+ * result for the lifetime of the process — this is expected to be called on
8102
+ * every span creation, so the actual `require`/`readdirSync` work must not
8103
+ * repeat.
8104
+ */
8105
+ const getAiSdkPackageVersions = () => {
8106
+ if (cached) return cached;
8107
+ try {
8108
+ cached = {
8109
+ aiVersion: readPackageVersion("ai"),
8110
+ aiSdkPackages: discoverAiSdkPackages()
8111
+ };
8112
+ } catch {
8113
+ cached = { aiSdkPackages: {} };
8114
+ }
8115
+ return cached;
8331
8116
  };
8332
- const readSpanEndTime = (span) => {
8333
- const innerEnd = span._span?.endTime;
8334
- if (innerEnd && (innerEnd[0] !== 0 || innerEnd[1] !== 0)) return innerEnd;
8335
- const outerEnd = span.endTime;
8336
- if (outerEnd && (outerEnd[0] !== 0 || outerEnd[1] !== 0)) return outerEnd;
8117
+ /**
8118
+ * Flat span-attribute object for the `ai` package's instrumentation scope
8119
+ * plus one `lmnr.span.instrumentation.@ai-sdk/<pkg>.version` entry per
8120
+ * resolvable `@ai-sdk/*` package. Merge this into every span this
8121
+ * integration creates.
8122
+ */
8123
+ const buildAiSdkInstrumentationAttributes = () => {
8124
+ const { aiVersion, aiSdkPackages } = getAiSdkPackageVersions();
8125
+ const attributes = { [require_dist.SPAN_INSTRUMENTATION_SCOPE_NAME]: "ai" };
8126
+ if (aiVersion) attributes[require_dist.SPAN_INSTRUMENTATION_SCOPE_VERSION] = aiVersion;
8127
+ for (const [pkg, version] of Object.entries(aiSdkPackages)) attributes[`lmnr.span.instrumentation.${pkg}.version`] = version;
8128
+ return attributes;
8337
8129
  };
8338
8130
  //#endregion
8131
+ //#region src/opentelemetry-lib/instrumentation/aisdk/v7-integration/types.ts
8132
+ const stepKey = (callId, stepNumber) => `${callId}:${stepNumber}`;
8133
+ //#endregion
8339
8134
  //#region src/opentelemetry-lib/instrumentation/aisdk/v7-integration/index.ts
8340
8135
  /**
8341
8136
  * The AI SDK v7 diagnostics channel name. Every lifecycle event fires
@@ -8357,6 +8152,8 @@ var LaminarAiSdkTelemetry = class {
8357
8152
  this.llmByKey = /* @__PURE__ */ new Map();
8358
8153
  this.toolByCallId = /* @__PURE__ */ new Map();
8359
8154
  this.activeStreamStepByCallId = /* @__PURE__ */ new Map();
8155
+ this.promptByCallId = /* @__PURE__ */ new Map();
8156
+ this.logger = require_dist.initializeLogger();
8360
8157
  this.onStart = (event) => {
8361
8158
  const callId = event?.callId;
8362
8159
  if (!callId) return;
@@ -8368,6 +8165,7 @@ var LaminarAiSdkTelemetry = class {
8368
8165
  kind: _opentelemetry_api.SpanKind.CLIENT,
8369
8166
  attributes: {
8370
8167
  [require_dist.SPAN_TYPE]: "DEFAULT",
8168
+ ...buildAiSdkInstrumentationAttributes(),
8371
8169
  ...typeof event.functionId === "string" ? {
8372
8170
  "operation.name": event.functionId,
8373
8171
  "ai.prompt": "_"
@@ -8388,8 +8186,10 @@ var LaminarAiSdkTelemetry = class {
8388
8186
  if (typeof event.functionId === "string") span.setAttribute("ai.functionId", event.functionId);
8389
8187
  if (event.operationId === "ai.embed" || event.operationId === "ai.embedMany" || event.operationId === "ai.rerank") span.setAttribute(require_dist.SPAN_TYPE, "LLM");
8390
8188
  if (this.recordInputs) {
8391
- if (Array.isArray(event.messages) || event.system !== void 0 || event.instructions !== void 0) applyPromptMessages(span, event);
8392
- else if (event.value !== void 0) span.setAttribute(require_dist.SPAN_INPUT, serializeJSON$1(event.value));
8189
+ if (Array.isArray(event.messages) || event.system !== void 0 || event.instructions !== void 0) {
8190
+ const msgs = verbatimStandardizedMessages(event);
8191
+ if (msgs.length > 0) span.setAttribute(require_dist.SPAN_INPUT, serializeJSON$1(msgs));
8192
+ } else if (event.value !== void 0) span.setAttribute(require_dist.SPAN_INPUT, serializeJSON$1(event.value));
8393
8193
  else if (event.query !== void 0 || event.documents !== void 0) span.setAttribute(require_dist.SPAN_INPUT, serializeJSON$1({
8394
8194
  query: event.query,
8395
8195
  documents: event.documents
@@ -8404,17 +8204,25 @@ var LaminarAiSdkTelemetry = class {
8404
8204
  });
8405
8205
  };
8406
8206
  this.onStepStart = (event) => {
8407
- if (!this.createStepSpan) return;
8408
8207
  const callId = event?.callId;
8409
8208
  const stepNumber = event?.stepNumber ?? 0;
8410
8209
  if (!callId) return;
8210
+ if (Array.isArray(event?.promptMessages)) {
8211
+ const serialized = verbatimPromptString(event.promptMessages);
8212
+ if (serialized !== null) this.promptByCallId.set(callId, serialized);
8213
+ }
8214
+ if (!this.createStepSpan) return;
8411
8215
  const op = this.operationByCallId.get(callId);
8412
8216
  if (!op) return;
8413
8217
  const span = getTracer().startSpan(`ai.step`, { kind: _opentelemetry_api.SpanKind.CLIENT }, op.ctx);
8414
8218
  const spanCtx = _opentelemetry_api.trace.setSpan(op.ctx, span);
8415
8219
  span.setAttribute(require_dist.SPAN_TYPE, "DEFAULT");
8220
+ span.setAttributes(buildAiSdkInstrumentationAttributes());
8416
8221
  span.setAttribute("ai.step.number", stepNumber);
8417
- if (this.recordInputs) applyPromptMessages(span, event);
8222
+ if (this.recordInputs) {
8223
+ const msgs = verbatimStandardizedMessages(event);
8224
+ if (msgs.length > 0) span.setAttribute(require_dist.SPAN_INPUT, serializeJSON$1(msgs));
8225
+ }
8418
8226
  this.stepByKey.set(stepKey(callId, stepNumber), {
8419
8227
  span,
8420
8228
  ctx: spanCtx,
@@ -8430,8 +8238,17 @@ var LaminarAiSdkTelemetry = class {
8430
8238
  if (!parentCtx) return;
8431
8239
  const span = getTracer().startSpan(`ai.llm ${event.provider ?? ""}:${event.modelId ?? ""}`, { kind: _opentelemetry_api.SpanKind.CLIENT }, parentCtx);
8432
8240
  span.setAttribute(require_dist.SPAN_TYPE, "LLM");
8241
+ span.setAttributes(buildAiSdkInstrumentationAttributes());
8433
8242
  applyRequestModelAttributes(span, event);
8434
- if (this.recordInputs) applyPromptMessages(span, event);
8243
+ if (this.recordInputs) {
8244
+ if (event.tools) try {
8245
+ span.setAttribute("gen_ai.tool.definitions", JSON.stringify(event.tools));
8246
+ } catch (e) {
8247
+ this.logger.debug(`Failed to record span tool definitions: ${require_dist.errorMessage(e)}`);
8248
+ }
8249
+ const serialized = this.promptByCallId.get(callId);
8250
+ if (serialized !== void 0) span.setAttribute("gen_ai.input.messages", serialized);
8251
+ }
8435
8252
  this.llmByKey.set(stepKey(callId, stepNumber), {
8436
8253
  span,
8437
8254
  textDeltas: []
@@ -8454,18 +8271,14 @@ var LaminarAiSdkTelemetry = class {
8454
8271
  if (typeof event.responseId === "string") span.setAttribute("gen_ai.response.id", event.responseId);
8455
8272
  applyUsageToSpan(span, event.usage);
8456
8273
  if (this.recordOutputs) {
8457
- const content = Array.isArray(event.content) ? event.content : void 0;
8458
- const outputMessages = buildGenAiOutputMessages({
8459
- text: extractTextFromContent(content),
8460
- reasoningText: extractReasoningFromContent(content),
8461
- toolCalls: normalizeToolCalls(content ? content.filter((p) => p && p.type === "tool-call") : [])
8462
- });
8274
+ const outputMessages = buildVerbatimOutputMessages(Array.isArray(event.content) ? event.content : void 0);
8463
8275
  if (outputMessages) span.setAttribute("gen_ai.output.messages", outputMessages);
8464
8276
  }
8465
8277
  span.setStatus({ code: _opentelemetry_api.SpanStatusCode.OK });
8466
8278
  span.end();
8467
8279
  removeActiveLlmSpan(span);
8468
8280
  this.llmByKey.delete(stepKey(callId, stepNumber));
8281
+ this.promptByCallId.delete(callId);
8469
8282
  };
8470
8283
  this.onChunk = (event) => {
8471
8284
  const chunk = event?.chunk;
@@ -8494,7 +8307,7 @@ var LaminarAiSdkTelemetry = class {
8494
8307
  const llm = this.llmByKey.get(key);
8495
8308
  if (llm) {
8496
8309
  if (this.recordOutputs && llm.textDeltas.length > 0) {
8497
- const outputMessages = buildGenAiOutputMessages({ text: llm.textDeltas.join("") });
8310
+ const outputMessages = buildTextOutputMessages(llm.textDeltas.join(""));
8498
8311
  if (outputMessages) llm.span.setAttribute("gen_ai.output.messages", outputMessages);
8499
8312
  }
8500
8313
  applyUsageToSpan(llm.span, event.usage);
@@ -8502,21 +8315,13 @@ var LaminarAiSdkTelemetry = class {
8502
8315
  removeActiveLlmSpan(llm.span);
8503
8316
  this.llmByKey.delete(key);
8504
8317
  }
8318
+ this.promptByCallId.delete(callId);
8505
8319
  const step = this.stepByKey.get(key);
8506
8320
  if (!step) return;
8507
8321
  if (typeof event.finishReason === "string") applyFinishReason(step.span, event.finishReason);
8508
8322
  if (this.recordOutputs) {
8509
- const outputPayload = {};
8510
- if (typeof event.text === "string" && event.text.length > 0) {
8511
- outputPayload.text = event.text;
8512
- step.span.setAttribute("ai.response.text", event.text);
8513
- }
8514
- const normalizedToolCallsList = normalizeToolCalls(event.toolCalls);
8515
- if (normalizedToolCallsList.length > 0) {
8516
- outputPayload.toolCalls = normalizedToolCallsList;
8517
- step.span.setAttribute("ai.response.toolCalls", serializeJSON$1(normalizedToolCallsList));
8518
- }
8519
- if (Object.keys(outputPayload).length > 0) step.span.setAttribute(require_dist.SPAN_OUTPUT, serializeJSON$1(outputPayload));
8323
+ const outputMessages = buildVerbatimOutputMessages(Array.isArray(event.content) ? event.content : void 0);
8324
+ if (outputMessages) step.span.setAttribute(require_dist.SPAN_OUTPUT, outputMessages);
8520
8325
  }
8521
8326
  step.span.setStatus({ code: _opentelemetry_api.SpanStatusCode.OK });
8522
8327
  step.span.end();
@@ -8529,7 +8334,12 @@ var LaminarAiSdkTelemetry = class {
8529
8334
  if (!op) return;
8530
8335
  const span = getTracer().startSpan(`ai.llm ${event.provider ?? ""}:${event.modelId ?? ""}`, { kind: _opentelemetry_api.SpanKind.CLIENT }, op.ctx);
8531
8336
  span.setAttribute(require_dist.SPAN_TYPE, "LLM");
8337
+ span.setAttributes(buildAiSdkInstrumentationAttributes());
8532
8338
  applyRequestModelAttributes(span, event);
8339
+ if (this.recordInputs && Array.isArray(event?.promptMessages)) {
8340
+ const serialized = verbatimPromptString(event.promptMessages);
8341
+ if (serialized !== null) span.setAttribute("gen_ai.input.messages", serialized);
8342
+ }
8533
8343
  this.llmByKey.set(stepKey(callId, 0), {
8534
8344
  span,
8535
8345
  textDeltas: []
@@ -8549,7 +8359,7 @@ var LaminarAiSdkTelemetry = class {
8549
8359
  }
8550
8360
  applyUsageToSpan(llm.span, event.usage);
8551
8361
  if (this.recordOutputs && typeof event.objectText === "string") {
8552
- const outputMessages = buildGenAiOutputMessages({ text: event.objectText });
8362
+ const outputMessages = buildTextOutputMessages(event.objectText);
8553
8363
  if (outputMessages) llm.span.setAttribute("gen_ai.output.messages", outputMessages);
8554
8364
  }
8555
8365
  llm.span.setStatus({ code: _opentelemetry_api.SpanStatusCode.OK });
@@ -8568,6 +8378,7 @@ var LaminarAiSdkTelemetry = class {
8568
8378
  const span = getTracer().startSpan(`ai.tool ${toolName ?? "unknown"}`, { kind: _opentelemetry_api.SpanKind.CLIENT }, parentCtx);
8569
8379
  const spanCtx = _opentelemetry_api.trace.setSpan(parentCtx, span);
8570
8380
  span.setAttribute(require_dist.SPAN_TYPE, "TOOL");
8381
+ span.setAttributes(buildAiSdkInstrumentationAttributes());
8571
8382
  if (toolName) span.setAttribute("ai.toolCall.name", toolName);
8572
8383
  span.setAttribute("ai.toolCall.id", toolCallId);
8573
8384
  if (this.recordInputs && toolCall?.input !== void 0) {
@@ -8645,17 +8456,8 @@ var LaminarAiSdkTelemetry = class {
8645
8456
  if (typeof event.finishReason === "string") applyFinishReason(op.span, event.finishReason);
8646
8457
  if (op.operationId === "ai.embed" || op.operationId === "ai.embedMany" || op.operationId === "ai.rerank") applyUsageToSpan(op.span, event.totalUsage ?? event.usage);
8647
8458
  if (this.recordOutputs) {
8648
- const hasText = typeof event.text === "string" && event.text.length > 0;
8649
- if (hasText) {
8650
- op.span.setAttribute("ai.response.text", event.text);
8651
- op.span.setAttribute(require_dist.SPAN_OUTPUT, event.text);
8652
- }
8653
- const normalizedToolCallsList = normalizeToolCalls(event.toolCalls);
8654
- if (normalizedToolCallsList.length > 0) {
8655
- const serialized = serializeJSON$1(normalizedToolCallsList);
8656
- op.span.setAttribute("ai.response.toolCalls", serialized);
8657
- if (!hasText) op.span.setAttribute(require_dist.SPAN_OUTPUT, serialized);
8658
- }
8459
+ const outputMessages = buildVerbatimOutputMessages(Array.isArray(event.content) ? event.content : void 0);
8460
+ if (outputMessages) op.span.setAttribute(require_dist.SPAN_OUTPUT, outputMessages);
8659
8461
  if (event.embedding !== void 0) {
8660
8462
  const emb = event.embedding;
8661
8463
  if (Array.isArray(emb) && Array.isArray(emb[0])) op.span.setAttribute("ai.embed.count", emb.length);
@@ -8759,7 +8561,7 @@ var LaminarAiSdkTelemetry = class {
8759
8561
  };
8760
8562
  for (const [key, llm] of this.llmByKey) if (key.startsWith(prefix)) {
8761
8563
  if (this.recordOutputs && llm.textDeltas.length > 0) {
8762
- const outputMessages = buildGenAiOutputMessages({ text: llm.textDeltas.join("") });
8564
+ const outputMessages = buildTextOutputMessages(llm.textDeltas.join(""));
8763
8565
  if (outputMessages) llm.span.setAttribute("gen_ai.output.messages", outputMessages);
8764
8566
  }
8765
8567
  llm.span.end();
@@ -8777,6 +8579,7 @@ var LaminarAiSdkTelemetry = class {
8777
8579
  for (const key of this.llmByKey.keys()) if (key.startsWith(prefix)) this.llmByKey.delete(key);
8778
8580
  for (const [toolCallId, tool] of this.toolByCallId) if (tool.callId === callId) this.toolByCallId.delete(toolCallId);
8779
8581
  for (const key of this.stepByKey.keys()) if (key.startsWith(prefix)) this.stepByKey.delete(key);
8582
+ this.promptByCallId.delete(callId);
8780
8583
  return latest;
8781
8584
  }
8782
8585
  };