@elasticdash/langchain 0.0.1 → 0.0.2
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/LICENSE +24 -0
- package/README.md +2 -2
- package/dist/index.cjs +559 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +69 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.mjs +538 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +12 -12
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
This repository is licensed under the MIT License. Portions of this codebase are derived from posthog/posthog-js-lite by PostHog, which is also licensed under the MIT License.
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2023-2026 Langfuse GmbH
|
|
6
|
+
Copyright (c) 2022 PostHog (part of Hiberly Inc)
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -6,8 +6,8 @@ This is the Langchain integration package of the Langfuse JS SDK containing the
|
|
|
6
6
|
|
|
7
7
|
## Packages
|
|
8
8
|
|
|
9
|
-
| Package
|
|
10
|
-
|
|
|
9
|
+
| Package | NPM | Description | Environments |
|
|
10
|
+
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ------------ |
|
|
11
11
|
| [@elasticdash/client](./packages/client) | [](https://www.npmjs.com/package/@elasticdash/client) | Langfuse API client for universal JavaScript environments | Universal JS |
|
|
12
12
|
| [@elasticdash/tracing](./packages/tracing) | [](https://www.npmjs.com/package/@elasticdash/tracing) | Langfuse instrumentation methods based on OpenTelemetry | Node.js 20+ |
|
|
13
13
|
| [@elasticdash/otel](./packages/otel) | [](https://www.npmjs.com/package/@elasticdash/otel) | Langfuse OpenTelemetry export helpers | Node.js 20+ |
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
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/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CallbackHandler: () => CallbackHandler
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/CallbackHandler.ts
|
|
28
|
+
var import_core = require("@elasticdash/core");
|
|
29
|
+
var import_tracing = require("@elasticdash/tracing");
|
|
30
|
+
var import_base = require("@langchain/core/callbacks/base");
|
|
31
|
+
var import_messages = require("@langchain/core/messages");
|
|
32
|
+
var LANGSMITH_HIDDEN_TAG = "langsmith:hidden";
|
|
33
|
+
var CallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
34
|
+
constructor(params) {
|
|
35
|
+
var _a;
|
|
36
|
+
super();
|
|
37
|
+
this.name = "LangfuseCallbackHandler";
|
|
38
|
+
this.completionStartTimes = {};
|
|
39
|
+
this.runMap = /* @__PURE__ */ new Map();
|
|
40
|
+
this.last_trace_id = null;
|
|
41
|
+
this.sessionId = params == null ? void 0 : params.sessionId;
|
|
42
|
+
this.userId = params == null ? void 0 : params.userId;
|
|
43
|
+
this.tags = (_a = params == null ? void 0 : params.tags) != null ? _a : [];
|
|
44
|
+
this.traceMetadata = params == null ? void 0 : params.traceMetadata;
|
|
45
|
+
this.version = params == null ? void 0 : params.version;
|
|
46
|
+
this.promptToParentRunMap = /* @__PURE__ */ new Map();
|
|
47
|
+
}
|
|
48
|
+
get logger() {
|
|
49
|
+
return (0, import_core.getGlobalLogger)();
|
|
50
|
+
}
|
|
51
|
+
async handleLLMNewToken(token, _idx, runId, _parentRunId, _tags, _fields) {
|
|
52
|
+
if (runId && !(runId in this.completionStartTimes)) {
|
|
53
|
+
this.logger.debug(`LLM first streaming token: ${runId}`);
|
|
54
|
+
this.completionStartTimes[runId] = /* @__PURE__ */ new Date();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, name) {
|
|
58
|
+
var _a, _b;
|
|
59
|
+
try {
|
|
60
|
+
this.logger.debug(`Chain start with Id: ${runId}`);
|
|
61
|
+
const runName = (_b = name != null ? name : (_a = chain.id.at(-1)) == null ? void 0 : _a.toString()) != null ? _b : "Langchain Run";
|
|
62
|
+
this.registerLangfusePrompt(parentRunId, metadata);
|
|
63
|
+
let finalInput = inputs;
|
|
64
|
+
if (typeof inputs === "object" && "input" in inputs && Array.isArray(inputs["input"]) && inputs["input"].every((m) => m instanceof import_messages.BaseMessage)) {
|
|
65
|
+
finalInput = inputs["input"].map(
|
|
66
|
+
(m) => this.extractChatMessageContent(m)
|
|
67
|
+
);
|
|
68
|
+
} else if (typeof inputs === "object" && "messages" in inputs && Array.isArray(inputs["messages"]) && inputs["messages"].every((m) => m instanceof import_messages.BaseMessage)) {
|
|
69
|
+
finalInput = inputs["messages"].map(
|
|
70
|
+
(m) => this.extractChatMessageContent(m)
|
|
71
|
+
);
|
|
72
|
+
} else if (typeof inputs === "object" && "content" in inputs && typeof inputs["content"] === "string") {
|
|
73
|
+
finalInput = inputs["content"];
|
|
74
|
+
}
|
|
75
|
+
const span = this.startAndRegisterOtelSpan({
|
|
76
|
+
runName,
|
|
77
|
+
parentRunId,
|
|
78
|
+
runId,
|
|
79
|
+
tags,
|
|
80
|
+
metadata,
|
|
81
|
+
attributes: {
|
|
82
|
+
input: finalInput
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const traceTags = [.../* @__PURE__ */ new Set([...tags != null ? tags : [], ...this.tags])];
|
|
86
|
+
if (!parentRunId) {
|
|
87
|
+
span.updateTrace({
|
|
88
|
+
tags: traceTags,
|
|
89
|
+
userId: metadata && "langfuseUserId" in metadata && typeof metadata["langfuseUserId"] === "string" ? metadata["langfuseUserId"] : this.userId,
|
|
90
|
+
sessionId: metadata && "langfuseSessionId" in metadata && typeof metadata["langfuseSessionId"] === "string" ? metadata["langfuseSessionId"] : this.sessionId,
|
|
91
|
+
metadata: this.traceMetadata,
|
|
92
|
+
version: this.version
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async handleAgentAction(action, runId, parentRunId) {
|
|
100
|
+
try {
|
|
101
|
+
this.logger.debug(`Agent action ${action.tool} with ID: ${runId}`);
|
|
102
|
+
this.startAndRegisterOtelSpan({
|
|
103
|
+
runId,
|
|
104
|
+
parentRunId,
|
|
105
|
+
runName: action.tool,
|
|
106
|
+
attributes: {
|
|
107
|
+
input: action
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
} catch (e) {
|
|
111
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async handleAgentEnd(action, runId, parentRunId) {
|
|
115
|
+
try {
|
|
116
|
+
this.logger.debug(`Agent finish with ID: ${runId}`);
|
|
117
|
+
this.handleOtelSpanEnd({
|
|
118
|
+
runId,
|
|
119
|
+
attributes: { output: action }
|
|
120
|
+
});
|
|
121
|
+
} catch (e) {
|
|
122
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async handleChainError(err, runId, parentRunId) {
|
|
126
|
+
try {
|
|
127
|
+
this.logger.debug(`Chain error: ${err} with ID: ${runId}`);
|
|
128
|
+
const azureRefusalError = this.parseAzureRefusalError(err);
|
|
129
|
+
this.handleOtelSpanEnd({
|
|
130
|
+
runId,
|
|
131
|
+
attributes: {
|
|
132
|
+
level: "ERROR",
|
|
133
|
+
statusMessage: err.toString() + azureRefusalError
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
} catch (e) {
|
|
137
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async handleGenerationStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, name) {
|
|
141
|
+
var _a, _b;
|
|
142
|
+
this.logger.debug(
|
|
143
|
+
`Generation start with ID: ${runId} and parentRunId ${parentRunId}`
|
|
144
|
+
);
|
|
145
|
+
const runName = (_b = name != null ? name : (_a = llm.id.at(-1)) == null ? void 0 : _a.toString()) != null ? _b : "Langchain Generation";
|
|
146
|
+
const modelParameters = {};
|
|
147
|
+
const invocationParams = extraParams == null ? void 0 : extraParams["invocation_params"];
|
|
148
|
+
for (const [key, value] of Object.entries({
|
|
149
|
+
temperature: invocationParams == null ? void 0 : invocationParams.temperature,
|
|
150
|
+
max_tokens: invocationParams == null ? void 0 : invocationParams.max_tokens,
|
|
151
|
+
top_p: invocationParams == null ? void 0 : invocationParams.top_p,
|
|
152
|
+
frequency_penalty: invocationParams == null ? void 0 : invocationParams.frequency_penalty,
|
|
153
|
+
presence_penalty: invocationParams == null ? void 0 : invocationParams.presence_penalty,
|
|
154
|
+
request_timeout: invocationParams == null ? void 0 : invocationParams.request_timeout
|
|
155
|
+
})) {
|
|
156
|
+
if (value !== void 0 && value !== null) {
|
|
157
|
+
modelParameters[key] = value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
let extractedModelName;
|
|
161
|
+
if (extraParams) {
|
|
162
|
+
const invocationParamsModelName = extraParams.invocation_params.model;
|
|
163
|
+
const metadataModelName = metadata && "ls_model_name" in metadata ? metadata["ls_model_name"] : void 0;
|
|
164
|
+
extractedModelName = invocationParamsModelName != null ? invocationParamsModelName : metadataModelName;
|
|
165
|
+
}
|
|
166
|
+
const registeredPrompt = this.promptToParentRunMap.get(
|
|
167
|
+
parentRunId != null ? parentRunId : "root"
|
|
168
|
+
);
|
|
169
|
+
if (registeredPrompt && parentRunId) {
|
|
170
|
+
this.deregisterLangfusePrompt(parentRunId);
|
|
171
|
+
}
|
|
172
|
+
this.startAndRegisterOtelSpan({
|
|
173
|
+
type: "generation",
|
|
174
|
+
runId,
|
|
175
|
+
parentRunId,
|
|
176
|
+
metadata,
|
|
177
|
+
tags,
|
|
178
|
+
runName,
|
|
179
|
+
attributes: {
|
|
180
|
+
input: messages,
|
|
181
|
+
model: extractedModelName,
|
|
182
|
+
modelParameters,
|
|
183
|
+
prompt: registeredPrompt
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, name) {
|
|
188
|
+
try {
|
|
189
|
+
this.logger.debug(`Chat model start with ID: ${runId}`);
|
|
190
|
+
const prompts = messages.flatMap(
|
|
191
|
+
(message) => message.map((m) => this.extractChatMessageContent(m))
|
|
192
|
+
);
|
|
193
|
+
this.handleGenerationStart(
|
|
194
|
+
llm,
|
|
195
|
+
prompts,
|
|
196
|
+
runId,
|
|
197
|
+
parentRunId,
|
|
198
|
+
extraParams,
|
|
199
|
+
tags,
|
|
200
|
+
metadata,
|
|
201
|
+
name
|
|
202
|
+
);
|
|
203
|
+
} catch (e) {
|
|
204
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async handleChainEnd(outputs, runId, parentRunId) {
|
|
208
|
+
try {
|
|
209
|
+
this.logger.debug(`Chain end with ID: ${runId}`);
|
|
210
|
+
let finalOutput = outputs;
|
|
211
|
+
if (typeof outputs === "object" && "output" in outputs && typeof outputs["output"] === "string") {
|
|
212
|
+
finalOutput = outputs["output"];
|
|
213
|
+
} else if (typeof outputs === "object" && "messages" in outputs && Array.isArray(outputs["messages"]) && outputs["messages"].every((m) => m instanceof import_messages.BaseMessage)) {
|
|
214
|
+
finalOutput = {
|
|
215
|
+
messages: outputs.messages.map(
|
|
216
|
+
(message) => this.extractChatMessageContent(message)
|
|
217
|
+
)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
this.handleOtelSpanEnd({
|
|
221
|
+
runId,
|
|
222
|
+
attributes: {
|
|
223
|
+
output: finalOutput
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
this.deregisterLangfusePrompt(runId);
|
|
227
|
+
} catch (e) {
|
|
228
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, name) {
|
|
232
|
+
try {
|
|
233
|
+
this.logger.debug(`LLM start with ID: ${runId}`);
|
|
234
|
+
this.handleGenerationStart(
|
|
235
|
+
llm,
|
|
236
|
+
prompts,
|
|
237
|
+
runId,
|
|
238
|
+
parentRunId,
|
|
239
|
+
extraParams,
|
|
240
|
+
tags,
|
|
241
|
+
metadata,
|
|
242
|
+
name
|
|
243
|
+
);
|
|
244
|
+
} catch (e) {
|
|
245
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async handleToolStart(tool, input, runId, parentRunId, tags, metadata, name) {
|
|
249
|
+
var _a, _b;
|
|
250
|
+
try {
|
|
251
|
+
this.logger.debug(`Tool start with ID: ${runId}`);
|
|
252
|
+
this.startAndRegisterOtelSpan({
|
|
253
|
+
runId,
|
|
254
|
+
parentRunId,
|
|
255
|
+
runName: (_b = name != null ? name : (_a = tool.id.at(-1)) == null ? void 0 : _a.toString()) != null ? _b : "Tool execution",
|
|
256
|
+
attributes: {
|
|
257
|
+
input
|
|
258
|
+
},
|
|
259
|
+
metadata,
|
|
260
|
+
tags
|
|
261
|
+
});
|
|
262
|
+
} catch (e) {
|
|
263
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
|
|
267
|
+
var _a, _b;
|
|
268
|
+
try {
|
|
269
|
+
this.logger.debug(`Retriever start with ID: ${runId}`);
|
|
270
|
+
this.startAndRegisterOtelSpan({
|
|
271
|
+
runId,
|
|
272
|
+
parentRunId,
|
|
273
|
+
runName: (_b = name != null ? name : (_a = retriever.id.at(-1)) == null ? void 0 : _a.toString()) != null ? _b : "Retriever",
|
|
274
|
+
attributes: {
|
|
275
|
+
input: query
|
|
276
|
+
},
|
|
277
|
+
tags,
|
|
278
|
+
metadata
|
|
279
|
+
});
|
|
280
|
+
} catch (e) {
|
|
281
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async handleRetrieverEnd(documents, runId, parentRunId) {
|
|
285
|
+
try {
|
|
286
|
+
this.logger.debug(`Retriever end with ID: ${runId}`);
|
|
287
|
+
this.handleOtelSpanEnd({
|
|
288
|
+
runId,
|
|
289
|
+
attributes: {
|
|
290
|
+
output: documents
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
} catch (e) {
|
|
294
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
async handleRetrieverError(err, runId, parentRunId) {
|
|
298
|
+
try {
|
|
299
|
+
this.logger.debug(`Retriever error: ${err} with ID: ${runId}`);
|
|
300
|
+
this.handleOtelSpanEnd({
|
|
301
|
+
runId,
|
|
302
|
+
attributes: {
|
|
303
|
+
level: "ERROR",
|
|
304
|
+
statusMessage: err.toString()
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
} catch (e) {
|
|
308
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async handleToolEnd(output, runId, parentRunId) {
|
|
312
|
+
try {
|
|
313
|
+
this.logger.debug(`Tool end with ID: ${runId}`);
|
|
314
|
+
this.handleOtelSpanEnd({
|
|
315
|
+
runId,
|
|
316
|
+
attributes: { output }
|
|
317
|
+
});
|
|
318
|
+
} catch (e) {
|
|
319
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async handleToolError(err, runId, parentRunId) {
|
|
323
|
+
try {
|
|
324
|
+
this.logger.debug(`Tool error ${err} with ID: ${runId}`);
|
|
325
|
+
this.handleOtelSpanEnd({
|
|
326
|
+
runId,
|
|
327
|
+
attributes: {
|
|
328
|
+
level: "ERROR",
|
|
329
|
+
statusMessage: err.toString()
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
} catch (e) {
|
|
333
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async handleLLMEnd(output, runId, parentRunId) {
|
|
337
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
338
|
+
try {
|
|
339
|
+
this.logger.debug(`LLM end with ID: ${runId}`);
|
|
340
|
+
const lastResponse = output.generations[output.generations.length - 1][output.generations[output.generations.length - 1].length - 1];
|
|
341
|
+
const llmUsage = (_b = this.extractUsageMetadata(lastResponse)) != null ? _b : (_a = output.llmOutput) == null ? void 0 : _a["tokenUsage"];
|
|
342
|
+
const modelName = this.extractModelNameFromMetadata(lastResponse);
|
|
343
|
+
const usageDetails = {
|
|
344
|
+
input: (_c = llmUsage == null ? void 0 : llmUsage.input_tokens) != null ? _c : "promptTokens" in llmUsage ? llmUsage == null ? void 0 : llmUsage.promptTokens : void 0,
|
|
345
|
+
output: (_d = llmUsage == null ? void 0 : llmUsage.output_tokens) != null ? _d : "completionTokens" in llmUsage ? llmUsage == null ? void 0 : llmUsage.completionTokens : void 0,
|
|
346
|
+
total: (_e = llmUsage == null ? void 0 : llmUsage.total_tokens) != null ? _e : "totalTokens" in llmUsage ? llmUsage == null ? void 0 : llmUsage.totalTokens : void 0
|
|
347
|
+
};
|
|
348
|
+
if (llmUsage && "input_token_details" in llmUsage) {
|
|
349
|
+
for (const [key, val] of Object.entries(
|
|
350
|
+
(_f = llmUsage["input_token_details"]) != null ? _f : {}
|
|
351
|
+
)) {
|
|
352
|
+
usageDetails[`input_${key}`] = val;
|
|
353
|
+
if ("input" in usageDetails && typeof val === "number") {
|
|
354
|
+
usageDetails["input"] = Math.max(0, usageDetails["input"] - val);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (llmUsage && "output_token_details" in llmUsage) {
|
|
359
|
+
for (const [key, val] of Object.entries(
|
|
360
|
+
(_g = llmUsage["output_token_details"]) != null ? _g : {}
|
|
361
|
+
)) {
|
|
362
|
+
usageDetails[`output_${key}`] = val;
|
|
363
|
+
if ("output" in usageDetails && typeof val === "number") {
|
|
364
|
+
usageDetails["output"] = Math.max(0, usageDetails["output"] - val);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const extractedOutput = "message" in lastResponse ? this.extractChatMessageContent(
|
|
369
|
+
lastResponse["message"]
|
|
370
|
+
) : lastResponse.text;
|
|
371
|
+
this.handleOtelSpanEnd({
|
|
372
|
+
runId,
|
|
373
|
+
type: "generation",
|
|
374
|
+
attributes: {
|
|
375
|
+
model: modelName,
|
|
376
|
+
output: extractedOutput,
|
|
377
|
+
completionStartTime: runId in this.completionStartTimes ? this.completionStartTimes[runId] : void 0,
|
|
378
|
+
usageDetails
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
if (runId in this.completionStartTimes) {
|
|
382
|
+
delete this.completionStartTimes[runId];
|
|
383
|
+
}
|
|
384
|
+
} catch (e) {
|
|
385
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async handleLLMError(err, runId, parentRunId) {
|
|
389
|
+
try {
|
|
390
|
+
this.logger.debug(`LLM error ${err} with ID: ${runId}`);
|
|
391
|
+
const azureRefusalError = this.parseAzureRefusalError(err);
|
|
392
|
+
this.handleOtelSpanEnd({
|
|
393
|
+
runId,
|
|
394
|
+
attributes: {
|
|
395
|
+
level: "ERROR",
|
|
396
|
+
statusMessage: err.toString() + azureRefusalError
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
} catch (e) {
|
|
400
|
+
this.logger.debug(e instanceof Error ? e.message : String(e));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
registerLangfusePrompt(parentRunId, metadata) {
|
|
404
|
+
if (metadata && "langfusePrompt" in metadata && parentRunId) {
|
|
405
|
+
this.promptToParentRunMap.set(
|
|
406
|
+
parentRunId,
|
|
407
|
+
metadata.langfusePrompt
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
deregisterLangfusePrompt(runId) {
|
|
412
|
+
this.promptToParentRunMap.delete(runId);
|
|
413
|
+
}
|
|
414
|
+
startAndRegisterOtelSpan(params) {
|
|
415
|
+
var _a, _b;
|
|
416
|
+
const { type, runName, runId, parentRunId, attributes, metadata, tags } = params;
|
|
417
|
+
const observation = type === "generation" ? (0, import_tracing.startObservation)(
|
|
418
|
+
runName,
|
|
419
|
+
{
|
|
420
|
+
version: this.version,
|
|
421
|
+
metadata: this.joinTagsAndMetaData(tags, metadata),
|
|
422
|
+
level: tags && tags.includes(LANGSMITH_HIDDEN_TAG) ? "DEBUG" : void 0,
|
|
423
|
+
...attributes
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
asType: "generation",
|
|
427
|
+
parentSpanContext: parentRunId ? (_a = this.runMap.get(parentRunId)) == null ? void 0 : _a.otelSpan.spanContext() : void 0
|
|
428
|
+
}
|
|
429
|
+
) : (0, import_tracing.startObservation)(
|
|
430
|
+
runName,
|
|
431
|
+
{
|
|
432
|
+
version: this.version,
|
|
433
|
+
metadata: this.joinTagsAndMetaData(tags, metadata),
|
|
434
|
+
level: tags && tags.includes(LANGSMITH_HIDDEN_TAG) ? "DEBUG" : void 0,
|
|
435
|
+
...attributes
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
parentSpanContext: parentRunId ? (_b = this.runMap.get(parentRunId)) == null ? void 0 : _b.otelSpan.spanContext() : void 0
|
|
439
|
+
}
|
|
440
|
+
);
|
|
441
|
+
this.runMap.set(runId, observation);
|
|
442
|
+
return observation;
|
|
443
|
+
}
|
|
444
|
+
handleOtelSpanEnd(params) {
|
|
445
|
+
const { runId, attributes = {} } = params;
|
|
446
|
+
const span = this.runMap.get(runId);
|
|
447
|
+
if (!span) {
|
|
448
|
+
this.logger.warn("Span not found in runMap. Skipping operation");
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
span.update(attributes).end();
|
|
452
|
+
this.last_trace_id = span.traceId;
|
|
453
|
+
this.runMap.delete(runId);
|
|
454
|
+
}
|
|
455
|
+
parseAzureRefusalError(err) {
|
|
456
|
+
let azureRefusalError = "";
|
|
457
|
+
if (typeof err == "object" && "error" in err) {
|
|
458
|
+
try {
|
|
459
|
+
azureRefusalError = "\n\nError details:\n" + JSON.stringify(err["error"], null, 2);
|
|
460
|
+
} catch {
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return azureRefusalError;
|
|
464
|
+
}
|
|
465
|
+
joinTagsAndMetaData(tags, metadata1, metadata2) {
|
|
466
|
+
const finalDict = {};
|
|
467
|
+
if (tags && tags.length > 0) {
|
|
468
|
+
finalDict.tags = tags;
|
|
469
|
+
}
|
|
470
|
+
if (metadata1) {
|
|
471
|
+
Object.assign(finalDict, metadata1);
|
|
472
|
+
}
|
|
473
|
+
if (metadata2) {
|
|
474
|
+
Object.assign(finalDict, metadata2);
|
|
475
|
+
}
|
|
476
|
+
return this.stripLangfuseKeysFromMetadata(finalDict);
|
|
477
|
+
}
|
|
478
|
+
stripLangfuseKeysFromMetadata(metadata) {
|
|
479
|
+
if (!metadata) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const langfuseKeys = [
|
|
483
|
+
"langfusePrompt",
|
|
484
|
+
"langfuseUserId",
|
|
485
|
+
"langfuseSessionId"
|
|
486
|
+
];
|
|
487
|
+
return Object.fromEntries(
|
|
488
|
+
Object.entries(metadata).filter(
|
|
489
|
+
([key, _]) => !langfuseKeys.includes(key)
|
|
490
|
+
)
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
/** Not all models supports tokenUsage in llmOutput, can use AIMessage.usage_metadata instead */
|
|
494
|
+
extractUsageMetadata(generation) {
|
|
495
|
+
try {
|
|
496
|
+
const usageMetadata = "message" in generation && (generation["message"] instanceof import_messages.AIMessage || generation["message"] instanceof import_messages.AIMessageChunk) ? generation["message"].usage_metadata : void 0;
|
|
497
|
+
return usageMetadata;
|
|
498
|
+
} catch (err) {
|
|
499
|
+
this.logger.debug(`Error extracting usage metadata: ${err}`);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
extractModelNameFromMetadata(generation) {
|
|
504
|
+
try {
|
|
505
|
+
return "message" in generation && (generation["message"] instanceof import_messages.AIMessage || generation["message"] instanceof import_messages.AIMessageChunk) ? generation["message"].response_metadata.model_name : void 0;
|
|
506
|
+
} catch {
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
extractChatMessageContent(message) {
|
|
510
|
+
var _a, _b;
|
|
511
|
+
let response = void 0;
|
|
512
|
+
if (message.getType() === "human") {
|
|
513
|
+
response = { content: message.content, role: "user" };
|
|
514
|
+
} else if (message.getType() === "generic") {
|
|
515
|
+
response = {
|
|
516
|
+
content: message.content,
|
|
517
|
+
role: "human"
|
|
518
|
+
};
|
|
519
|
+
} else if (message.getType() === "ai") {
|
|
520
|
+
response = { content: message.content, role: "assistant" };
|
|
521
|
+
if ("tool_calls" in message && Array.isArray(message.tool_calls) && ((_b = (_a = message.tool_calls) == null ? void 0 : _a.length) != null ? _b : 0) > 0) {
|
|
522
|
+
response["tool_calls"] = message["tool_calls"];
|
|
523
|
+
}
|
|
524
|
+
if ("additional_kwargs" in message && "tool_calls" in message["additional_kwargs"]) {
|
|
525
|
+
response["tool_calls"] = message["additional_kwargs"]["tool_calls"];
|
|
526
|
+
}
|
|
527
|
+
} else if (message.getType() === "system") {
|
|
528
|
+
response = { content: message.content, role: "system" };
|
|
529
|
+
} else if (message.getType() === "function") {
|
|
530
|
+
response = {
|
|
531
|
+
content: message.content,
|
|
532
|
+
additional_kwargs: message.additional_kwargs,
|
|
533
|
+
role: message.name
|
|
534
|
+
};
|
|
535
|
+
} else if (message.getType() === "tool") {
|
|
536
|
+
response = {
|
|
537
|
+
content: message.content,
|
|
538
|
+
additional_kwargs: message.additional_kwargs,
|
|
539
|
+
role: message.name
|
|
540
|
+
};
|
|
541
|
+
} else if (!message.name) {
|
|
542
|
+
response = { content: message.content };
|
|
543
|
+
} else {
|
|
544
|
+
response = {
|
|
545
|
+
role: message.name,
|
|
546
|
+
content: message.content
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
if ((message.additional_kwargs.function_call || message.additional_kwargs.tool_calls) && response["tool_calls"] === void 0) {
|
|
550
|
+
return { ...response, additional_kwargs: message.additional_kwargs };
|
|
551
|
+
}
|
|
552
|
+
return response;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
556
|
+
0 && (module.exports = {
|
|
557
|
+
CallbackHandler
|
|
558
|
+
});
|
|
559
|
+
//# sourceMappingURL=index.cjs.map
|