neatlogs 1.0.3 → 1.0.5
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/anthropic.cjs +373 -0
- package/dist/anthropic.cjs.map +1 -0
- package/dist/anthropic.d.ts +27 -0
- package/dist/anthropic.mjs +347 -0
- package/dist/anthropic.mjs.map +1 -0
- package/dist/index.cjs +1665 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.mjs +1656 -7
- package/dist/index.mjs.map +1 -1
- package/dist/langchain.cjs +269 -0
- package/dist/langchain.cjs.map +1 -0
- package/dist/langchain.d.ts +16 -0
- package/dist/langchain.mjs +244 -0
- package/dist/langchain.mjs.map +1 -0
- package/dist/mastra-wrap.cjs +597 -0
- package/dist/mastra-wrap.cjs.map +1 -0
- package/dist/mastra-wrap.d.ts +38 -0
- package/dist/mastra-wrap.mjs +571 -0
- package/dist/mastra-wrap.mjs.map +1 -0
- package/dist/openai-agents.cjs +215 -0
- package/dist/openai-agents.cjs.map +1 -0
- package/dist/openai-agents.d.ts +13 -0
- package/dist/openai-agents.mjs +190 -0
- package/dist/openai-agents.mjs.map +1 -0
- package/dist/openai.cjs +342 -0
- package/dist/openai.cjs.map +1 -0
- package/dist/openai.d.ts +26 -0
- package/dist/openai.mjs +316 -0
- package/dist/openai.mjs.map +1 -0
- package/dist/strands.cjs +44 -0
- package/dist/strands.cjs.map +1 -0
- package/dist/strands.d.ts +27 -0
- package/dist/strands.mjs +19 -0
- package/dist/strands.mjs.map +1 -0
- package/package.json +80 -10
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/langchain.ts
|
|
21
|
+
var langchain_exports = {};
|
|
22
|
+
__export(langchain_exports, {
|
|
23
|
+
langchainHandler: () => langchainHandler
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(langchain_exports);
|
|
26
|
+
var import_api = require("@opentelemetry/api");
|
|
27
|
+
var TRACER_NAME = "neatlogs.langchain";
|
|
28
|
+
function langchainHandler(opts) {
|
|
29
|
+
return new NeatlogsCallbackHandler(opts);
|
|
30
|
+
}
|
|
31
|
+
var NeatlogsCallbackHandler = class {
|
|
32
|
+
name = "neatlogs";
|
|
33
|
+
_spans = /* @__PURE__ */ new Map();
|
|
34
|
+
_workflowName;
|
|
35
|
+
constructor(opts) {
|
|
36
|
+
this._workflowName = opts?.workflowName;
|
|
37
|
+
}
|
|
38
|
+
// --- Chain/Graph callbacks ---
|
|
39
|
+
async handleChainStart(serialized, inputs, runId, parentRunId, tags, metadata) {
|
|
40
|
+
const tracer = import_api.trace.getTracer(TRACER_NAME);
|
|
41
|
+
const name = serialized?.name ?? serialized?.id?.at(-1) ?? "chain";
|
|
42
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
43
|
+
const parentCtx = parentSpan ? import_api.trace.setSpan(import_api.context.active(), parentSpan) : import_api.context.active();
|
|
44
|
+
const attrs = {
|
|
45
|
+
"neatlogs.span.kind": "CHAIN",
|
|
46
|
+
"neatlogs.chain.name": name
|
|
47
|
+
};
|
|
48
|
+
if (this._workflowName) attrs["neatlogs.workflow.name"] = this._workflowName;
|
|
49
|
+
if (inputs) attrs["input.value"] = safeStringify(inputs).slice(0, 1e4);
|
|
50
|
+
if (tags?.length) attrs["neatlogs.tags"] = tags.join(",");
|
|
51
|
+
const span = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);
|
|
52
|
+
this._spans.set(runId, span);
|
|
53
|
+
}
|
|
54
|
+
async handleChainEnd(outputs, runId) {
|
|
55
|
+
const span = this._spans.get(runId);
|
|
56
|
+
if (!span) return;
|
|
57
|
+
if (outputs) span.setAttribute("output.value", safeStringify(outputs).slice(0, 1e4));
|
|
58
|
+
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
59
|
+
span.end();
|
|
60
|
+
this._spans.delete(runId);
|
|
61
|
+
}
|
|
62
|
+
async handleChainError(error, runId) {
|
|
63
|
+
const span = this._spans.get(runId);
|
|
64
|
+
if (!span) return;
|
|
65
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
|
|
66
|
+
span.recordException(error);
|
|
67
|
+
span.end();
|
|
68
|
+
this._spans.delete(runId);
|
|
69
|
+
}
|
|
70
|
+
// --- LLM callbacks ---
|
|
71
|
+
async handleLLMStart(serialized, prompts, runId, parentRunId, extraParams) {
|
|
72
|
+
const tracer = import_api.trace.getTracer(TRACER_NAME);
|
|
73
|
+
const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
|
|
74
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
75
|
+
const parentCtx = parentSpan ? import_api.trace.setSpan(import_api.context.active(), parentSpan) : import_api.context.active();
|
|
76
|
+
const attrs = {
|
|
77
|
+
"neatlogs.span.kind": "LLM",
|
|
78
|
+
"neatlogs.llm.provider": detectProvider(model),
|
|
79
|
+
"neatlogs.llm.model_name": model
|
|
80
|
+
};
|
|
81
|
+
for (let i = 0; i < prompts.length; i++) {
|
|
82
|
+
attrs[`neatlogs.llm.input_messages.${i}.role`] = "user";
|
|
83
|
+
attrs[`neatlogs.llm.input_messages.${i}.content`] = prompts[i].slice(0, 1e4);
|
|
84
|
+
}
|
|
85
|
+
if (extraParams?.invocation_params) {
|
|
86
|
+
const p = extraParams.invocation_params;
|
|
87
|
+
if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
|
|
88
|
+
if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
|
|
89
|
+
if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
|
|
90
|
+
}
|
|
91
|
+
const span = tracer.startSpan("langchain.llm", { attributes: attrs }, parentCtx);
|
|
92
|
+
this._spans.set(runId, span);
|
|
93
|
+
}
|
|
94
|
+
async handleChatModelStart(serialized, messages, runId, parentRunId, extraParams) {
|
|
95
|
+
const tracer = import_api.trace.getTracer(TRACER_NAME);
|
|
96
|
+
const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
|
|
97
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
98
|
+
const parentCtx = parentSpan ? import_api.trace.setSpan(import_api.context.active(), parentSpan) : import_api.context.active();
|
|
99
|
+
const attrs = {
|
|
100
|
+
"neatlogs.span.kind": "LLM",
|
|
101
|
+
"neatlogs.llm.provider": detectProvider(model),
|
|
102
|
+
"neatlogs.llm.model_name": model
|
|
103
|
+
};
|
|
104
|
+
const flatMessages = messages.flat();
|
|
105
|
+
for (let i = 0; i < flatMessages.length; i++) {
|
|
106
|
+
const msg = flatMessages[i];
|
|
107
|
+
const role = msg?.role ?? msg?._getType?.() ?? msg?.constructor?.name ?? "unknown";
|
|
108
|
+
const content = typeof msg?.content === "string" ? msg.content : safeStringify(msg?.content);
|
|
109
|
+
attrs[`neatlogs.llm.input_messages.${i}.role`] = mapRole(role);
|
|
110
|
+
attrs[`neatlogs.llm.input_messages.${i}.content`] = content.slice(0, 1e4);
|
|
111
|
+
}
|
|
112
|
+
if (extraParams?.invocation_params) {
|
|
113
|
+
const p = extraParams.invocation_params;
|
|
114
|
+
if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
|
|
115
|
+
if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
|
|
116
|
+
if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
|
|
117
|
+
}
|
|
118
|
+
const span = tracer.startSpan("langchain.chat_model", { attributes: attrs }, parentCtx);
|
|
119
|
+
this._spans.set(runId, span);
|
|
120
|
+
}
|
|
121
|
+
async handleLLMEnd(output, runId) {
|
|
122
|
+
const span = this._spans.get(runId);
|
|
123
|
+
if (!span) return;
|
|
124
|
+
const generations = output?.generations ?? [];
|
|
125
|
+
for (let i = 0; i < generations.length; i++) {
|
|
126
|
+
const gen = generations[i];
|
|
127
|
+
if (!Array.isArray(gen)) continue;
|
|
128
|
+
for (let j = 0; j < gen.length; j++) {
|
|
129
|
+
const msg = gen[j]?.message ?? gen[j];
|
|
130
|
+
const content = msg?.content ?? msg?.text ?? "";
|
|
131
|
+
span.setAttribute(`neatlogs.llm.output_messages.${i}.role`, "assistant");
|
|
132
|
+
span.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content).slice(0, 1e4));
|
|
133
|
+
const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;
|
|
134
|
+
if (toolCalls && Array.isArray(toolCalls)) {
|
|
135
|
+
for (let k = 0; k < toolCalls.length; k++) {
|
|
136
|
+
const tc = toolCalls[k];
|
|
137
|
+
span.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? "");
|
|
138
|
+
span.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? "");
|
|
139
|
+
span.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify(tc.args) : tc.function?.arguments ?? "");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const usage = output?.llmOutput?.tokenUsage ?? output?.llmOutput?.usage;
|
|
145
|
+
if (usage) {
|
|
146
|
+
if (usage.promptTokens != null || usage.prompt_tokens != null) {
|
|
147
|
+
span.setAttribute("neatlogs.llm.token_count.prompt", usage.promptTokens ?? usage.prompt_tokens);
|
|
148
|
+
}
|
|
149
|
+
if (usage.completionTokens != null || usage.completion_tokens != null) {
|
|
150
|
+
span.setAttribute("neatlogs.llm.token_count.completion", usage.completionTokens ?? usage.completion_tokens);
|
|
151
|
+
}
|
|
152
|
+
if (usage.totalTokens != null || usage.total_tokens != null) {
|
|
153
|
+
span.setAttribute("neatlogs.llm.token_count.total", usage.totalTokens ?? usage.total_tokens);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
157
|
+
span.end();
|
|
158
|
+
this._spans.delete(runId);
|
|
159
|
+
}
|
|
160
|
+
async handleLLMNewToken(_token, _idx, _runId) {
|
|
161
|
+
}
|
|
162
|
+
async handleLLMError(error, runId) {
|
|
163
|
+
const span = this._spans.get(runId);
|
|
164
|
+
if (!span) return;
|
|
165
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
|
|
166
|
+
span.recordException(error);
|
|
167
|
+
span.end();
|
|
168
|
+
this._spans.delete(runId);
|
|
169
|
+
}
|
|
170
|
+
// --- Tool callbacks ---
|
|
171
|
+
async handleToolStart(serialized, input, runId, parentRunId, _tags, _metadata, runName, toolCallId) {
|
|
172
|
+
const tracer = import_api.trace.getTracer(TRACER_NAME);
|
|
173
|
+
const name = serialized?.name || runName || (Array.isArray(serialized?.id) ? serialized.id[serialized.id.length - 1] : void 0) || "tool";
|
|
174
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
175
|
+
const parentCtx = parentSpan ? import_api.trace.setSpan(import_api.context.active(), parentSpan) : import_api.context.active();
|
|
176
|
+
const attrs = {
|
|
177
|
+
"neatlogs.span.kind": "TOOL",
|
|
178
|
+
"neatlogs.tool.name": name,
|
|
179
|
+
"input.value": String(input).slice(0, 1e4)
|
|
180
|
+
};
|
|
181
|
+
if (toolCallId) attrs["neatlogs.tool_call.id"] = toolCallId;
|
|
182
|
+
const span = tracer.startSpan(`langchain.tool.${name}`, { attributes: attrs }, parentCtx);
|
|
183
|
+
this._spans.set(runId, span);
|
|
184
|
+
}
|
|
185
|
+
async handleToolEnd(output, runId) {
|
|
186
|
+
const span = this._spans.get(runId);
|
|
187
|
+
if (!span) return;
|
|
188
|
+
span.setAttribute("output.value", String(output).slice(0, 1e4));
|
|
189
|
+
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
190
|
+
span.end();
|
|
191
|
+
this._spans.delete(runId);
|
|
192
|
+
}
|
|
193
|
+
async handleToolError(error, runId) {
|
|
194
|
+
const span = this._spans.get(runId);
|
|
195
|
+
if (!span) return;
|
|
196
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
|
|
197
|
+
span.recordException(error);
|
|
198
|
+
span.end();
|
|
199
|
+
this._spans.delete(runId);
|
|
200
|
+
}
|
|
201
|
+
// --- Retriever callbacks ---
|
|
202
|
+
async handleRetrieverStart(serialized, query, runId, parentRunId) {
|
|
203
|
+
const tracer = import_api.trace.getTracer(TRACER_NAME);
|
|
204
|
+
const name = serialized?.name ?? "retriever";
|
|
205
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
206
|
+
const parentCtx = parentSpan ? import_api.trace.setSpan(import_api.context.active(), parentSpan) : import_api.context.active();
|
|
207
|
+
const attrs = {
|
|
208
|
+
"neatlogs.span.kind": "RETRIEVER",
|
|
209
|
+
"neatlogs.retriever.name": name,
|
|
210
|
+
"input.value": query.slice(0, 1e4)
|
|
211
|
+
};
|
|
212
|
+
const span = tracer.startSpan(`langchain.retriever.${name}`, { attributes: attrs }, parentCtx);
|
|
213
|
+
this._spans.set(runId, span);
|
|
214
|
+
}
|
|
215
|
+
async handleRetrieverEnd(documents, runId) {
|
|
216
|
+
const span = this._spans.get(runId);
|
|
217
|
+
if (!span) return;
|
|
218
|
+
if (documents?.length) {
|
|
219
|
+
span.setAttribute("neatlogs.retriever.document_count", documents.length);
|
|
220
|
+
for (let i = 0; i < Math.min(documents.length, 10); i++) {
|
|
221
|
+
const doc = documents[i];
|
|
222
|
+
if (doc?.pageContent) {
|
|
223
|
+
span.setAttribute(`neatlogs.retriever.documents.${i}.content`, doc.pageContent.slice(0, 2e3));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
228
|
+
span.end();
|
|
229
|
+
this._spans.delete(runId);
|
|
230
|
+
}
|
|
231
|
+
async handleRetrieverError(error, runId) {
|
|
232
|
+
const span = this._spans.get(runId);
|
|
233
|
+
if (!span) return;
|
|
234
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
|
|
235
|
+
span.recordException(error);
|
|
236
|
+
span.end();
|
|
237
|
+
this._spans.delete(runId);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
function detectProvider(model) {
|
|
241
|
+
const m = model.toLowerCase();
|
|
242
|
+
if (m.includes("gpt") || m.includes("o1") || m.includes("o3") || m.includes("o4")) return "openai";
|
|
243
|
+
if (m.includes("claude")) return "anthropic";
|
|
244
|
+
if (m.includes("gemini")) return "google";
|
|
245
|
+
if (m.includes("command")) return "cohere";
|
|
246
|
+
if (m.includes("llama") || m.includes("mixtral")) return "meta";
|
|
247
|
+
return "unknown";
|
|
248
|
+
}
|
|
249
|
+
function mapRole(role) {
|
|
250
|
+
const r = role.toLowerCase();
|
|
251
|
+
if (r === "human" || r === "humanmessage") return "user";
|
|
252
|
+
if (r === "ai" || r === "aimessage") return "assistant";
|
|
253
|
+
if (r === "system" || r === "systemmessage") return "system";
|
|
254
|
+
if (r === "function" || r === "functionmessage") return "function";
|
|
255
|
+
if (r === "tool" || r === "toolmessage") return "tool";
|
|
256
|
+
return role;
|
|
257
|
+
}
|
|
258
|
+
function safeStringify(value) {
|
|
259
|
+
try {
|
|
260
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
261
|
+
} catch {
|
|
262
|
+
return "";
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
266
|
+
0 && (module.exports = {
|
|
267
|
+
langchainHandler
|
|
268
|
+
});
|
|
269
|
+
//# sourceMappingURL=langchain.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/langchain.ts"],"sourcesContent":["/**\n * Neatlogs LangChain/LangGraph callback handler.\n *\n * Usage:\n * import { langchainHandler } from 'neatlogs/langchain';\n * const result = await chain.invoke(input, { callbacks: [langchainHandler()] });\n *\n * Creates spans: CHAIN (chain/graph runs), LLM (model calls), TOOL (tool invocations).\n * Works with LangChain, LangGraph, and Deep Agents (same callback interface).\n */\n\nimport { trace, context as otelContext, SpanStatusCode, type Span } from '@opentelemetry/api';\n\nconst TRACER_NAME = 'neatlogs.langchain';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface LangchainHandlerOptions {\n workflowName?: string;\n}\n\nexport function langchainHandler(opts?: LangchainHandlerOptions): any {\n return new NeatlogsCallbackHandler(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Callback Handler\n// ---------------------------------------------------------------------------\n\nclass NeatlogsCallbackHandler {\n name = 'neatlogs';\n private _spans: Map<string, Span> = new Map();\n private _workflowName: string | undefined;\n\n constructor(opts?: LangchainHandlerOptions) {\n this._workflowName = opts?.workflowName;\n }\n\n // --- Chain/Graph callbacks ---\n\n async handleChainStart(\n serialized: Record<string, any>,\n inputs: Record<string, any>,\n runId: string,\n parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, any>,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const name = serialized?.name ?? serialized?.id?.at(-1) ?? 'chain';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'CHAIN',\n 'neatlogs.chain.name': name,\n };\n if (this._workflowName) attrs['neatlogs.workflow.name'] = this._workflowName;\n if (inputs) attrs['input.value'] = safeStringify(inputs).slice(0, 10000);\n if (tags?.length) attrs['neatlogs.tags'] = tags.join(',');\n\n const span = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleChainEnd(\n outputs: Record<string, any>,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n if (outputs) span.setAttribute('output.value', safeStringify(outputs).slice(0, 10000));\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleChainError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n\n // --- LLM callbacks ---\n\n async handleLLMStart(\n serialized: Record<string, any>,\n prompts: string[],\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, any>,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? '';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'LLM',\n 'neatlogs.llm.provider': detectProvider(model),\n 'neatlogs.llm.model_name': model,\n };\n\n for (let i = 0; i < prompts.length; i++) {\n attrs[`neatlogs.llm.input_messages.${i}.role`] = 'user';\n attrs[`neatlogs.llm.input_messages.${i}.content`] = prompts[i].slice(0, 10000);\n }\n\n if (extraParams?.invocation_params) {\n const p = extraParams.invocation_params;\n if (p.temperature != null) attrs['neatlogs.llm.temperature'] = p.temperature;\n if (p.max_tokens != null) attrs['neatlogs.llm.max_tokens'] = p.max_tokens;\n if (p.model_name) attrs['neatlogs.llm.model_name'] = p.model_name;\n }\n\n const span = tracer.startSpan('langchain.llm', { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleChatModelStart(\n serialized: Record<string, any>,\n messages: any[][],\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, any>,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? '';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'LLM',\n 'neatlogs.llm.provider': detectProvider(model),\n 'neatlogs.llm.model_name': model,\n };\n\n const flatMessages = messages.flat();\n for (let i = 0; i < flatMessages.length; i++) {\n const msg = flatMessages[i];\n const role = msg?.role ?? msg?._getType?.() ?? msg?.constructor?.name ?? 'unknown';\n const content = typeof msg?.content === 'string' ? msg.content : safeStringify(msg?.content);\n attrs[`neatlogs.llm.input_messages.${i}.role`] = mapRole(role);\n attrs[`neatlogs.llm.input_messages.${i}.content`] = content.slice(0, 10000);\n }\n\n if (extraParams?.invocation_params) {\n const p = extraParams.invocation_params;\n if (p.temperature != null) attrs['neatlogs.llm.temperature'] = p.temperature;\n if (p.max_tokens != null) attrs['neatlogs.llm.max_tokens'] = p.max_tokens;\n if (p.model_name) attrs['neatlogs.llm.model_name'] = p.model_name;\n }\n\n const span = tracer.startSpan('langchain.chat_model', { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleLLMEnd(\n output: any,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n const generations = output?.generations ?? [];\n for (let i = 0; i < generations.length; i++) {\n const gen = generations[i];\n if (!Array.isArray(gen)) continue;\n for (let j = 0; j < gen.length; j++) {\n const msg = gen[j]?.message ?? gen[j];\n const content = msg?.content ?? msg?.text ?? '';\n span.setAttribute(`neatlogs.llm.output_messages.${i}.role`, 'assistant');\n span.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content).slice(0, 10000));\n\n const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;\n if (toolCalls && Array.isArray(toolCalls)) {\n for (let k = 0; k < toolCalls.length; k++) {\n const tc = toolCalls[k];\n span.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? '');\n span.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? '');\n span.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify(tc.args) : (tc.function?.arguments ?? ''));\n }\n }\n }\n }\n\n const usage = output?.llmOutput?.tokenUsage ?? output?.llmOutput?.usage;\n if (usage) {\n if (usage.promptTokens != null || usage.prompt_tokens != null) {\n span.setAttribute('neatlogs.llm.token_count.prompt', usage.promptTokens ?? usage.prompt_tokens);\n }\n if (usage.completionTokens != null || usage.completion_tokens != null) {\n span.setAttribute('neatlogs.llm.token_count.completion', usage.completionTokens ?? usage.completion_tokens);\n }\n if (usage.totalTokens != null || usage.total_tokens != null) {\n span.setAttribute('neatlogs.llm.token_count.total', usage.totalTokens ?? usage.total_tokens);\n }\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleLLMNewToken(\n _token: string,\n _idx: any,\n _runId: string,\n ): Promise<void> {}\n\n async handleLLMError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n\n // --- Tool callbacks ---\n\n async handleToolStart(\n serialized: Record<string, any>,\n input: string,\n runId: string,\n parentRunId?: string,\n _tags?: string[],\n _metadata?: Record<string, unknown>,\n runName?: string,\n toolCallId?: string,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n // LangChain 1.x: serialized.name is absent and serialized.id is the class\n // name (e.g. \"DynamicStructuredTool\"); the real tool name arrives as `runName`.\n // Prefer serialized.name (older LC), then runName, then the class id, then 'tool'.\n const name =\n serialized?.name ||\n runName ||\n (Array.isArray(serialized?.id) ? serialized.id[serialized.id.length - 1] : undefined) ||\n 'tool';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'TOOL',\n 'neatlogs.tool.name': name,\n 'input.value': String(input).slice(0, 10000),\n };\n if (toolCallId) attrs['neatlogs.tool_call.id'] = toolCallId;\n\n const span = tracer.startSpan(`langchain.tool.${name}`, { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleToolEnd(\n output: string,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setAttribute('output.value', String(output).slice(0, 10000));\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleToolError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n\n // --- Retriever callbacks ---\n\n async handleRetrieverStart(\n serialized: Record<string, any>,\n query: string,\n runId: string,\n parentRunId?: string,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const name = serialized?.name ?? 'retriever';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'RETRIEVER',\n 'neatlogs.retriever.name': name,\n 'input.value': query.slice(0, 10000),\n };\n\n const span = tracer.startSpan(`langchain.retriever.${name}`, { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleRetrieverEnd(\n documents: any[],\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n if (documents?.length) {\n span.setAttribute('neatlogs.retriever.document_count', documents.length);\n for (let i = 0; i < Math.min(documents.length, 10); i++) {\n const doc = documents[i];\n if (doc?.pageContent) {\n span.setAttribute(`neatlogs.retriever.documents.${i}.content`, doc.pageContent.slice(0, 2000));\n }\n }\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleRetrieverError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction detectProvider(model: string): string {\n const m = model.toLowerCase();\n if (m.includes('gpt') || m.includes('o1') || m.includes('o3') || m.includes('o4')) return 'openai';\n if (m.includes('claude')) return 'anthropic';\n if (m.includes('gemini')) return 'google';\n if (m.includes('command')) return 'cohere';\n if (m.includes('llama') || m.includes('mixtral')) return 'meta';\n return 'unknown';\n}\n\nfunction mapRole(role: string): string {\n const r = role.toLowerCase();\n if (r === 'human' || r === 'humanmessage') return 'user';\n if (r === 'ai' || r === 'aimessage') return 'assistant';\n if (r === 'system' || r === 'systemmessage') return 'system';\n if (r === 'function' || r === 'functionmessage') return 'function';\n if (r === 'tool' || r === 'toolmessage') return 'tool';\n return role;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return typeof value === 'string' ? value : JSON.stringify(value);\n } catch {\n return '';\n }\n}\n"],"mappings":"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","names":["otelContext"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Neatlogs LangChain/LangGraph callback handler.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { langchainHandler } from 'neatlogs/langchain';
|
|
6
|
+
* const result = await chain.invoke(input, { callbacks: [langchainHandler()] });
|
|
7
|
+
*
|
|
8
|
+
* Creates spans: CHAIN (chain/graph runs), LLM (model calls), TOOL (tool invocations).
|
|
9
|
+
* Works with LangChain, LangGraph, and Deep Agents (same callback interface).
|
|
10
|
+
*/
|
|
11
|
+
interface LangchainHandlerOptions {
|
|
12
|
+
workflowName?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function langchainHandler(opts?: LangchainHandlerOptions): any;
|
|
15
|
+
|
|
16
|
+
export { type LangchainHandlerOptions, langchainHandler };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// src/langchain.ts
|
|
2
|
+
import { trace, context as otelContext, SpanStatusCode } from "@opentelemetry/api";
|
|
3
|
+
var TRACER_NAME = "neatlogs.langchain";
|
|
4
|
+
function langchainHandler(opts) {
|
|
5
|
+
return new NeatlogsCallbackHandler(opts);
|
|
6
|
+
}
|
|
7
|
+
var NeatlogsCallbackHandler = class {
|
|
8
|
+
name = "neatlogs";
|
|
9
|
+
_spans = /* @__PURE__ */ new Map();
|
|
10
|
+
_workflowName;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this._workflowName = opts?.workflowName;
|
|
13
|
+
}
|
|
14
|
+
// --- Chain/Graph callbacks ---
|
|
15
|
+
async handleChainStart(serialized, inputs, runId, parentRunId, tags, metadata) {
|
|
16
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
17
|
+
const name = serialized?.name ?? serialized?.id?.at(-1) ?? "chain";
|
|
18
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
19
|
+
const parentCtx = parentSpan ? trace.setSpan(otelContext.active(), parentSpan) : otelContext.active();
|
|
20
|
+
const attrs = {
|
|
21
|
+
"neatlogs.span.kind": "CHAIN",
|
|
22
|
+
"neatlogs.chain.name": name
|
|
23
|
+
};
|
|
24
|
+
if (this._workflowName) attrs["neatlogs.workflow.name"] = this._workflowName;
|
|
25
|
+
if (inputs) attrs["input.value"] = safeStringify(inputs).slice(0, 1e4);
|
|
26
|
+
if (tags?.length) attrs["neatlogs.tags"] = tags.join(",");
|
|
27
|
+
const span = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);
|
|
28
|
+
this._spans.set(runId, span);
|
|
29
|
+
}
|
|
30
|
+
async handleChainEnd(outputs, runId) {
|
|
31
|
+
const span = this._spans.get(runId);
|
|
32
|
+
if (!span) return;
|
|
33
|
+
if (outputs) span.setAttribute("output.value", safeStringify(outputs).slice(0, 1e4));
|
|
34
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
35
|
+
span.end();
|
|
36
|
+
this._spans.delete(runId);
|
|
37
|
+
}
|
|
38
|
+
async handleChainError(error, runId) {
|
|
39
|
+
const span = this._spans.get(runId);
|
|
40
|
+
if (!span) return;
|
|
41
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
42
|
+
span.recordException(error);
|
|
43
|
+
span.end();
|
|
44
|
+
this._spans.delete(runId);
|
|
45
|
+
}
|
|
46
|
+
// --- LLM callbacks ---
|
|
47
|
+
async handleLLMStart(serialized, prompts, runId, parentRunId, extraParams) {
|
|
48
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
49
|
+
const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
|
|
50
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
51
|
+
const parentCtx = parentSpan ? trace.setSpan(otelContext.active(), parentSpan) : otelContext.active();
|
|
52
|
+
const attrs = {
|
|
53
|
+
"neatlogs.span.kind": "LLM",
|
|
54
|
+
"neatlogs.llm.provider": detectProvider(model),
|
|
55
|
+
"neatlogs.llm.model_name": model
|
|
56
|
+
};
|
|
57
|
+
for (let i = 0; i < prompts.length; i++) {
|
|
58
|
+
attrs[`neatlogs.llm.input_messages.${i}.role`] = "user";
|
|
59
|
+
attrs[`neatlogs.llm.input_messages.${i}.content`] = prompts[i].slice(0, 1e4);
|
|
60
|
+
}
|
|
61
|
+
if (extraParams?.invocation_params) {
|
|
62
|
+
const p = extraParams.invocation_params;
|
|
63
|
+
if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
|
|
64
|
+
if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
|
|
65
|
+
if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
|
|
66
|
+
}
|
|
67
|
+
const span = tracer.startSpan("langchain.llm", { attributes: attrs }, parentCtx);
|
|
68
|
+
this._spans.set(runId, span);
|
|
69
|
+
}
|
|
70
|
+
async handleChatModelStart(serialized, messages, runId, parentRunId, extraParams) {
|
|
71
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
72
|
+
const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
|
|
73
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
74
|
+
const parentCtx = parentSpan ? trace.setSpan(otelContext.active(), parentSpan) : otelContext.active();
|
|
75
|
+
const attrs = {
|
|
76
|
+
"neatlogs.span.kind": "LLM",
|
|
77
|
+
"neatlogs.llm.provider": detectProvider(model),
|
|
78
|
+
"neatlogs.llm.model_name": model
|
|
79
|
+
};
|
|
80
|
+
const flatMessages = messages.flat();
|
|
81
|
+
for (let i = 0; i < flatMessages.length; i++) {
|
|
82
|
+
const msg = flatMessages[i];
|
|
83
|
+
const role = msg?.role ?? msg?._getType?.() ?? msg?.constructor?.name ?? "unknown";
|
|
84
|
+
const content = typeof msg?.content === "string" ? msg.content : safeStringify(msg?.content);
|
|
85
|
+
attrs[`neatlogs.llm.input_messages.${i}.role`] = mapRole(role);
|
|
86
|
+
attrs[`neatlogs.llm.input_messages.${i}.content`] = content.slice(0, 1e4);
|
|
87
|
+
}
|
|
88
|
+
if (extraParams?.invocation_params) {
|
|
89
|
+
const p = extraParams.invocation_params;
|
|
90
|
+
if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
|
|
91
|
+
if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
|
|
92
|
+
if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
|
|
93
|
+
}
|
|
94
|
+
const span = tracer.startSpan("langchain.chat_model", { attributes: attrs }, parentCtx);
|
|
95
|
+
this._spans.set(runId, span);
|
|
96
|
+
}
|
|
97
|
+
async handleLLMEnd(output, runId) {
|
|
98
|
+
const span = this._spans.get(runId);
|
|
99
|
+
if (!span) return;
|
|
100
|
+
const generations = output?.generations ?? [];
|
|
101
|
+
for (let i = 0; i < generations.length; i++) {
|
|
102
|
+
const gen = generations[i];
|
|
103
|
+
if (!Array.isArray(gen)) continue;
|
|
104
|
+
for (let j = 0; j < gen.length; j++) {
|
|
105
|
+
const msg = gen[j]?.message ?? gen[j];
|
|
106
|
+
const content = msg?.content ?? msg?.text ?? "";
|
|
107
|
+
span.setAttribute(`neatlogs.llm.output_messages.${i}.role`, "assistant");
|
|
108
|
+
span.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content).slice(0, 1e4));
|
|
109
|
+
const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;
|
|
110
|
+
if (toolCalls && Array.isArray(toolCalls)) {
|
|
111
|
+
for (let k = 0; k < toolCalls.length; k++) {
|
|
112
|
+
const tc = toolCalls[k];
|
|
113
|
+
span.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? "");
|
|
114
|
+
span.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? "");
|
|
115
|
+
span.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify(tc.args) : tc.function?.arguments ?? "");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const usage = output?.llmOutput?.tokenUsage ?? output?.llmOutput?.usage;
|
|
121
|
+
if (usage) {
|
|
122
|
+
if (usage.promptTokens != null || usage.prompt_tokens != null) {
|
|
123
|
+
span.setAttribute("neatlogs.llm.token_count.prompt", usage.promptTokens ?? usage.prompt_tokens);
|
|
124
|
+
}
|
|
125
|
+
if (usage.completionTokens != null || usage.completion_tokens != null) {
|
|
126
|
+
span.setAttribute("neatlogs.llm.token_count.completion", usage.completionTokens ?? usage.completion_tokens);
|
|
127
|
+
}
|
|
128
|
+
if (usage.totalTokens != null || usage.total_tokens != null) {
|
|
129
|
+
span.setAttribute("neatlogs.llm.token_count.total", usage.totalTokens ?? usage.total_tokens);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
133
|
+
span.end();
|
|
134
|
+
this._spans.delete(runId);
|
|
135
|
+
}
|
|
136
|
+
async handleLLMNewToken(_token, _idx, _runId) {
|
|
137
|
+
}
|
|
138
|
+
async handleLLMError(error, runId) {
|
|
139
|
+
const span = this._spans.get(runId);
|
|
140
|
+
if (!span) return;
|
|
141
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
142
|
+
span.recordException(error);
|
|
143
|
+
span.end();
|
|
144
|
+
this._spans.delete(runId);
|
|
145
|
+
}
|
|
146
|
+
// --- Tool callbacks ---
|
|
147
|
+
async handleToolStart(serialized, input, runId, parentRunId, _tags, _metadata, runName, toolCallId) {
|
|
148
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
149
|
+
const name = serialized?.name || runName || (Array.isArray(serialized?.id) ? serialized.id[serialized.id.length - 1] : void 0) || "tool";
|
|
150
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
151
|
+
const parentCtx = parentSpan ? trace.setSpan(otelContext.active(), parentSpan) : otelContext.active();
|
|
152
|
+
const attrs = {
|
|
153
|
+
"neatlogs.span.kind": "TOOL",
|
|
154
|
+
"neatlogs.tool.name": name,
|
|
155
|
+
"input.value": String(input).slice(0, 1e4)
|
|
156
|
+
};
|
|
157
|
+
if (toolCallId) attrs["neatlogs.tool_call.id"] = toolCallId;
|
|
158
|
+
const span = tracer.startSpan(`langchain.tool.${name}`, { attributes: attrs }, parentCtx);
|
|
159
|
+
this._spans.set(runId, span);
|
|
160
|
+
}
|
|
161
|
+
async handleToolEnd(output, runId) {
|
|
162
|
+
const span = this._spans.get(runId);
|
|
163
|
+
if (!span) return;
|
|
164
|
+
span.setAttribute("output.value", String(output).slice(0, 1e4));
|
|
165
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
166
|
+
span.end();
|
|
167
|
+
this._spans.delete(runId);
|
|
168
|
+
}
|
|
169
|
+
async handleToolError(error, runId) {
|
|
170
|
+
const span = this._spans.get(runId);
|
|
171
|
+
if (!span) return;
|
|
172
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
173
|
+
span.recordException(error);
|
|
174
|
+
span.end();
|
|
175
|
+
this._spans.delete(runId);
|
|
176
|
+
}
|
|
177
|
+
// --- Retriever callbacks ---
|
|
178
|
+
async handleRetrieverStart(serialized, query, runId, parentRunId) {
|
|
179
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
180
|
+
const name = serialized?.name ?? "retriever";
|
|
181
|
+
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
182
|
+
const parentCtx = parentSpan ? trace.setSpan(otelContext.active(), parentSpan) : otelContext.active();
|
|
183
|
+
const attrs = {
|
|
184
|
+
"neatlogs.span.kind": "RETRIEVER",
|
|
185
|
+
"neatlogs.retriever.name": name,
|
|
186
|
+
"input.value": query.slice(0, 1e4)
|
|
187
|
+
};
|
|
188
|
+
const span = tracer.startSpan(`langchain.retriever.${name}`, { attributes: attrs }, parentCtx);
|
|
189
|
+
this._spans.set(runId, span);
|
|
190
|
+
}
|
|
191
|
+
async handleRetrieverEnd(documents, runId) {
|
|
192
|
+
const span = this._spans.get(runId);
|
|
193
|
+
if (!span) return;
|
|
194
|
+
if (documents?.length) {
|
|
195
|
+
span.setAttribute("neatlogs.retriever.document_count", documents.length);
|
|
196
|
+
for (let i = 0; i < Math.min(documents.length, 10); i++) {
|
|
197
|
+
const doc = documents[i];
|
|
198
|
+
if (doc?.pageContent) {
|
|
199
|
+
span.setAttribute(`neatlogs.retriever.documents.${i}.content`, doc.pageContent.slice(0, 2e3));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
204
|
+
span.end();
|
|
205
|
+
this._spans.delete(runId);
|
|
206
|
+
}
|
|
207
|
+
async handleRetrieverError(error, runId) {
|
|
208
|
+
const span = this._spans.get(runId);
|
|
209
|
+
if (!span) return;
|
|
210
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
211
|
+
span.recordException(error);
|
|
212
|
+
span.end();
|
|
213
|
+
this._spans.delete(runId);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function detectProvider(model) {
|
|
217
|
+
const m = model.toLowerCase();
|
|
218
|
+
if (m.includes("gpt") || m.includes("o1") || m.includes("o3") || m.includes("o4")) return "openai";
|
|
219
|
+
if (m.includes("claude")) return "anthropic";
|
|
220
|
+
if (m.includes("gemini")) return "google";
|
|
221
|
+
if (m.includes("command")) return "cohere";
|
|
222
|
+
if (m.includes("llama") || m.includes("mixtral")) return "meta";
|
|
223
|
+
return "unknown";
|
|
224
|
+
}
|
|
225
|
+
function mapRole(role) {
|
|
226
|
+
const r = role.toLowerCase();
|
|
227
|
+
if (r === "human" || r === "humanmessage") return "user";
|
|
228
|
+
if (r === "ai" || r === "aimessage") return "assistant";
|
|
229
|
+
if (r === "system" || r === "systemmessage") return "system";
|
|
230
|
+
if (r === "function" || r === "functionmessage") return "function";
|
|
231
|
+
if (r === "tool" || r === "toolmessage") return "tool";
|
|
232
|
+
return role;
|
|
233
|
+
}
|
|
234
|
+
function safeStringify(value) {
|
|
235
|
+
try {
|
|
236
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
237
|
+
} catch {
|
|
238
|
+
return "";
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
export {
|
|
242
|
+
langchainHandler
|
|
243
|
+
};
|
|
244
|
+
//# sourceMappingURL=langchain.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/langchain.ts"],"sourcesContent":["/**\n * Neatlogs LangChain/LangGraph callback handler.\n *\n * Usage:\n * import { langchainHandler } from 'neatlogs/langchain';\n * const result = await chain.invoke(input, { callbacks: [langchainHandler()] });\n *\n * Creates spans: CHAIN (chain/graph runs), LLM (model calls), TOOL (tool invocations).\n * Works with LangChain, LangGraph, and Deep Agents (same callback interface).\n */\n\nimport { trace, context as otelContext, SpanStatusCode, type Span } from '@opentelemetry/api';\n\nconst TRACER_NAME = 'neatlogs.langchain';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface LangchainHandlerOptions {\n workflowName?: string;\n}\n\nexport function langchainHandler(opts?: LangchainHandlerOptions): any {\n return new NeatlogsCallbackHandler(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Callback Handler\n// ---------------------------------------------------------------------------\n\nclass NeatlogsCallbackHandler {\n name = 'neatlogs';\n private _spans: Map<string, Span> = new Map();\n private _workflowName: string | undefined;\n\n constructor(opts?: LangchainHandlerOptions) {\n this._workflowName = opts?.workflowName;\n }\n\n // --- Chain/Graph callbacks ---\n\n async handleChainStart(\n serialized: Record<string, any>,\n inputs: Record<string, any>,\n runId: string,\n parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, any>,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const name = serialized?.name ?? serialized?.id?.at(-1) ?? 'chain';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'CHAIN',\n 'neatlogs.chain.name': name,\n };\n if (this._workflowName) attrs['neatlogs.workflow.name'] = this._workflowName;\n if (inputs) attrs['input.value'] = safeStringify(inputs).slice(0, 10000);\n if (tags?.length) attrs['neatlogs.tags'] = tags.join(',');\n\n const span = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleChainEnd(\n outputs: Record<string, any>,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n if (outputs) span.setAttribute('output.value', safeStringify(outputs).slice(0, 10000));\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleChainError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n\n // --- LLM callbacks ---\n\n async handleLLMStart(\n serialized: Record<string, any>,\n prompts: string[],\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, any>,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? '';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'LLM',\n 'neatlogs.llm.provider': detectProvider(model),\n 'neatlogs.llm.model_name': model,\n };\n\n for (let i = 0; i < prompts.length; i++) {\n attrs[`neatlogs.llm.input_messages.${i}.role`] = 'user';\n attrs[`neatlogs.llm.input_messages.${i}.content`] = prompts[i].slice(0, 10000);\n }\n\n if (extraParams?.invocation_params) {\n const p = extraParams.invocation_params;\n if (p.temperature != null) attrs['neatlogs.llm.temperature'] = p.temperature;\n if (p.max_tokens != null) attrs['neatlogs.llm.max_tokens'] = p.max_tokens;\n if (p.model_name) attrs['neatlogs.llm.model_name'] = p.model_name;\n }\n\n const span = tracer.startSpan('langchain.llm', { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleChatModelStart(\n serialized: Record<string, any>,\n messages: any[][],\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, any>,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? '';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'LLM',\n 'neatlogs.llm.provider': detectProvider(model),\n 'neatlogs.llm.model_name': model,\n };\n\n const flatMessages = messages.flat();\n for (let i = 0; i < flatMessages.length; i++) {\n const msg = flatMessages[i];\n const role = msg?.role ?? msg?._getType?.() ?? msg?.constructor?.name ?? 'unknown';\n const content = typeof msg?.content === 'string' ? msg.content : safeStringify(msg?.content);\n attrs[`neatlogs.llm.input_messages.${i}.role`] = mapRole(role);\n attrs[`neatlogs.llm.input_messages.${i}.content`] = content.slice(0, 10000);\n }\n\n if (extraParams?.invocation_params) {\n const p = extraParams.invocation_params;\n if (p.temperature != null) attrs['neatlogs.llm.temperature'] = p.temperature;\n if (p.max_tokens != null) attrs['neatlogs.llm.max_tokens'] = p.max_tokens;\n if (p.model_name) attrs['neatlogs.llm.model_name'] = p.model_name;\n }\n\n const span = tracer.startSpan('langchain.chat_model', { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleLLMEnd(\n output: any,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n const generations = output?.generations ?? [];\n for (let i = 0; i < generations.length; i++) {\n const gen = generations[i];\n if (!Array.isArray(gen)) continue;\n for (let j = 0; j < gen.length; j++) {\n const msg = gen[j]?.message ?? gen[j];\n const content = msg?.content ?? msg?.text ?? '';\n span.setAttribute(`neatlogs.llm.output_messages.${i}.role`, 'assistant');\n span.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content).slice(0, 10000));\n\n const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;\n if (toolCalls && Array.isArray(toolCalls)) {\n for (let k = 0; k < toolCalls.length; k++) {\n const tc = toolCalls[k];\n span.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? '');\n span.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? '');\n span.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify(tc.args) : (tc.function?.arguments ?? ''));\n }\n }\n }\n }\n\n const usage = output?.llmOutput?.tokenUsage ?? output?.llmOutput?.usage;\n if (usage) {\n if (usage.promptTokens != null || usage.prompt_tokens != null) {\n span.setAttribute('neatlogs.llm.token_count.prompt', usage.promptTokens ?? usage.prompt_tokens);\n }\n if (usage.completionTokens != null || usage.completion_tokens != null) {\n span.setAttribute('neatlogs.llm.token_count.completion', usage.completionTokens ?? usage.completion_tokens);\n }\n if (usage.totalTokens != null || usage.total_tokens != null) {\n span.setAttribute('neatlogs.llm.token_count.total', usage.totalTokens ?? usage.total_tokens);\n }\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleLLMNewToken(\n _token: string,\n _idx: any,\n _runId: string,\n ): Promise<void> {}\n\n async handleLLMError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n\n // --- Tool callbacks ---\n\n async handleToolStart(\n serialized: Record<string, any>,\n input: string,\n runId: string,\n parentRunId?: string,\n _tags?: string[],\n _metadata?: Record<string, unknown>,\n runName?: string,\n toolCallId?: string,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n // LangChain 1.x: serialized.name is absent and serialized.id is the class\n // name (e.g. \"DynamicStructuredTool\"); the real tool name arrives as `runName`.\n // Prefer serialized.name (older LC), then runName, then the class id, then 'tool'.\n const name =\n serialized?.name ||\n runName ||\n (Array.isArray(serialized?.id) ? serialized.id[serialized.id.length - 1] : undefined) ||\n 'tool';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'TOOL',\n 'neatlogs.tool.name': name,\n 'input.value': String(input).slice(0, 10000),\n };\n if (toolCallId) attrs['neatlogs.tool_call.id'] = toolCallId;\n\n const span = tracer.startSpan(`langchain.tool.${name}`, { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleToolEnd(\n output: string,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setAttribute('output.value', String(output).slice(0, 10000));\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleToolError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n\n // --- Retriever callbacks ---\n\n async handleRetrieverStart(\n serialized: Record<string, any>,\n query: string,\n runId: string,\n parentRunId?: string,\n ): Promise<void> {\n const tracer = trace.getTracer(TRACER_NAME);\n const name = serialized?.name ?? 'retriever';\n\n const parentSpan = parentRunId ? this._spans.get(parentRunId) : undefined;\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'RETRIEVER',\n 'neatlogs.retriever.name': name,\n 'input.value': query.slice(0, 10000),\n };\n\n const span = tracer.startSpan(`langchain.retriever.${name}`, { attributes: attrs }, parentCtx);\n this._spans.set(runId, span);\n }\n\n async handleRetrieverEnd(\n documents: any[],\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n if (documents?.length) {\n span.setAttribute('neatlogs.retriever.document_count', documents.length);\n for (let i = 0; i < Math.min(documents.length, 10); i++) {\n const doc = documents[i];\n if (doc?.pageContent) {\n span.setAttribute(`neatlogs.retriever.documents.${i}.content`, doc.pageContent.slice(0, 2000));\n }\n }\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(runId);\n }\n\n async handleRetrieverError(\n error: Error,\n runId: string,\n ): Promise<void> {\n const span = this._spans.get(runId);\n if (!span) return;\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.end();\n this._spans.delete(runId);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction detectProvider(model: string): string {\n const m = model.toLowerCase();\n if (m.includes('gpt') || m.includes('o1') || m.includes('o3') || m.includes('o4')) return 'openai';\n if (m.includes('claude')) return 'anthropic';\n if (m.includes('gemini')) return 'google';\n if (m.includes('command')) return 'cohere';\n if (m.includes('llama') || m.includes('mixtral')) return 'meta';\n return 'unknown';\n}\n\nfunction mapRole(role: string): string {\n const r = role.toLowerCase();\n if (r === 'human' || r === 'humanmessage') return 'user';\n if (r === 'ai' || r === 'aimessage') return 'assistant';\n if (r === 'system' || r === 'systemmessage') return 'system';\n if (r === 'function' || r === 'functionmessage') return 'function';\n if (r === 'tool' || r === 'toolmessage') return 'tool';\n return role;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return typeof value === 'string' ? value : JSON.stringify(value);\n } catch {\n return '';\n }\n}\n"],"mappings":"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","names":[]}
|