neatlogs 1.0.2 → 1.0.4
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/README.md +28 -0
- package/dist/ai-sdk.cjs +190 -0
- package/dist/ai-sdk.cjs.map +1 -0
- package/dist/ai-sdk.d.ts +39 -0
- package/dist/ai-sdk.mjs +164 -0
- package/dist/ai-sdk.mjs.map +1 -0
- package/dist/index.cjs +426 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +423 -71
- package/dist/index.mjs.map +1 -1
- package/package.json +32 -9
- package/dist/index.d.mts +0 -531
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
UserPromptTemplate: () => UserPromptTemplate,
|
|
41
41
|
__version__: () => __version__,
|
|
42
42
|
bindTemplates: () => bindTemplates,
|
|
43
|
+
createAITelemetry: () => createAITelemetry,
|
|
43
44
|
createPrompt: () => createPrompt,
|
|
44
45
|
deletePrompt: () => deletePrompt,
|
|
45
46
|
fetchPrompt: () => fetchPrompt,
|
|
@@ -57,7 +58,8 @@ __export(index_exports, {
|
|
|
57
58
|
shutdown: () => shutdown,
|
|
58
59
|
span: () => span,
|
|
59
60
|
trace: () => trace2,
|
|
60
|
-
updatePrompt: () => updatePrompt
|
|
61
|
+
updatePrompt: () => updatePrompt,
|
|
62
|
+
wrapAISDK: () => wrapAISDK
|
|
61
63
|
});
|
|
62
64
|
module.exports = __toCommonJS(index_exports);
|
|
63
65
|
|
|
@@ -132,6 +134,9 @@ var SCOPE_PATTERNS = {
|
|
|
132
134
|
// Neatlogs custom instrumentations
|
|
133
135
|
"@neatlogs/instrumentation-google-genai": { provider: "google", framework: "google_genai" },
|
|
134
136
|
"@neatlogs/instrumentation-mastra": { framework: "mastra" },
|
|
137
|
+
"@neatlogs/instrumentation-ai-sdk": { framework: "ai_sdk" },
|
|
138
|
+
// Vercel AI SDK native scope (the `ai` package emits this directly)
|
|
139
|
+
ai: { framework: "ai_sdk" },
|
|
135
140
|
// OpenInference instrumentations (npm @arizeai scope names)
|
|
136
141
|
"@arizeai/openinference-instrumentation-openai": { provider: "openai", framework: "openai" },
|
|
137
142
|
"@arizeai/openinference-instrumentation-anthropic": { provider: "anthropic", framework: "anthropic" },
|
|
@@ -219,6 +224,8 @@ function parseInstrumentationScope(scopeName) {
|
|
|
219
224
|
result.framework = "haystack";
|
|
220
225
|
} else if (scopeLower.includes("dspy")) {
|
|
221
226
|
result.framework = "dspy";
|
|
227
|
+
} else if (scopeLower.includes("vercel-ai") || scopeLower.includes("ai-sdk")) {
|
|
228
|
+
result.framework = "ai_sdk";
|
|
222
229
|
}
|
|
223
230
|
if (scopeLower.includes("openai")) {
|
|
224
231
|
result.provider = "openai";
|
|
@@ -1231,6 +1238,7 @@ var UnifiedAttributeProcessor = class {
|
|
|
1231
1238
|
this.addCrewaiTokenUsageFallback(attrs);
|
|
1232
1239
|
this.addReasoningTokensFromOutputValue(attrs);
|
|
1233
1240
|
this.addCrewaiKickoffTelemetry(attrs);
|
|
1241
|
+
this.extractVercelAiSdkAttrs(attrs);
|
|
1234
1242
|
this.extractToolCalls(attrs);
|
|
1235
1243
|
for (const [k, v] of Object.entries(attrs)) {
|
|
1236
1244
|
const m = INPUT_MSG_TOOL_RE.exec(k);
|
|
@@ -1591,6 +1599,167 @@ var UnifiedAttributeProcessor = class {
|
|
|
1591
1599
|
attrs["llm.invocation_parameters"] = JSON.stringify(existing);
|
|
1592
1600
|
}
|
|
1593
1601
|
}
|
|
1602
|
+
// ── Vercel AI SDK extraction ───────────────────────
|
|
1603
|
+
/**
|
|
1604
|
+
* The Vercel AI SDK emits its own `ai.*` namespace alongside `gen_ai.*`. Map
|
|
1605
|
+
* the AI-SDK-specific keys onto the canonical `llm.*` / `gen_ai.*` / `tool.*`
|
|
1606
|
+
* keys that the existing pipeline already understands. Span-kind inference
|
|
1607
|
+
* runs first so downstream `applyNamespaceMapping` resolves it correctly.
|
|
1608
|
+
*/
|
|
1609
|
+
extractVercelAiSdkAttrs(attrs) {
|
|
1610
|
+
const spanName = attrs["_span_name"] ?? "";
|
|
1611
|
+
const isAiSdkSpan = spanName.startsWith("ai.") || "ai.model.id" in attrs || "ai.toolCall.name" in attrs;
|
|
1612
|
+
if (!isAiSdkSpan) return;
|
|
1613
|
+
if (!("openinference.span.kind" in attrs)) {
|
|
1614
|
+
if (spanName === "ai.toolCall") {
|
|
1615
|
+
attrs["openinference.span.kind"] = "TOOL";
|
|
1616
|
+
} else if (spanName.startsWith("ai.embed")) {
|
|
1617
|
+
attrs["openinference.span.kind"] = "EMBEDDING";
|
|
1618
|
+
} else if (spanName.startsWith("ai.rerank")) {
|
|
1619
|
+
attrs["openinference.span.kind"] = "RERANKER";
|
|
1620
|
+
} else if (spanName.endsWith(".doStream") || spanName.endsWith(".doGenerate") || spanName.endsWith(".doRerank") || spanName.endsWith(".doEmbed")) {
|
|
1621
|
+
if (spanName.includes("embed")) {
|
|
1622
|
+
attrs["openinference.span.kind"] = "EMBEDDING";
|
|
1623
|
+
} else if (spanName.includes("rerank")) {
|
|
1624
|
+
attrs["openinference.span.kind"] = "RERANKER";
|
|
1625
|
+
} else {
|
|
1626
|
+
attrs["openinference.span.kind"] = "LLM";
|
|
1627
|
+
}
|
|
1628
|
+
} else if (spanName === "ai.generateText" || spanName === "ai.streamText" || spanName === "ai.generateObject" || spanName === "ai.streamObject") {
|
|
1629
|
+
attrs["openinference.span.kind"] = "CHAIN";
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
if ("ai.model.id" in attrs && !("llm.model_name" in attrs)) {
|
|
1633
|
+
attrs["llm.model_name"] = attrs["ai.model.id"];
|
|
1634
|
+
}
|
|
1635
|
+
if ("ai.model.provider" in attrs && !("llm.provider" in attrs)) {
|
|
1636
|
+
const raw = String(attrs["ai.model.provider"]);
|
|
1637
|
+
attrs["llm.provider"] = raw.split(".")[0];
|
|
1638
|
+
}
|
|
1639
|
+
if ("ai.usage.promptTokens" in attrs && !("llm.token_count.prompt" in attrs)) {
|
|
1640
|
+
attrs["llm.token_count.prompt"] = attrs["ai.usage.promptTokens"];
|
|
1641
|
+
}
|
|
1642
|
+
if ("ai.usage.completionTokens" in attrs && !("llm.token_count.completion" in attrs)) {
|
|
1643
|
+
attrs["llm.token_count.completion"] = attrs["ai.usage.completionTokens"];
|
|
1644
|
+
}
|
|
1645
|
+
if ("ai.usage.totalTokens" in attrs && !("llm.token_count.total" in attrs)) {
|
|
1646
|
+
attrs["llm.token_count.total"] = attrs["ai.usage.totalTokens"];
|
|
1647
|
+
}
|
|
1648
|
+
const settingMap = {
|
|
1649
|
+
"ai.settings.temperature": "gen_ai.request.temperature",
|
|
1650
|
+
"ai.settings.maxTokens": "gen_ai.request.max_tokens",
|
|
1651
|
+
"ai.settings.topP": "gen_ai.request.top_p",
|
|
1652
|
+
"ai.settings.topK": "gen_ai.request.top_k",
|
|
1653
|
+
"ai.settings.frequencyPenalty": "gen_ai.request.frequency_penalty",
|
|
1654
|
+
"ai.settings.presencePenalty": "gen_ai.request.presence_penalty",
|
|
1655
|
+
"ai.settings.stopSequences": "gen_ai.request.stop_sequences"
|
|
1656
|
+
};
|
|
1657
|
+
for (const [src, tgt] of Object.entries(settingMap)) {
|
|
1658
|
+
if (src in attrs && !(tgt in attrs)) {
|
|
1659
|
+
attrs[tgt] = attrs[src];
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
if (!("llm.invocation_parameters" in attrs)) {
|
|
1663
|
+
const params = {};
|
|
1664
|
+
if ("gen_ai.request.temperature" in attrs) params.temperature = attrs["gen_ai.request.temperature"];
|
|
1665
|
+
if ("gen_ai.request.max_tokens" in attrs) params.max_tokens = attrs["gen_ai.request.max_tokens"];
|
|
1666
|
+
if ("gen_ai.request.top_p" in attrs) params.top_p = attrs["gen_ai.request.top_p"];
|
|
1667
|
+
if ("gen_ai.request.top_k" in attrs) params.top_k = attrs["gen_ai.request.top_k"];
|
|
1668
|
+
if ("gen_ai.request.frequency_penalty" in attrs) params.frequency_penalty = attrs["gen_ai.request.frequency_penalty"];
|
|
1669
|
+
if ("gen_ai.request.presence_penalty" in attrs) params.presence_penalty = attrs["gen_ai.request.presence_penalty"];
|
|
1670
|
+
if ("gen_ai.request.stop_sequences" in attrs) params.stop_sequences = attrs["gen_ai.request.stop_sequences"];
|
|
1671
|
+
if (Object.keys(params).length > 0) {
|
|
1672
|
+
attrs["llm.invocation_parameters"] = JSON.stringify(params);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
if ("ai.operationId" in attrs && !("gen_ai.operation.name" in attrs)) {
|
|
1676
|
+
attrs["gen_ai.operation.name"] = attrs["ai.operationId"];
|
|
1677
|
+
}
|
|
1678
|
+
if ("ai.response.text" in attrs && !("llm.output_messages.0.message.content" in attrs)) {
|
|
1679
|
+
attrs["llm.output_messages.0.message.role"] = "assistant";
|
|
1680
|
+
attrs["llm.output_messages.0.message.content"] = attrs["ai.response.text"];
|
|
1681
|
+
}
|
|
1682
|
+
if ("ai.response.finishReason" in attrs && !("llm.response.finish_reason" in attrs)) {
|
|
1683
|
+
attrs["llm.response.finish_reason"] = attrs["ai.response.finishReason"];
|
|
1684
|
+
}
|
|
1685
|
+
if ("ai.response.id" in attrs && !("gen_ai.response.id" in attrs)) {
|
|
1686
|
+
attrs["gen_ai.response.id"] = attrs["ai.response.id"];
|
|
1687
|
+
}
|
|
1688
|
+
const rawMessages = attrs["ai.prompt.messages"];
|
|
1689
|
+
if (typeof rawMessages === "string") {
|
|
1690
|
+
try {
|
|
1691
|
+
const parsed = JSON.parse(rawMessages);
|
|
1692
|
+
if (Array.isArray(parsed)) {
|
|
1693
|
+
parsed.forEach((msg, i) => {
|
|
1694
|
+
if (msg && typeof msg === "object") {
|
|
1695
|
+
if (typeof msg.role === "string") {
|
|
1696
|
+
attrs[`llm.input_messages.${i}.message.role`] = msg.role;
|
|
1697
|
+
}
|
|
1698
|
+
if (typeof msg.content === "string") {
|
|
1699
|
+
attrs[`llm.input_messages.${i}.message.content`] = msg.content;
|
|
1700
|
+
} else if (msg.content !== void 0) {
|
|
1701
|
+
attrs[`llm.input_messages.${i}.message.content`] = JSON.stringify(msg.content);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
} catch {
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
const rawToolCalls = attrs["ai.response.toolCalls"];
|
|
1710
|
+
if (typeof rawToolCalls === "string") {
|
|
1711
|
+
try {
|
|
1712
|
+
const parsed = JSON.parse(rawToolCalls);
|
|
1713
|
+
if (Array.isArray(parsed)) {
|
|
1714
|
+
parsed.forEach((tc, i) => {
|
|
1715
|
+
if (tc && typeof tc === "object") {
|
|
1716
|
+
if (tc.toolName !== void 0) {
|
|
1717
|
+
attrs[`llm.output_messages.0.message.tool_calls.${i}.tool_call.function.name`] = tc.toolName;
|
|
1718
|
+
}
|
|
1719
|
+
if (tc.args !== void 0) {
|
|
1720
|
+
const argStr = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
1721
|
+
attrs[`llm.output_messages.0.message.tool_calls.${i}.tool_call.function.arguments`] = argStr;
|
|
1722
|
+
}
|
|
1723
|
+
if (tc.toolCallId !== void 0) {
|
|
1724
|
+
attrs[`llm.output_messages.0.message.tool_calls.${i}.tool_call.id`] = tc.toolCallId;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
} catch {
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
if ("ai.value" in attrs && typeof attrs["ai.value"] === "string") {
|
|
1733
|
+
try {
|
|
1734
|
+
attrs["ai.value"] = JSON.parse(attrs["ai.value"]);
|
|
1735
|
+
} catch {
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
if ("ai.values" in attrs && Array.isArray(attrs["ai.values"])) {
|
|
1739
|
+
attrs["ai.values"] = JSON.stringify(attrs["ai.values"].map((v) => {
|
|
1740
|
+
if (typeof v === "string") {
|
|
1741
|
+
try {
|
|
1742
|
+
return JSON.parse(v);
|
|
1743
|
+
} catch {
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
return v;
|
|
1747
|
+
}));
|
|
1748
|
+
}
|
|
1749
|
+
if (spanName === "ai.toolCall") {
|
|
1750
|
+
if ("ai.toolCall.name" in attrs && !("tool.name" in attrs)) {
|
|
1751
|
+
attrs["tool.name"] = attrs["ai.toolCall.name"];
|
|
1752
|
+
}
|
|
1753
|
+
if ("ai.toolCall.args" in attrs && !("input.value" in attrs)) {
|
|
1754
|
+
const raw = attrs["ai.toolCall.args"];
|
|
1755
|
+
attrs["input.value"] = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
1756
|
+
}
|
|
1757
|
+
if ("ai.toolCall.result" in attrs && !("output.value" in attrs)) {
|
|
1758
|
+
const raw = attrs["ai.toolCall.result"];
|
|
1759
|
+
attrs["output.value"] = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1594
1763
|
// ── CrewAI-specific ─────────────────────────────────
|
|
1595
1764
|
addCrewaiTokenUsageFallback(attrs) {
|
|
1596
1765
|
const usage = attrs["neatlogs.crew.token_usage"];
|
|
@@ -1766,8 +1935,9 @@ var UnifiedAttributeProcessor = class {
|
|
|
1766
1935
|
if (oiKind) {
|
|
1767
1936
|
unified["neatlogs.span.kind"] = String(oiKind).toLowerCase();
|
|
1768
1937
|
} else {
|
|
1938
|
+
const scopeName = attrs["neatlogs.instrumentation.name"] ?? "";
|
|
1769
1939
|
const spanName = attrs["_span_name"] ?? "";
|
|
1770
|
-
if (spanName) {
|
|
1940
|
+
if (spanName && scopeName !== "next.js") {
|
|
1771
1941
|
const inferred = inferSpanKindFromName(spanName).toLowerCase();
|
|
1772
1942
|
unified["neatlogs.span.kind"] = inferred;
|
|
1773
1943
|
}
|
|
@@ -1776,7 +1946,8 @@ var UnifiedAttributeProcessor = class {
|
|
|
1776
1946
|
const llmRequestType = (attrs["llm.request.type"] ?? "").toLowerCase();
|
|
1777
1947
|
const genAiOperation = (attrs["gen_ai.operation.name"] ?? "").toLowerCase();
|
|
1778
1948
|
const spanNameLower = (attrs["_span_name"] ?? "").toLowerCase();
|
|
1779
|
-
|
|
1949
|
+
const hasExplicitKind = "openinference.span.kind" in attrs || "traceloop.span.kind" in attrs;
|
|
1950
|
+
if (!hasExplicitKind && (llmRequestType === "rerank" || genAiOperation === "rerank" || spanNameLower.includes("rerank"))) {
|
|
1780
1951
|
unified["neatlogs.span.kind"] = "reranker";
|
|
1781
1952
|
}
|
|
1782
1953
|
const spanKind = (attrs["neatlogs.span.kind"] ?? attrs["openinference.span.kind"] ?? "").toLowerCase();
|
|
@@ -1955,7 +2126,7 @@ var UnifiedAttributeProcessor = class {
|
|
|
1955
2126
|
filterEmbeddingVectors(attrs) {
|
|
1956
2127
|
const filtered = {};
|
|
1957
2128
|
for (const [key, value] of Object.entries(attrs)) {
|
|
1958
|
-
if (key.includes(".embedding.vector") || key.includes(".embeddings.")) {
|
|
2129
|
+
if (key.includes(".embedding.vector") || key.includes(".embeddings.") || key === "ai.embeddings" || key === "ai.embedding") {
|
|
1959
2130
|
if (this.debug) {
|
|
1960
2131
|
logger2.debug(`[FILTER] Dropped embedding vector key: ${key}`);
|
|
1961
2132
|
}
|
|
@@ -1982,7 +2153,7 @@ var UnifiedAttributeProcessor = class {
|
|
|
1982
2153
|
* Check if the raw span kind indicates CLIENT (OTel SpanKind.CLIENT = 3).
|
|
1983
2154
|
*/
|
|
1984
2155
|
isHttpLikeSpanKind(kind) {
|
|
1985
|
-
if (typeof kind === "number") return kind ===
|
|
2156
|
+
if (typeof kind === "number") return kind === 3;
|
|
1986
2157
|
return String(kind).toUpperCase() === "CLIENT";
|
|
1987
2158
|
}
|
|
1988
2159
|
};
|
|
@@ -2613,21 +2784,24 @@ var attribute_mapping_default = {
|
|
|
2613
2784
|
total: {
|
|
2614
2785
|
sources: [
|
|
2615
2786
|
"llm.token_count.total",
|
|
2616
|
-
"llm.usage.total_tokens"
|
|
2787
|
+
"llm.usage.total_tokens",
|
|
2788
|
+
"ai.usage.totalTokens"
|
|
2617
2789
|
],
|
|
2618
2790
|
target: "neatlogs.llm.token_count.total"
|
|
2619
2791
|
},
|
|
2620
2792
|
prompt: {
|
|
2621
2793
|
sources: [
|
|
2622
2794
|
"llm.token_count.prompt",
|
|
2623
|
-
"gen_ai.usage.input_tokens"
|
|
2795
|
+
"gen_ai.usage.input_tokens",
|
|
2796
|
+
"ai.usage.promptTokens"
|
|
2624
2797
|
],
|
|
2625
2798
|
target: "neatlogs.llm.token_count.prompt"
|
|
2626
2799
|
},
|
|
2627
2800
|
completion: {
|
|
2628
2801
|
sources: [
|
|
2629
2802
|
"llm.token_count.completion",
|
|
2630
|
-
"gen_ai.usage.output_tokens"
|
|
2803
|
+
"gen_ai.usage.output_tokens",
|
|
2804
|
+
"ai.usage.completionTokens"
|
|
2631
2805
|
],
|
|
2632
2806
|
target: "neatlogs.llm.token_count.completion"
|
|
2633
2807
|
},
|
|
@@ -3218,24 +3392,62 @@ var attribute_mapping_default = {
|
|
|
3218
3392
|
},
|
|
3219
3393
|
reranker: {
|
|
3220
3394
|
description: "Reranker model attributes",
|
|
3395
|
+
applies_to: ["reranker"],
|
|
3221
3396
|
model_name: {
|
|
3222
3397
|
sources: [
|
|
3223
|
-
"reranker.model_name"
|
|
3398
|
+
"reranker.model_name",
|
|
3399
|
+
"ai.model.id"
|
|
3224
3400
|
],
|
|
3225
3401
|
target: "neatlogs.reranker.model_name"
|
|
3226
3402
|
},
|
|
3403
|
+
provider: {
|
|
3404
|
+
sources: [
|
|
3405
|
+
"ai.model.provider"
|
|
3406
|
+
],
|
|
3407
|
+
target: "neatlogs.reranker.provider",
|
|
3408
|
+
description: "Vercel AI SDK reranker provider (e.g. gateway, cohere)"
|
|
3409
|
+
},
|
|
3227
3410
|
query: {
|
|
3228
3411
|
sources: [
|
|
3229
|
-
"reranker.query"
|
|
3412
|
+
"reranker.query",
|
|
3413
|
+
"ai.rerank.query"
|
|
3230
3414
|
],
|
|
3231
3415
|
target: "neatlogs.reranker.query"
|
|
3232
3416
|
},
|
|
3417
|
+
documents: {
|
|
3418
|
+
sources: [
|
|
3419
|
+
"ai.documents"
|
|
3420
|
+
],
|
|
3421
|
+
target: "neatlogs.reranker.input_documents",
|
|
3422
|
+
description: "Vercel AI SDK rerank input documents array"
|
|
3423
|
+
},
|
|
3424
|
+
ranking: {
|
|
3425
|
+
sources: [
|
|
3426
|
+
"ai.ranking"
|
|
3427
|
+
],
|
|
3428
|
+
target: "neatlogs.reranker.output_documents",
|
|
3429
|
+
description: "Vercel AI SDK rerank output ranking array"
|
|
3430
|
+
},
|
|
3431
|
+
ranking_type: {
|
|
3432
|
+
sources: [
|
|
3433
|
+
"ai.ranking.type"
|
|
3434
|
+
],
|
|
3435
|
+
target: "neatlogs.reranker.ranking_type",
|
|
3436
|
+
description: "Vercel AI SDK rerank type (e.g. text)"
|
|
3437
|
+
},
|
|
3233
3438
|
top_k: {
|
|
3234
3439
|
sources: [
|
|
3235
3440
|
"reranker.top_k"
|
|
3236
3441
|
],
|
|
3237
3442
|
target: "neatlogs.reranker.top_k"
|
|
3238
3443
|
},
|
|
3444
|
+
max_retries: {
|
|
3445
|
+
sources: [
|
|
3446
|
+
"ai.settings.maxRetries"
|
|
3447
|
+
],
|
|
3448
|
+
target: "neatlogs.reranker.max_retries",
|
|
3449
|
+
description: "Vercel AI SDK max retries setting"
|
|
3450
|
+
},
|
|
3239
3451
|
input_documents: {
|
|
3240
3452
|
sources: {
|
|
3241
3453
|
id: [
|
|
@@ -3273,9 +3485,19 @@ var attribute_mapping_default = {
|
|
|
3273
3485
|
},
|
|
3274
3486
|
embedding: {
|
|
3275
3487
|
description: "Embedding model attributes",
|
|
3488
|
+
applies_to: ["embedding"],
|
|
3489
|
+
input: {
|
|
3490
|
+
sources: [
|
|
3491
|
+
"ai.value",
|
|
3492
|
+
"ai.values"
|
|
3493
|
+
],
|
|
3494
|
+
target: "neatlogs.embedding.input",
|
|
3495
|
+
description: "Vercel AI SDK embed/embedMany input value(s)"
|
|
3496
|
+
},
|
|
3276
3497
|
model_name: {
|
|
3277
3498
|
sources: [
|
|
3278
|
-
"embedding.model_name"
|
|
3499
|
+
"embedding.model_name",
|
|
3500
|
+
"ai.model.id"
|
|
3279
3501
|
],
|
|
3280
3502
|
target: "neatlogs.embedding.model_name"
|
|
3281
3503
|
},
|
|
@@ -3293,7 +3515,8 @@ var attribute_mapping_default = {
|
|
|
3293
3515
|
},
|
|
3294
3516
|
token_count: {
|
|
3295
3517
|
sources: [
|
|
3296
|
-
"embedding.token_count"
|
|
3518
|
+
"embedding.token_count",
|
|
3519
|
+
"ai.usage.tokens"
|
|
3297
3520
|
],
|
|
3298
3521
|
target: "neatlogs.embedding.token_count"
|
|
3299
3522
|
},
|
|
@@ -3748,10 +3971,13 @@ var AttributeMapper = class {
|
|
|
3748
3971
|
mapNestedConfig(config, attributes, spanKind) {
|
|
3749
3972
|
const mapped = {};
|
|
3750
3973
|
for (const [key, value] of Object.entries(config)) {
|
|
3751
|
-
if (["description", "sources", "target", "indexed", "priority", "values"].includes(key)) {
|
|
3974
|
+
if (["description", "sources", "target", "indexed", "priority", "values", "applies_to"].includes(key)) {
|
|
3752
3975
|
continue;
|
|
3753
3976
|
}
|
|
3754
3977
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3978
|
+
if (Array.isArray(value.applies_to) && spanKind && !value.applies_to.includes(spanKind)) {
|
|
3979
|
+
continue;
|
|
3980
|
+
}
|
|
3755
3981
|
if ("sources" in value) {
|
|
3756
3982
|
if (value.indexed) {
|
|
3757
3983
|
const target = value.target ?? "";
|
|
@@ -3790,6 +4016,9 @@ var AttributeMapper = class {
|
|
|
3790
4016
|
for (const [sectionName, sectionConfig] of Object.entries(this.mappings)) {
|
|
3791
4017
|
if (sectionName === "span_kind" || sectionName === "keep_as_is" || sectionName === "ignore") continue;
|
|
3792
4018
|
if (typeof sectionConfig === "object" && sectionConfig !== null) {
|
|
4019
|
+
if (Array.isArray(sectionConfig.applies_to) && spanKind && !sectionConfig.applies_to.includes(spanKind)) {
|
|
4020
|
+
continue;
|
|
4021
|
+
}
|
|
3793
4022
|
if ("mappings" in sectionConfig) {
|
|
3794
4023
|
const nestedMapped = this.mapNestedConfig(
|
|
3795
4024
|
sectionConfig.mappings,
|
|
@@ -3798,8 +4027,11 @@ var AttributeMapper = class {
|
|
|
3798
4027
|
);
|
|
3799
4028
|
Object.assign(mapped, nestedMapped);
|
|
3800
4029
|
for (const [subKey, subVal] of Object.entries(sectionConfig)) {
|
|
3801
|
-
if (subKey === "mappings" || subKey === "description") continue;
|
|
4030
|
+
if (subKey === "mappings" || subKey === "description" || subKey === "applies_to") continue;
|
|
3802
4031
|
if (typeof subVal === "object" && subVal !== null && !Array.isArray(subVal)) {
|
|
4032
|
+
if (Array.isArray(subVal.applies_to) && spanKind && !subVal.applies_to.includes(spanKind)) {
|
|
4033
|
+
continue;
|
|
4034
|
+
}
|
|
3803
4035
|
if ("sources" in subVal) {
|
|
3804
4036
|
if (subVal.indexed) {
|
|
3805
4037
|
const target = subVal.target ?? "";
|
|
@@ -4179,7 +4411,7 @@ var NeatlogsSpanProcessor = class {
|
|
|
4179
4411
|
for (const key of Object.keys(unifiedAttrs)) {
|
|
4180
4412
|
if (key.includes("input_messages") || key.includes("output_messages") || key.includes("gen_ai.prompt") || key.includes("gen_ai.completion") || key.includes(".content")) {
|
|
4181
4413
|
keysToRemove.push(key);
|
|
4182
|
-
} else if (
|
|
4414
|
+
} else if (key === "neatlogs.embedding.output" || skipOutput && key === "neatlogs.embedding.input") {
|
|
4183
4415
|
keysToRemove.push(key);
|
|
4184
4416
|
}
|
|
4185
4417
|
}
|
|
@@ -4482,7 +4714,7 @@ var FilteringExporter = class {
|
|
|
4482
4714
|
_delegate;
|
|
4483
4715
|
export(spans, resultCallback) {
|
|
4484
4716
|
const filtered = spans.filter(
|
|
4485
|
-
(s) => !s.attributes["neatlogs.dropped"]
|
|
4717
|
+
(s) => !s.attributes["neatlogs.dropped"] && s.instrumentationLibrary.name !== "next.js"
|
|
4486
4718
|
);
|
|
4487
4719
|
if (filtered.length === 0) {
|
|
4488
4720
|
resultCallback({ code: 0 });
|
|
@@ -4738,7 +4970,8 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
4738
4970
|
"huggingface_hub",
|
|
4739
4971
|
"litellm",
|
|
4740
4972
|
"google_genai",
|
|
4741
|
-
"portkey"
|
|
4973
|
+
"portkey",
|
|
4974
|
+
"ai_sdk"
|
|
4742
4975
|
],
|
|
4743
4976
|
embedding: ["openai", "cohere", "huggingface", "vertexai", "mistralai", "ollama"],
|
|
4744
4977
|
retrieval: [
|
|
@@ -4767,7 +5000,8 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
4767
5000
|
"pydantic_ai",
|
|
4768
5001
|
"smolagents",
|
|
4769
5002
|
"strands",
|
|
4770
|
-
"pipecat"
|
|
5003
|
+
"pipecat",
|
|
5004
|
+
"ai_sdk"
|
|
4771
5005
|
],
|
|
4772
5006
|
tool: ["langchain", "llamaindex", "haystack", "mcp"],
|
|
4773
5007
|
http: ["requests", "httpx", "urllib3", "aiohttp"],
|
|
@@ -4780,6 +5014,15 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
4780
5014
|
neatlogs: null,
|
|
4781
5015
|
default_span_kind: "LLM"
|
|
4782
5016
|
},
|
|
5017
|
+
ai_sdk: {
|
|
5018
|
+
openinference: null,
|
|
5019
|
+
openllmetry: null,
|
|
5020
|
+
// The wrapper is opt-in per call site; init({ instrumentations: ['ai_sdk'] })
|
|
5021
|
+
// is a no-op. This registry entry exists so scope detection and tagging stay
|
|
5022
|
+
// consistent with other LLM/agent libraries.
|
|
5023
|
+
neatlogs: "@neatlogs/instrumentation-ai-sdk",
|
|
5024
|
+
default_span_kind: "LLM"
|
|
5025
|
+
},
|
|
4783
5026
|
openai: {
|
|
4784
5027
|
openinference: "@arizeai/openinference-instrumentation-openai",
|
|
4785
5028
|
openllmetry: null,
|
|
@@ -5107,63 +5350,14 @@ function getLibraryInfo(library) {
|
|
|
5107
5350
|
var logger12 = getLogger();
|
|
5108
5351
|
var InstrumentationManager = class {
|
|
5109
5352
|
provider;
|
|
5110
|
-
debug;
|
|
5111
|
-
excludedUrls;
|
|
5112
5353
|
_instrumented = [];
|
|
5113
5354
|
constructor(options) {
|
|
5114
5355
|
this.provider = options.provider;
|
|
5115
|
-
this.debug = options.debug ?? false;
|
|
5116
|
-
this.excludedUrls = options.excludedUrls ?? [];
|
|
5117
5356
|
}
|
|
5118
5357
|
/** Get list of successfully instrumented libraries. */
|
|
5119
5358
|
get instrumented() {
|
|
5120
5359
|
return [...this._instrumented];
|
|
5121
5360
|
}
|
|
5122
|
-
/**
|
|
5123
|
-
* Instrument HTTP (fetch/undici) for W3C traceparent context propagation.
|
|
5124
|
-
* Always called by init().
|
|
5125
|
-
*/
|
|
5126
|
-
async instrumentHttp() {
|
|
5127
|
-
const excludedUrls = this.excludedUrls;
|
|
5128
|
-
const ignoreOutgoingRequestHook = excludedUrls.length > 0 ? (request) => {
|
|
5129
|
-
try {
|
|
5130
|
-
const url = typeof request === "string" ? request : request?.href ?? request?.path ?? "";
|
|
5131
|
-
return excludedUrls.some((excluded) => url.includes(excluded));
|
|
5132
|
-
} catch {
|
|
5133
|
-
return false;
|
|
5134
|
-
}
|
|
5135
|
-
} : void 0;
|
|
5136
|
-
try {
|
|
5137
|
-
const { HttpInstrumentation } = await import("@opentelemetry/instrumentation-http");
|
|
5138
|
-
const httpInstr = new HttpInstrumentation({
|
|
5139
|
-
...ignoreOutgoingRequestHook ? { ignoreOutgoingRequestHook } : {}
|
|
5140
|
-
});
|
|
5141
|
-
httpInstr.setTracerProvider(this.provider);
|
|
5142
|
-
httpInstr.enable();
|
|
5143
|
-
logger12.debug("Instrumented http/https for context propagation");
|
|
5144
|
-
} catch {
|
|
5145
|
-
logger12.debug("http instrumentation not available \u2014 skipping");
|
|
5146
|
-
}
|
|
5147
|
-
try {
|
|
5148
|
-
const { UndiciInstrumentation } = await import("@opentelemetry/instrumentation-undici");
|
|
5149
|
-
const ignoreUndiciHook = excludedUrls.length > 0 ? (request) => {
|
|
5150
|
-
try {
|
|
5151
|
-
const url = `${request?.origin ?? ""}${request?.path ?? ""}`;
|
|
5152
|
-
return excludedUrls.some((excluded) => url.includes(excluded));
|
|
5153
|
-
} catch {
|
|
5154
|
-
return false;
|
|
5155
|
-
}
|
|
5156
|
-
} : void 0;
|
|
5157
|
-
const undiciInstr = new UndiciInstrumentation({
|
|
5158
|
-
...ignoreUndiciHook ? { ignoreRequestHook: ignoreUndiciHook } : {}
|
|
5159
|
-
});
|
|
5160
|
-
undiciInstr.setTracerProvider(this.provider);
|
|
5161
|
-
undiciInstr.enable();
|
|
5162
|
-
logger12.debug("Instrumented undici for context propagation");
|
|
5163
|
-
} catch {
|
|
5164
|
-
logger12.debug("undici instrumentation not available \u2014 skipping");
|
|
5165
|
-
}
|
|
5166
|
-
}
|
|
5167
5361
|
/**
|
|
5168
5362
|
* Instrument the specified libraries.
|
|
5169
5363
|
* Priority: neatlogs custom > OpenInference > skip
|
|
@@ -5717,7 +5911,7 @@ async function init(options = {}) {
|
|
|
5717
5911
|
logger13.debug(`Auto-generated session_id: ${sessionId}`);
|
|
5718
5912
|
}
|
|
5719
5913
|
}
|
|
5720
|
-
const endpoint = options.endpoint ?? "https://staging-cloud.neatlogs.com
|
|
5914
|
+
const endpoint = options.endpoint ?? "https://staging-cloud.neatlogs.com";
|
|
5721
5915
|
const baseUrl = new URL(endpoint).origin;
|
|
5722
5916
|
_setSessionConfig({
|
|
5723
5917
|
sessionId,
|
|
@@ -5832,10 +6026,8 @@ async function init(options = {}) {
|
|
|
5832
6026
|
}
|
|
5833
6027
|
const manager = new InstrumentationManager({
|
|
5834
6028
|
provider,
|
|
5835
|
-
debug: options.debug
|
|
5836
|
-
excludedUrls: [baseUrl, endpoint].filter(Boolean)
|
|
6029
|
+
debug: options.debug
|
|
5837
6030
|
});
|
|
5838
|
-
await manager.instrumentHttp();
|
|
5839
6031
|
if (options.instrumentations?.length) {
|
|
5840
6032
|
await manager.instrument(options.instrumentations);
|
|
5841
6033
|
if (options.debug) {
|
|
@@ -6126,6 +6318,166 @@ async function getMastraObservability() {
|
|
|
6126
6318
|
return _cached;
|
|
6127
6319
|
}
|
|
6128
6320
|
|
|
6321
|
+
// src/ai-sdk.ts
|
|
6322
|
+
var import_api8 = require("@opentelemetry/api");
|
|
6323
|
+
var TRACER_NAME2 = "neatlogs.ai-sdk";
|
|
6324
|
+
function createAITelemetry(opts = {}) {
|
|
6325
|
+
const userMeta = opts.metadata ?? {};
|
|
6326
|
+
return {
|
|
6327
|
+
isEnabled: true,
|
|
6328
|
+
recordInputs: true,
|
|
6329
|
+
recordOutputs: true,
|
|
6330
|
+
tracer: import_api8.trace.getTracer(TRACER_NAME2),
|
|
6331
|
+
metadata: { ...userMeta, neatlogsWrapped: true }
|
|
6332
|
+
};
|
|
6333
|
+
}
|
|
6334
|
+
function safeStringify2(value) {
|
|
6335
|
+
try {
|
|
6336
|
+
return JSON.stringify(value);
|
|
6337
|
+
} catch {
|
|
6338
|
+
return "";
|
|
6339
|
+
}
|
|
6340
|
+
}
|
|
6341
|
+
function setInputValue(span2, opts) {
|
|
6342
|
+
if (opts && ("prompt" in opts || "messages" in opts)) {
|
|
6343
|
+
const input = opts.messages ?? opts.prompt;
|
|
6344
|
+
const stringified2 = safeStringify2(input);
|
|
6345
|
+
if (stringified2) {
|
|
6346
|
+
span2.setAttribute("input.value", stringified2);
|
|
6347
|
+
}
|
|
6348
|
+
return;
|
|
6349
|
+
}
|
|
6350
|
+
const stringified = safeStringify2(opts);
|
|
6351
|
+
if (stringified) {
|
|
6352
|
+
span2.setAttribute("input.value", stringified);
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6355
|
+
function setOutputValue(span2, result) {
|
|
6356
|
+
if (result && typeof result === "object") {
|
|
6357
|
+
const r = result;
|
|
6358
|
+
if ("text" in r && "finishReason" in r) {
|
|
6359
|
+
const text = String(r.text ?? "");
|
|
6360
|
+
if (text) {
|
|
6361
|
+
span2.setAttribute("output.value", text);
|
|
6362
|
+
}
|
|
6363
|
+
if (r.finishReason) {
|
|
6364
|
+
span2.setAttribute("gen_ai.finish_reason", String(r.finishReason));
|
|
6365
|
+
}
|
|
6366
|
+
return;
|
|
6367
|
+
}
|
|
6368
|
+
}
|
|
6369
|
+
const stringified = safeStringify2(result);
|
|
6370
|
+
if (stringified) {
|
|
6371
|
+
span2.setAttribute("output.value", stringified);
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6374
|
+
var WRAPPED_FUNCTIONS = [
|
|
6375
|
+
"generateText",
|
|
6376
|
+
"streamText",
|
|
6377
|
+
"generateObject",
|
|
6378
|
+
"streamObject",
|
|
6379
|
+
"embed",
|
|
6380
|
+
"embedMany",
|
|
6381
|
+
"rerank"
|
|
6382
|
+
];
|
|
6383
|
+
function wrapAISDK(aiModule) {
|
|
6384
|
+
const wrapped = { ...aiModule };
|
|
6385
|
+
for (const name of WRAPPED_FUNCTIONS) {
|
|
6386
|
+
const original = aiModule[name];
|
|
6387
|
+
if (typeof original !== "function") continue;
|
|
6388
|
+
if (name === "streamText" || name === "streamObject") {
|
|
6389
|
+
wrapped[name] = createSyncWrapper(name, original);
|
|
6390
|
+
} else {
|
|
6391
|
+
wrapped[name] = createAsyncWrapper(name, original);
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
return wrapped;
|
|
6395
|
+
}
|
|
6396
|
+
function rootSpanKind(name) {
|
|
6397
|
+
if (name === "embed" || name === "embedMany" || name === "rerank") return "CHAIN";
|
|
6398
|
+
return "WORKFLOW";
|
|
6399
|
+
}
|
|
6400
|
+
function getParentContext() {
|
|
6401
|
+
const activeSpan = import_api8.trace.getActiveSpan();
|
|
6402
|
+
if (activeSpan) {
|
|
6403
|
+
const instrScope = activeSpan.instrumentationLibrary?.name ?? "";
|
|
6404
|
+
if (instrScope === "next.js") {
|
|
6405
|
+
return import_api8.ROOT_CONTEXT;
|
|
6406
|
+
}
|
|
6407
|
+
}
|
|
6408
|
+
return import_api8.context.active();
|
|
6409
|
+
}
|
|
6410
|
+
function createAsyncWrapper(name, original) {
|
|
6411
|
+
return async function wrappedAsyncFn(opts) {
|
|
6412
|
+
const tracer = import_api8.trace.getTracer(TRACER_NAME2);
|
|
6413
|
+
return tracer.startActiveSpan(
|
|
6414
|
+
`ai.${name}`,
|
|
6415
|
+
{ attributes: { "openinference.span.kind": rootSpanKind(name) } },
|
|
6416
|
+
getParentContext(),
|
|
6417
|
+
async (span2) => {
|
|
6418
|
+
try {
|
|
6419
|
+
const isEmbedOrRerank = name === "embed" || name === "embedMany" || name === "rerank";
|
|
6420
|
+
if (!isEmbedOrRerank) {
|
|
6421
|
+
setInputValue(span2, opts);
|
|
6422
|
+
}
|
|
6423
|
+
if (name === "rerank" && opts?.query) {
|
|
6424
|
+
span2.setAttribute("ai.rerank.query", String(opts.query));
|
|
6425
|
+
}
|
|
6426
|
+
const merged = mergeTelemetry(opts);
|
|
6427
|
+
const result = await original(merged);
|
|
6428
|
+
if (!isEmbedOrRerank) {
|
|
6429
|
+
setOutputValue(span2, result);
|
|
6430
|
+
}
|
|
6431
|
+
return result;
|
|
6432
|
+
} catch (err) {
|
|
6433
|
+
recordSpanError(span2, err);
|
|
6434
|
+
throw err;
|
|
6435
|
+
} finally {
|
|
6436
|
+
span2.end();
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
);
|
|
6440
|
+
};
|
|
6441
|
+
}
|
|
6442
|
+
function createSyncWrapper(name, original) {
|
|
6443
|
+
return function wrappedSyncFn(opts) {
|
|
6444
|
+
const tracer = import_api8.trace.getTracer(TRACER_NAME2);
|
|
6445
|
+
return tracer.startActiveSpan(`ai.${name}`, { attributes: { "openinference.span.kind": rootSpanKind(name) } }, getParentContext(), (span2) => {
|
|
6446
|
+
try {
|
|
6447
|
+
setInputValue(span2, opts);
|
|
6448
|
+
const merged = mergeTelemetry(opts);
|
|
6449
|
+
const result = original(merged);
|
|
6450
|
+
return result;
|
|
6451
|
+
} catch (err) {
|
|
6452
|
+
recordSpanError(span2, err);
|
|
6453
|
+
throw err;
|
|
6454
|
+
} finally {
|
|
6455
|
+
span2.end();
|
|
6456
|
+
}
|
|
6457
|
+
});
|
|
6458
|
+
};
|
|
6459
|
+
}
|
|
6460
|
+
function mergeTelemetry(opts) {
|
|
6461
|
+
const baseTelemetry = createAITelemetry({
|
|
6462
|
+
metadata: opts?.experimental_telemetry?.metadata
|
|
6463
|
+
});
|
|
6464
|
+
return {
|
|
6465
|
+
...opts,
|
|
6466
|
+
experimental_telemetry: {
|
|
6467
|
+
...opts?.experimental_telemetry,
|
|
6468
|
+
...baseTelemetry
|
|
6469
|
+
}
|
|
6470
|
+
};
|
|
6471
|
+
}
|
|
6472
|
+
function recordSpanError(span2, err) {
|
|
6473
|
+
if (err instanceof Error) {
|
|
6474
|
+
span2.setStatus({ code: import_api8.SpanStatusCode.ERROR, message: err.message });
|
|
6475
|
+
span2.recordException(err);
|
|
6476
|
+
} else {
|
|
6477
|
+
span2.setStatus({ code: import_api8.SpanStatusCode.ERROR, message: String(err) });
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
|
|
6129
6481
|
// src/core/llm-binder.ts
|
|
6130
6482
|
var logger15 = getLogger();
|
|
6131
6483
|
function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
|
|
@@ -6187,6 +6539,7 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
|
|
|
6187
6539
|
UserPromptTemplate,
|
|
6188
6540
|
__version__,
|
|
6189
6541
|
bindTemplates,
|
|
6542
|
+
createAITelemetry,
|
|
6190
6543
|
createPrompt,
|
|
6191
6544
|
deletePrompt,
|
|
6192
6545
|
fetchPrompt,
|
|
@@ -6204,6 +6557,7 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
|
|
|
6204
6557
|
shutdown,
|
|
6205
6558
|
span,
|
|
6206
6559
|
trace,
|
|
6207
|
-
updatePrompt
|
|
6560
|
+
updatePrompt,
|
|
6561
|
+
wrapAISDK
|
|
6208
6562
|
});
|
|
6209
6563
|
//# sourceMappingURL=index.cjs.map
|