neatlogs 1.0.2 → 1.0.3

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.mjs CHANGED
@@ -74,6 +74,9 @@ var SCOPE_PATTERNS = {
74
74
  // Neatlogs custom instrumentations
75
75
  "@neatlogs/instrumentation-google-genai": { provider: "google", framework: "google_genai" },
76
76
  "@neatlogs/instrumentation-mastra": { framework: "mastra" },
77
+ "@neatlogs/instrumentation-ai-sdk": { framework: "ai_sdk" },
78
+ // Vercel AI SDK native scope (the `ai` package emits this directly)
79
+ ai: { framework: "ai_sdk" },
77
80
  // OpenInference instrumentations (npm @arizeai scope names)
78
81
  "@arizeai/openinference-instrumentation-openai": { provider: "openai", framework: "openai" },
79
82
  "@arizeai/openinference-instrumentation-anthropic": { provider: "anthropic", framework: "anthropic" },
@@ -161,6 +164,8 @@ function parseInstrumentationScope(scopeName) {
161
164
  result.framework = "haystack";
162
165
  } else if (scopeLower.includes("dspy")) {
163
166
  result.framework = "dspy";
167
+ } else if (scopeLower.includes("vercel-ai") || scopeLower.includes("ai-sdk")) {
168
+ result.framework = "ai_sdk";
164
169
  }
165
170
  if (scopeLower.includes("openai")) {
166
171
  result.provider = "openai";
@@ -1173,6 +1178,7 @@ var UnifiedAttributeProcessor = class {
1173
1178
  this.addCrewaiTokenUsageFallback(attrs);
1174
1179
  this.addReasoningTokensFromOutputValue(attrs);
1175
1180
  this.addCrewaiKickoffTelemetry(attrs);
1181
+ this.extractVercelAiSdkAttrs(attrs);
1176
1182
  this.extractToolCalls(attrs);
1177
1183
  for (const [k, v] of Object.entries(attrs)) {
1178
1184
  const m = INPUT_MSG_TOOL_RE.exec(k);
@@ -1533,6 +1539,167 @@ var UnifiedAttributeProcessor = class {
1533
1539
  attrs["llm.invocation_parameters"] = JSON.stringify(existing);
1534
1540
  }
1535
1541
  }
1542
+ // ── Vercel AI SDK extraction ───────────────────────
1543
+ /**
1544
+ * The Vercel AI SDK emits its own `ai.*` namespace alongside `gen_ai.*`. Map
1545
+ * the AI-SDK-specific keys onto the canonical `llm.*` / `gen_ai.*` / `tool.*`
1546
+ * keys that the existing pipeline already understands. Span-kind inference
1547
+ * runs first so downstream `applyNamespaceMapping` resolves it correctly.
1548
+ */
1549
+ extractVercelAiSdkAttrs(attrs) {
1550
+ const spanName = attrs["_span_name"] ?? "";
1551
+ const isAiSdkSpan = spanName.startsWith("ai.") || "ai.model.id" in attrs || "ai.toolCall.name" in attrs;
1552
+ if (!isAiSdkSpan) return;
1553
+ if (!("openinference.span.kind" in attrs)) {
1554
+ if (spanName === "ai.toolCall") {
1555
+ attrs["openinference.span.kind"] = "TOOL";
1556
+ } else if (spanName.startsWith("ai.embed")) {
1557
+ attrs["openinference.span.kind"] = "EMBEDDING";
1558
+ } else if (spanName.startsWith("ai.rerank")) {
1559
+ attrs["openinference.span.kind"] = "RERANKER";
1560
+ } else if (spanName.endsWith(".doStream") || spanName.endsWith(".doGenerate") || spanName.endsWith(".doRerank") || spanName.endsWith(".doEmbed")) {
1561
+ if (spanName.includes("embed")) {
1562
+ attrs["openinference.span.kind"] = "EMBEDDING";
1563
+ } else if (spanName.includes("rerank")) {
1564
+ attrs["openinference.span.kind"] = "RERANKER";
1565
+ } else {
1566
+ attrs["openinference.span.kind"] = "LLM";
1567
+ }
1568
+ } else if (spanName === "ai.generateText" || spanName === "ai.streamText" || spanName === "ai.generateObject" || spanName === "ai.streamObject") {
1569
+ attrs["openinference.span.kind"] = "CHAIN";
1570
+ }
1571
+ }
1572
+ if ("ai.model.id" in attrs && !("llm.model_name" in attrs)) {
1573
+ attrs["llm.model_name"] = attrs["ai.model.id"];
1574
+ }
1575
+ if ("ai.model.provider" in attrs && !("llm.provider" in attrs)) {
1576
+ const raw = String(attrs["ai.model.provider"]);
1577
+ attrs["llm.provider"] = raw.split(".")[0];
1578
+ }
1579
+ if ("ai.usage.promptTokens" in attrs && !("llm.token_count.prompt" in attrs)) {
1580
+ attrs["llm.token_count.prompt"] = attrs["ai.usage.promptTokens"];
1581
+ }
1582
+ if ("ai.usage.completionTokens" in attrs && !("llm.token_count.completion" in attrs)) {
1583
+ attrs["llm.token_count.completion"] = attrs["ai.usage.completionTokens"];
1584
+ }
1585
+ if ("ai.usage.totalTokens" in attrs && !("llm.token_count.total" in attrs)) {
1586
+ attrs["llm.token_count.total"] = attrs["ai.usage.totalTokens"];
1587
+ }
1588
+ const settingMap = {
1589
+ "ai.settings.temperature": "gen_ai.request.temperature",
1590
+ "ai.settings.maxTokens": "gen_ai.request.max_tokens",
1591
+ "ai.settings.topP": "gen_ai.request.top_p",
1592
+ "ai.settings.topK": "gen_ai.request.top_k",
1593
+ "ai.settings.frequencyPenalty": "gen_ai.request.frequency_penalty",
1594
+ "ai.settings.presencePenalty": "gen_ai.request.presence_penalty",
1595
+ "ai.settings.stopSequences": "gen_ai.request.stop_sequences"
1596
+ };
1597
+ for (const [src, tgt] of Object.entries(settingMap)) {
1598
+ if (src in attrs && !(tgt in attrs)) {
1599
+ attrs[tgt] = attrs[src];
1600
+ }
1601
+ }
1602
+ if (!("llm.invocation_parameters" in attrs)) {
1603
+ const params = {};
1604
+ if ("gen_ai.request.temperature" in attrs) params.temperature = attrs["gen_ai.request.temperature"];
1605
+ if ("gen_ai.request.max_tokens" in attrs) params.max_tokens = attrs["gen_ai.request.max_tokens"];
1606
+ if ("gen_ai.request.top_p" in attrs) params.top_p = attrs["gen_ai.request.top_p"];
1607
+ if ("gen_ai.request.top_k" in attrs) params.top_k = attrs["gen_ai.request.top_k"];
1608
+ if ("gen_ai.request.frequency_penalty" in attrs) params.frequency_penalty = attrs["gen_ai.request.frequency_penalty"];
1609
+ if ("gen_ai.request.presence_penalty" in attrs) params.presence_penalty = attrs["gen_ai.request.presence_penalty"];
1610
+ if ("gen_ai.request.stop_sequences" in attrs) params.stop_sequences = attrs["gen_ai.request.stop_sequences"];
1611
+ if (Object.keys(params).length > 0) {
1612
+ attrs["llm.invocation_parameters"] = JSON.stringify(params);
1613
+ }
1614
+ }
1615
+ if ("ai.operationId" in attrs && !("gen_ai.operation.name" in attrs)) {
1616
+ attrs["gen_ai.operation.name"] = attrs["ai.operationId"];
1617
+ }
1618
+ if ("ai.response.text" in attrs && !("llm.output_messages.0.message.content" in attrs)) {
1619
+ attrs["llm.output_messages.0.message.role"] = "assistant";
1620
+ attrs["llm.output_messages.0.message.content"] = attrs["ai.response.text"];
1621
+ }
1622
+ if ("ai.response.finishReason" in attrs && !("llm.response.finish_reason" in attrs)) {
1623
+ attrs["llm.response.finish_reason"] = attrs["ai.response.finishReason"];
1624
+ }
1625
+ if ("ai.response.id" in attrs && !("gen_ai.response.id" in attrs)) {
1626
+ attrs["gen_ai.response.id"] = attrs["ai.response.id"];
1627
+ }
1628
+ const rawMessages = attrs["ai.prompt.messages"];
1629
+ if (typeof rawMessages === "string") {
1630
+ try {
1631
+ const parsed = JSON.parse(rawMessages);
1632
+ if (Array.isArray(parsed)) {
1633
+ parsed.forEach((msg, i) => {
1634
+ if (msg && typeof msg === "object") {
1635
+ if (typeof msg.role === "string") {
1636
+ attrs[`llm.input_messages.${i}.message.role`] = msg.role;
1637
+ }
1638
+ if (typeof msg.content === "string") {
1639
+ attrs[`llm.input_messages.${i}.message.content`] = msg.content;
1640
+ } else if (msg.content !== void 0) {
1641
+ attrs[`llm.input_messages.${i}.message.content`] = JSON.stringify(msg.content);
1642
+ }
1643
+ }
1644
+ });
1645
+ }
1646
+ } catch {
1647
+ }
1648
+ }
1649
+ const rawToolCalls = attrs["ai.response.toolCalls"];
1650
+ if (typeof rawToolCalls === "string") {
1651
+ try {
1652
+ const parsed = JSON.parse(rawToolCalls);
1653
+ if (Array.isArray(parsed)) {
1654
+ parsed.forEach((tc, i) => {
1655
+ if (tc && typeof tc === "object") {
1656
+ if (tc.toolName !== void 0) {
1657
+ attrs[`llm.output_messages.0.message.tool_calls.${i}.tool_call.function.name`] = tc.toolName;
1658
+ }
1659
+ if (tc.args !== void 0) {
1660
+ const argStr = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
1661
+ attrs[`llm.output_messages.0.message.tool_calls.${i}.tool_call.function.arguments`] = argStr;
1662
+ }
1663
+ if (tc.toolCallId !== void 0) {
1664
+ attrs[`llm.output_messages.0.message.tool_calls.${i}.tool_call.id`] = tc.toolCallId;
1665
+ }
1666
+ }
1667
+ });
1668
+ }
1669
+ } catch {
1670
+ }
1671
+ }
1672
+ if ("ai.value" in attrs && typeof attrs["ai.value"] === "string") {
1673
+ try {
1674
+ attrs["ai.value"] = JSON.parse(attrs["ai.value"]);
1675
+ } catch {
1676
+ }
1677
+ }
1678
+ if ("ai.values" in attrs && Array.isArray(attrs["ai.values"])) {
1679
+ attrs["ai.values"] = JSON.stringify(attrs["ai.values"].map((v) => {
1680
+ if (typeof v === "string") {
1681
+ try {
1682
+ return JSON.parse(v);
1683
+ } catch {
1684
+ }
1685
+ }
1686
+ return v;
1687
+ }));
1688
+ }
1689
+ if (spanName === "ai.toolCall") {
1690
+ if ("ai.toolCall.name" in attrs && !("tool.name" in attrs)) {
1691
+ attrs["tool.name"] = attrs["ai.toolCall.name"];
1692
+ }
1693
+ if ("ai.toolCall.args" in attrs && !("input.value" in attrs)) {
1694
+ const raw = attrs["ai.toolCall.args"];
1695
+ attrs["input.value"] = typeof raw === "string" ? raw : JSON.stringify(raw);
1696
+ }
1697
+ if ("ai.toolCall.result" in attrs && !("output.value" in attrs)) {
1698
+ const raw = attrs["ai.toolCall.result"];
1699
+ attrs["output.value"] = typeof raw === "string" ? raw : JSON.stringify(raw);
1700
+ }
1701
+ }
1702
+ }
1536
1703
  // ── CrewAI-specific ─────────────────────────────────
1537
1704
  addCrewaiTokenUsageFallback(attrs) {
1538
1705
  const usage = attrs["neatlogs.crew.token_usage"];
@@ -1708,8 +1875,9 @@ var UnifiedAttributeProcessor = class {
1708
1875
  if (oiKind) {
1709
1876
  unified["neatlogs.span.kind"] = String(oiKind).toLowerCase();
1710
1877
  } else {
1878
+ const scopeName = attrs["neatlogs.instrumentation.name"] ?? "";
1711
1879
  const spanName = attrs["_span_name"] ?? "";
1712
- if (spanName) {
1880
+ if (spanName && scopeName !== "next.js") {
1713
1881
  const inferred = inferSpanKindFromName(spanName).toLowerCase();
1714
1882
  unified["neatlogs.span.kind"] = inferred;
1715
1883
  }
@@ -1718,7 +1886,8 @@ var UnifiedAttributeProcessor = class {
1718
1886
  const llmRequestType = (attrs["llm.request.type"] ?? "").toLowerCase();
1719
1887
  const genAiOperation = (attrs["gen_ai.operation.name"] ?? "").toLowerCase();
1720
1888
  const spanNameLower = (attrs["_span_name"] ?? "").toLowerCase();
1721
- if (llmRequestType === "rerank" || genAiOperation === "rerank" || spanNameLower.includes("rerank")) {
1889
+ const hasExplicitKind = "openinference.span.kind" in attrs || "traceloop.span.kind" in attrs;
1890
+ if (!hasExplicitKind && (llmRequestType === "rerank" || genAiOperation === "rerank" || spanNameLower.includes("rerank"))) {
1722
1891
  unified["neatlogs.span.kind"] = "reranker";
1723
1892
  }
1724
1893
  const spanKind = (attrs["neatlogs.span.kind"] ?? attrs["openinference.span.kind"] ?? "").toLowerCase();
@@ -1897,7 +2066,7 @@ var UnifiedAttributeProcessor = class {
1897
2066
  filterEmbeddingVectors(attrs) {
1898
2067
  const filtered = {};
1899
2068
  for (const [key, value] of Object.entries(attrs)) {
1900
- if (key.includes(".embedding.vector") || key.includes(".embeddings.")) {
2069
+ if (key.includes(".embedding.vector") || key.includes(".embeddings.") || key === "ai.embeddings" || key === "ai.embedding") {
1901
2070
  if (this.debug) {
1902
2071
  logger2.debug(`[FILTER] Dropped embedding vector key: ${key}`);
1903
2072
  }
@@ -1924,7 +2093,7 @@ var UnifiedAttributeProcessor = class {
1924
2093
  * Check if the raw span kind indicates CLIENT (OTel SpanKind.CLIENT = 3).
1925
2094
  */
1926
2095
  isHttpLikeSpanKind(kind) {
1927
- if (typeof kind === "number") return kind === 2;
2096
+ if (typeof kind === "number") return kind === 3;
1928
2097
  return String(kind).toUpperCase() === "CLIENT";
1929
2098
  }
1930
2099
  };
@@ -2561,21 +2730,24 @@ var attribute_mapping_default = {
2561
2730
  total: {
2562
2731
  sources: [
2563
2732
  "llm.token_count.total",
2564
- "llm.usage.total_tokens"
2733
+ "llm.usage.total_tokens",
2734
+ "ai.usage.totalTokens"
2565
2735
  ],
2566
2736
  target: "neatlogs.llm.token_count.total"
2567
2737
  },
2568
2738
  prompt: {
2569
2739
  sources: [
2570
2740
  "llm.token_count.prompt",
2571
- "gen_ai.usage.input_tokens"
2741
+ "gen_ai.usage.input_tokens",
2742
+ "ai.usage.promptTokens"
2572
2743
  ],
2573
2744
  target: "neatlogs.llm.token_count.prompt"
2574
2745
  },
2575
2746
  completion: {
2576
2747
  sources: [
2577
2748
  "llm.token_count.completion",
2578
- "gen_ai.usage.output_tokens"
2749
+ "gen_ai.usage.output_tokens",
2750
+ "ai.usage.completionTokens"
2579
2751
  ],
2580
2752
  target: "neatlogs.llm.token_count.completion"
2581
2753
  },
@@ -3166,24 +3338,62 @@ var attribute_mapping_default = {
3166
3338
  },
3167
3339
  reranker: {
3168
3340
  description: "Reranker model attributes",
3341
+ applies_to: ["reranker"],
3169
3342
  model_name: {
3170
3343
  sources: [
3171
- "reranker.model_name"
3344
+ "reranker.model_name",
3345
+ "ai.model.id"
3172
3346
  ],
3173
3347
  target: "neatlogs.reranker.model_name"
3174
3348
  },
3349
+ provider: {
3350
+ sources: [
3351
+ "ai.model.provider"
3352
+ ],
3353
+ target: "neatlogs.reranker.provider",
3354
+ description: "Vercel AI SDK reranker provider (e.g. gateway, cohere)"
3355
+ },
3175
3356
  query: {
3176
3357
  sources: [
3177
- "reranker.query"
3358
+ "reranker.query",
3359
+ "ai.rerank.query"
3178
3360
  ],
3179
3361
  target: "neatlogs.reranker.query"
3180
3362
  },
3363
+ documents: {
3364
+ sources: [
3365
+ "ai.documents"
3366
+ ],
3367
+ target: "neatlogs.reranker.input_documents",
3368
+ description: "Vercel AI SDK rerank input documents array"
3369
+ },
3370
+ ranking: {
3371
+ sources: [
3372
+ "ai.ranking"
3373
+ ],
3374
+ target: "neatlogs.reranker.output_documents",
3375
+ description: "Vercel AI SDK rerank output ranking array"
3376
+ },
3377
+ ranking_type: {
3378
+ sources: [
3379
+ "ai.ranking.type"
3380
+ ],
3381
+ target: "neatlogs.reranker.ranking_type",
3382
+ description: "Vercel AI SDK rerank type (e.g. text)"
3383
+ },
3181
3384
  top_k: {
3182
3385
  sources: [
3183
3386
  "reranker.top_k"
3184
3387
  ],
3185
3388
  target: "neatlogs.reranker.top_k"
3186
3389
  },
3390
+ max_retries: {
3391
+ sources: [
3392
+ "ai.settings.maxRetries"
3393
+ ],
3394
+ target: "neatlogs.reranker.max_retries",
3395
+ description: "Vercel AI SDK max retries setting"
3396
+ },
3187
3397
  input_documents: {
3188
3398
  sources: {
3189
3399
  id: [
@@ -3221,9 +3431,19 @@ var attribute_mapping_default = {
3221
3431
  },
3222
3432
  embedding: {
3223
3433
  description: "Embedding model attributes",
3434
+ applies_to: ["embedding"],
3435
+ input: {
3436
+ sources: [
3437
+ "ai.value",
3438
+ "ai.values"
3439
+ ],
3440
+ target: "neatlogs.embedding.input",
3441
+ description: "Vercel AI SDK embed/embedMany input value(s)"
3442
+ },
3224
3443
  model_name: {
3225
3444
  sources: [
3226
- "embedding.model_name"
3445
+ "embedding.model_name",
3446
+ "ai.model.id"
3227
3447
  ],
3228
3448
  target: "neatlogs.embedding.model_name"
3229
3449
  },
@@ -3241,7 +3461,8 @@ var attribute_mapping_default = {
3241
3461
  },
3242
3462
  token_count: {
3243
3463
  sources: [
3244
- "embedding.token_count"
3464
+ "embedding.token_count",
3465
+ "ai.usage.tokens"
3245
3466
  ],
3246
3467
  target: "neatlogs.embedding.token_count"
3247
3468
  },
@@ -3696,10 +3917,13 @@ var AttributeMapper = class {
3696
3917
  mapNestedConfig(config, attributes, spanKind) {
3697
3918
  const mapped = {};
3698
3919
  for (const [key, value] of Object.entries(config)) {
3699
- if (["description", "sources", "target", "indexed", "priority", "values"].includes(key)) {
3920
+ if (["description", "sources", "target", "indexed", "priority", "values", "applies_to"].includes(key)) {
3700
3921
  continue;
3701
3922
  }
3702
3923
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3924
+ if (Array.isArray(value.applies_to) && spanKind && !value.applies_to.includes(spanKind)) {
3925
+ continue;
3926
+ }
3703
3927
  if ("sources" in value) {
3704
3928
  if (value.indexed) {
3705
3929
  const target = value.target ?? "";
@@ -3738,6 +3962,9 @@ var AttributeMapper = class {
3738
3962
  for (const [sectionName, sectionConfig] of Object.entries(this.mappings)) {
3739
3963
  if (sectionName === "span_kind" || sectionName === "keep_as_is" || sectionName === "ignore") continue;
3740
3964
  if (typeof sectionConfig === "object" && sectionConfig !== null) {
3965
+ if (Array.isArray(sectionConfig.applies_to) && spanKind && !sectionConfig.applies_to.includes(spanKind)) {
3966
+ continue;
3967
+ }
3741
3968
  if ("mappings" in sectionConfig) {
3742
3969
  const nestedMapped = this.mapNestedConfig(
3743
3970
  sectionConfig.mappings,
@@ -3746,8 +3973,11 @@ var AttributeMapper = class {
3746
3973
  );
3747
3974
  Object.assign(mapped, nestedMapped);
3748
3975
  for (const [subKey, subVal] of Object.entries(sectionConfig)) {
3749
- if (subKey === "mappings" || subKey === "description") continue;
3976
+ if (subKey === "mappings" || subKey === "description" || subKey === "applies_to") continue;
3750
3977
  if (typeof subVal === "object" && subVal !== null && !Array.isArray(subVal)) {
3978
+ if (Array.isArray(subVal.applies_to) && spanKind && !subVal.applies_to.includes(spanKind)) {
3979
+ continue;
3980
+ }
3751
3981
  if ("sources" in subVal) {
3752
3982
  if (subVal.indexed) {
3753
3983
  const target = subVal.target ?? "";
@@ -4127,7 +4357,7 @@ var NeatlogsSpanProcessor = class {
4127
4357
  for (const key of Object.keys(unifiedAttrs)) {
4128
4358
  if (key.includes("input_messages") || key.includes("output_messages") || key.includes("gen_ai.prompt") || key.includes("gen_ai.completion") || key.includes(".content")) {
4129
4359
  keysToRemove.push(key);
4130
- } else if (skipOutput && (key === "neatlogs.embedding.input" || key === "neatlogs.embedding.output")) {
4360
+ } else if (key === "neatlogs.embedding.output" || skipOutput && key === "neatlogs.embedding.input") {
4131
4361
  keysToRemove.push(key);
4132
4362
  }
4133
4363
  }
@@ -4430,7 +4660,7 @@ var FilteringExporter = class {
4430
4660
  _delegate;
4431
4661
  export(spans, resultCallback) {
4432
4662
  const filtered = spans.filter(
4433
- (s) => !s.attributes["neatlogs.dropped"]
4663
+ (s) => !s.attributes["neatlogs.dropped"] && s.instrumentationLibrary.name !== "next.js"
4434
4664
  );
4435
4665
  if (filtered.length === 0) {
4436
4666
  resultCallback({ code: 0 });
@@ -4686,7 +4916,8 @@ var INSTRUMENTATION_REGISTRY = {
4686
4916
  "huggingface_hub",
4687
4917
  "litellm",
4688
4918
  "google_genai",
4689
- "portkey"
4919
+ "portkey",
4920
+ "ai_sdk"
4690
4921
  ],
4691
4922
  embedding: ["openai", "cohere", "huggingface", "vertexai", "mistralai", "ollama"],
4692
4923
  retrieval: [
@@ -4715,7 +4946,8 @@ var INSTRUMENTATION_REGISTRY = {
4715
4946
  "pydantic_ai",
4716
4947
  "smolagents",
4717
4948
  "strands",
4718
- "pipecat"
4949
+ "pipecat",
4950
+ "ai_sdk"
4719
4951
  ],
4720
4952
  tool: ["langchain", "llamaindex", "haystack", "mcp"],
4721
4953
  http: ["requests", "httpx", "urllib3", "aiohttp"],
@@ -4728,6 +4960,15 @@ var INSTRUMENTATION_REGISTRY = {
4728
4960
  neatlogs: null,
4729
4961
  default_span_kind: "LLM"
4730
4962
  },
4963
+ ai_sdk: {
4964
+ openinference: null,
4965
+ openllmetry: null,
4966
+ // The wrapper is opt-in per call site; init({ instrumentations: ['ai_sdk'] })
4967
+ // is a no-op. This registry entry exists so scope detection and tagging stay
4968
+ // consistent with other LLM/agent libraries.
4969
+ neatlogs: "@neatlogs/instrumentation-ai-sdk",
4970
+ default_span_kind: "LLM"
4971
+ },
4731
4972
  openai: {
4732
4973
  openinference: "@arizeai/openinference-instrumentation-openai",
4733
4974
  openllmetry: null,
@@ -5055,63 +5296,14 @@ function getLibraryInfo(library) {
5055
5296
  var logger12 = getLogger();
5056
5297
  var InstrumentationManager = class {
5057
5298
  provider;
5058
- debug;
5059
- excludedUrls;
5060
5299
  _instrumented = [];
5061
5300
  constructor(options) {
5062
5301
  this.provider = options.provider;
5063
- this.debug = options.debug ?? false;
5064
- this.excludedUrls = options.excludedUrls ?? [];
5065
5302
  }
5066
5303
  /** Get list of successfully instrumented libraries. */
5067
5304
  get instrumented() {
5068
5305
  return [...this._instrumented];
5069
5306
  }
5070
- /**
5071
- * Instrument HTTP (fetch/undici) for W3C traceparent context propagation.
5072
- * Always called by init().
5073
- */
5074
- async instrumentHttp() {
5075
- const excludedUrls = this.excludedUrls;
5076
- const ignoreOutgoingRequestHook = excludedUrls.length > 0 ? (request) => {
5077
- try {
5078
- const url = typeof request === "string" ? request : request?.href ?? request?.path ?? "";
5079
- return excludedUrls.some((excluded) => url.includes(excluded));
5080
- } catch {
5081
- return false;
5082
- }
5083
- } : void 0;
5084
- try {
5085
- const { HttpInstrumentation } = await import("@opentelemetry/instrumentation-http");
5086
- const httpInstr = new HttpInstrumentation({
5087
- ...ignoreOutgoingRequestHook ? { ignoreOutgoingRequestHook } : {}
5088
- });
5089
- httpInstr.setTracerProvider(this.provider);
5090
- httpInstr.enable();
5091
- logger12.debug("Instrumented http/https for context propagation");
5092
- } catch {
5093
- logger12.debug("http instrumentation not available \u2014 skipping");
5094
- }
5095
- try {
5096
- const { UndiciInstrumentation } = await import("@opentelemetry/instrumentation-undici");
5097
- const ignoreUndiciHook = excludedUrls.length > 0 ? (request) => {
5098
- try {
5099
- const url = `${request?.origin ?? ""}${request?.path ?? ""}`;
5100
- return excludedUrls.some((excluded) => url.includes(excluded));
5101
- } catch {
5102
- return false;
5103
- }
5104
- } : void 0;
5105
- const undiciInstr = new UndiciInstrumentation({
5106
- ...ignoreUndiciHook ? { ignoreRequestHook: ignoreUndiciHook } : {}
5107
- });
5108
- undiciInstr.setTracerProvider(this.provider);
5109
- undiciInstr.enable();
5110
- logger12.debug("Instrumented undici for context propagation");
5111
- } catch {
5112
- logger12.debug("undici instrumentation not available \u2014 skipping");
5113
- }
5114
- }
5115
5307
  /**
5116
5308
  * Instrument the specified libraries.
5117
5309
  * Priority: neatlogs custom > OpenInference > skip
@@ -5780,10 +5972,8 @@ async function init(options = {}) {
5780
5972
  }
5781
5973
  const manager = new InstrumentationManager({
5782
5974
  provider,
5783
- debug: options.debug,
5784
- excludedUrls: [baseUrl, endpoint].filter(Boolean)
5975
+ debug: options.debug
5785
5976
  });
5786
- await manager.instrumentHttp();
5787
5977
  if (options.instrumentations?.length) {
5788
5978
  await manager.instrument(options.instrumentations);
5789
5979
  if (options.debug) {
@@ -6074,6 +6264,166 @@ async function getMastraObservability() {
6074
6264
  return _cached;
6075
6265
  }
6076
6266
 
6267
+ // src/ai-sdk.ts
6268
+ import { trace as trace5, context as otelContext3, ROOT_CONTEXT as ROOT_CONTEXT2, SpanStatusCode as SpanStatusCode4 } from "@opentelemetry/api";
6269
+ var TRACER_NAME2 = "neatlogs.ai-sdk";
6270
+ function createAITelemetry(opts = {}) {
6271
+ const userMeta = opts.metadata ?? {};
6272
+ return {
6273
+ isEnabled: true,
6274
+ recordInputs: true,
6275
+ recordOutputs: true,
6276
+ tracer: trace5.getTracer(TRACER_NAME2),
6277
+ metadata: { ...userMeta, neatlogsWrapped: true }
6278
+ };
6279
+ }
6280
+ function safeStringify2(value) {
6281
+ try {
6282
+ return JSON.stringify(value);
6283
+ } catch {
6284
+ return "";
6285
+ }
6286
+ }
6287
+ function setInputValue(span2, opts) {
6288
+ if (opts && ("prompt" in opts || "messages" in opts)) {
6289
+ const input = opts.messages ?? opts.prompt;
6290
+ const stringified2 = safeStringify2(input);
6291
+ if (stringified2) {
6292
+ span2.setAttribute("input.value", stringified2);
6293
+ }
6294
+ return;
6295
+ }
6296
+ const stringified = safeStringify2(opts);
6297
+ if (stringified) {
6298
+ span2.setAttribute("input.value", stringified);
6299
+ }
6300
+ }
6301
+ function setOutputValue(span2, result) {
6302
+ if (result && typeof result === "object") {
6303
+ const r = result;
6304
+ if ("text" in r && "finishReason" in r) {
6305
+ const text = String(r.text ?? "");
6306
+ if (text) {
6307
+ span2.setAttribute("output.value", text);
6308
+ }
6309
+ if (r.finishReason) {
6310
+ span2.setAttribute("gen_ai.finish_reason", String(r.finishReason));
6311
+ }
6312
+ return;
6313
+ }
6314
+ }
6315
+ const stringified = safeStringify2(result);
6316
+ if (stringified) {
6317
+ span2.setAttribute("output.value", stringified);
6318
+ }
6319
+ }
6320
+ var WRAPPED_FUNCTIONS = [
6321
+ "generateText",
6322
+ "streamText",
6323
+ "generateObject",
6324
+ "streamObject",
6325
+ "embed",
6326
+ "embedMany",
6327
+ "rerank"
6328
+ ];
6329
+ function wrapAISDK(aiModule) {
6330
+ const wrapped = { ...aiModule };
6331
+ for (const name of WRAPPED_FUNCTIONS) {
6332
+ const original = aiModule[name];
6333
+ if (typeof original !== "function") continue;
6334
+ if (name === "streamText" || name === "streamObject") {
6335
+ wrapped[name] = createSyncWrapper(name, original);
6336
+ } else {
6337
+ wrapped[name] = createAsyncWrapper(name, original);
6338
+ }
6339
+ }
6340
+ return wrapped;
6341
+ }
6342
+ function rootSpanKind(name) {
6343
+ if (name === "embed" || name === "embedMany" || name === "rerank") return "CHAIN";
6344
+ return "WORKFLOW";
6345
+ }
6346
+ function getParentContext() {
6347
+ const activeSpan = trace5.getActiveSpan();
6348
+ if (activeSpan) {
6349
+ const instrScope = activeSpan.instrumentationLibrary?.name ?? "";
6350
+ if (instrScope === "next.js") {
6351
+ return ROOT_CONTEXT2;
6352
+ }
6353
+ }
6354
+ return otelContext3.active();
6355
+ }
6356
+ function createAsyncWrapper(name, original) {
6357
+ return async function wrappedAsyncFn(opts) {
6358
+ const tracer = trace5.getTracer(TRACER_NAME2);
6359
+ return tracer.startActiveSpan(
6360
+ `ai.${name}`,
6361
+ { attributes: { "openinference.span.kind": rootSpanKind(name) } },
6362
+ getParentContext(),
6363
+ async (span2) => {
6364
+ try {
6365
+ const isEmbedOrRerank = name === "embed" || name === "embedMany" || name === "rerank";
6366
+ if (!isEmbedOrRerank) {
6367
+ setInputValue(span2, opts);
6368
+ }
6369
+ if (name === "rerank" && opts?.query) {
6370
+ span2.setAttribute("ai.rerank.query", String(opts.query));
6371
+ }
6372
+ const merged = mergeTelemetry(opts);
6373
+ const result = await original(merged);
6374
+ if (!isEmbedOrRerank) {
6375
+ setOutputValue(span2, result);
6376
+ }
6377
+ return result;
6378
+ } catch (err) {
6379
+ recordSpanError(span2, err);
6380
+ throw err;
6381
+ } finally {
6382
+ span2.end();
6383
+ }
6384
+ }
6385
+ );
6386
+ };
6387
+ }
6388
+ function createSyncWrapper(name, original) {
6389
+ return function wrappedSyncFn(opts) {
6390
+ const tracer = trace5.getTracer(TRACER_NAME2);
6391
+ return tracer.startActiveSpan(`ai.${name}`, { attributes: { "openinference.span.kind": rootSpanKind(name) } }, getParentContext(), (span2) => {
6392
+ try {
6393
+ setInputValue(span2, opts);
6394
+ const merged = mergeTelemetry(opts);
6395
+ const result = original(merged);
6396
+ return result;
6397
+ } catch (err) {
6398
+ recordSpanError(span2, err);
6399
+ throw err;
6400
+ } finally {
6401
+ span2.end();
6402
+ }
6403
+ });
6404
+ };
6405
+ }
6406
+ function mergeTelemetry(opts) {
6407
+ const baseTelemetry = createAITelemetry({
6408
+ metadata: opts?.experimental_telemetry?.metadata
6409
+ });
6410
+ return {
6411
+ ...opts,
6412
+ experimental_telemetry: {
6413
+ ...opts?.experimental_telemetry,
6414
+ ...baseTelemetry
6415
+ }
6416
+ };
6417
+ }
6418
+ function recordSpanError(span2, err) {
6419
+ if (err instanceof Error) {
6420
+ span2.setStatus({ code: SpanStatusCode4.ERROR, message: err.message });
6421
+ span2.recordException(err);
6422
+ } else {
6423
+ span2.setStatus({ code: SpanStatusCode4.ERROR, message: String(err) });
6424
+ }
6425
+ }
6426
+
6077
6427
  // src/core/llm-binder.ts
6078
6428
  var logger15 = getLogger();
6079
6429
  function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
@@ -6134,6 +6484,7 @@ export {
6134
6484
  UserPromptTemplate,
6135
6485
  __version__,
6136
6486
  bindTemplates,
6487
+ createAITelemetry,
6137
6488
  createPrompt,
6138
6489
  deletePrompt,
6139
6490
  fetchPrompt,
@@ -6151,6 +6502,7 @@ export {
6151
6502
  shutdown,
6152
6503
  span,
6153
6504
  trace2 as trace,
6154
- updatePrompt
6505
+ updatePrompt,
6506
+ wrapAISDK
6155
6507
  };
6156
6508
  //# sourceMappingURL=index.mjs.map