@visibe.ai/node 0.1.20 → 0.1.22
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/cjs/index.js +17 -4
- package/dist/cjs/integrations/langchain.js +125 -2
- package/dist/cjs/integrations/langgraph.js +2 -0
- package/dist/esm/index.js +17 -4
- package/dist/esm/integrations/langchain.js +124 -2
- package/dist/esm/integrations/langgraph.js +2 -0
- package/dist/types/integrations/langchain.d.ts +4 -0
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -190,12 +190,25 @@ async function patchFramework(framework, client) {
|
|
|
190
190
|
}
|
|
191
191
|
case 'langchain': {
|
|
192
192
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
193
|
-
const { patchRunnableSequence } = await Promise.resolve().then(() => __importStar(require('./integrations/langchain')));
|
|
193
|
+
const { patchRunnableSequence, patchAgentExecutor } = await Promise.resolve().then(() => __importStar(require('./integrations/langchain')));
|
|
194
194
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
195
195
|
const lcModule = await Promise.resolve().then(() => __importStar(require('@langchain/core/runnables')));
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
const r1 = patchRunnableSequence(lcModule, client);
|
|
197
|
+
// Also patch AgentExecutor (langchain/agents) if installed — AgentExecutor is NOT a
|
|
198
|
+
// RunnableSequence so without this patch each agent loop iteration creates a separate trace.
|
|
199
|
+
let r2;
|
|
200
|
+
try {
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
202
|
+
const agentsModule = await Promise.resolve().then(() => __importStar(require('langchain/agents')));
|
|
203
|
+
r2 = patchAgentExecutor(agentsModule, client);
|
|
204
|
+
}
|
|
205
|
+
catch { /* langchain package not installed — skip */ }
|
|
206
|
+
_lcRestore = () => {
|
|
207
|
+
if (typeof r1 === 'function')
|
|
208
|
+
r1();
|
|
209
|
+
if (typeof r2 === 'function')
|
|
210
|
+
r2();
|
|
211
|
+
};
|
|
199
212
|
break;
|
|
200
213
|
}
|
|
201
214
|
case 'vercel_ai': {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LangChainCallback = exports.LANGGRAPH_INTERNAL_NODES = exports.activeLangChainStorage = void 0;
|
|
4
4
|
exports.patchRunnableSequence = patchRunnableSequence;
|
|
5
|
+
exports.patchAgentExecutor = patchAgentExecutor;
|
|
5
6
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
6
7
|
const node_crypto_1 = require("node:crypto");
|
|
7
8
|
const utils_1 = require("../utils");
|
|
@@ -31,6 +32,16 @@ class LangChainCallback {
|
|
|
31
32
|
nextSpanId() {
|
|
32
33
|
return `step_${++this.stepCounter}`;
|
|
33
34
|
}
|
|
35
|
+
// Walk up the run parent chain to find the nearest agent name.
|
|
36
|
+
// Falls back to this.agentName if no ancestor has an associated agent.
|
|
37
|
+
_findAgentName(runId) {
|
|
38
|
+
if (!runId)
|
|
39
|
+
return this.agentName;
|
|
40
|
+
const name = this.runIdToAgentName.get(runId);
|
|
41
|
+
if (name)
|
|
42
|
+
return name;
|
|
43
|
+
return this._findAgentName(this.runIdToParent.get(runId));
|
|
44
|
+
}
|
|
34
45
|
constructor(options) {
|
|
35
46
|
// Required by @langchain/core v1+ for proper callback registration.
|
|
36
47
|
// Without `name`, ensureHandler() wraps via fromMethods() which drops prototype methods.
|
|
@@ -41,6 +52,11 @@ class LangChainCallback {
|
|
|
41
52
|
this.raiseError = false;
|
|
42
53
|
// Maps LangChain runId → our spanId so we can set parent_span_id.
|
|
43
54
|
this.runIdToSpanId = new Map();
|
|
55
|
+
// Tracks parent run IDs so we can walk up the chain hierarchy.
|
|
56
|
+
this.runIdToParent = new Map();
|
|
57
|
+
// Maps runId → agent name for chains that emitted an agent_start span.
|
|
58
|
+
// Used by _findAgentName() to resolve the correct agent for llm_call / tool_call spans.
|
|
59
|
+
this.runIdToAgentName = new Map();
|
|
44
60
|
// Pending LLM calls: runId → { startMs, model, inputText }
|
|
45
61
|
this.pendingLLMCalls = new Map();
|
|
46
62
|
this.pendingToolCalls = new Map();
|
|
@@ -103,7 +119,7 @@ class LangChainCallback {
|
|
|
103
119
|
const span = this.visibe.buildLLMSpan({
|
|
104
120
|
spanId,
|
|
105
121
|
parentSpanId,
|
|
106
|
-
agentName: this.
|
|
122
|
+
agentName: this._findAgentName(parentRunId),
|
|
107
123
|
model,
|
|
108
124
|
status: 'success',
|
|
109
125
|
inputTokens,
|
|
@@ -146,7 +162,7 @@ class LangChainCallback {
|
|
|
146
162
|
spanId,
|
|
147
163
|
parentSpanId,
|
|
148
164
|
toolName: pending?.toolName ?? 'tool',
|
|
149
|
-
agentName: this.
|
|
165
|
+
agentName: this._findAgentName(parentRunId),
|
|
150
166
|
status: 'success',
|
|
151
167
|
durationMs: pending ? Date.now() - pending.startMs : 0,
|
|
152
168
|
inputText: pending?.inputText ?? '',
|
|
@@ -175,12 +191,16 @@ class LangChainCallback {
|
|
|
175
191
|
if (!this.runIdToSpanId.has(runId)) {
|
|
176
192
|
this.runIdToSpanId.set(runId, this.nextSpanId());
|
|
177
193
|
}
|
|
194
|
+
if (_parentRunId) {
|
|
195
|
+
this.runIdToParent.set(runId, _parentRunId);
|
|
196
|
+
}
|
|
178
197
|
// Emit agent_start for the root chain so LLM spans have a real parent and
|
|
179
198
|
// the agents breakdown is populated. Subclasses that manage their own
|
|
180
199
|
// agent_start spans (LangGraphCallback) set _emitRootAgentStart = false.
|
|
181
200
|
if (this._emitRootAgentStart && !_parentRunId) {
|
|
182
201
|
const spanId = this.runIdToSpanId.get(runId);
|
|
183
202
|
const agentName = _name ?? _chain?.name ?? this.agentName;
|
|
203
|
+
this.runIdToAgentName.set(runId, agentName);
|
|
184
204
|
this.visibe.batcher.add(this.traceId, this.visibe.buildAgentStartSpan({ spanId, agentName }));
|
|
185
205
|
}
|
|
186
206
|
}
|
|
@@ -293,6 +313,109 @@ function patchRunnableSequence(lcModule, visibe) {
|
|
|
293
313
|
};
|
|
294
314
|
}
|
|
295
315
|
// ---------------------------------------------------------------------------
|
|
316
|
+
// patchAgentExecutor — patches AgentExecutor from `langchain/agents` so the
|
|
317
|
+
// entire multi-step agent loop is captured as ONE trace.
|
|
318
|
+
//
|
|
319
|
+
// AgentExecutor is NOT a RunnableSequence — it extends Runnable directly and
|
|
320
|
+
// calls the inner agent RunnableSequence in a loop. Without this patch each
|
|
321
|
+
// iteration fires patchRunnableSequence and creates a separate trace.
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
324
|
+
function patchAgentExecutor(agentsModule, visibe) {
|
|
325
|
+
const AgentExecutor = agentsModule?.AgentExecutor;
|
|
326
|
+
if (!AgentExecutor)
|
|
327
|
+
return () => { };
|
|
328
|
+
const originalInvoke = AgentExecutor.prototype.invoke;
|
|
329
|
+
const originalStream = AgentExecutor.prototype.stream;
|
|
330
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
331
|
+
AgentExecutor.prototype.invoke = async function (input, config) {
|
|
332
|
+
if (exports.activeLangChainStorage.getStore() !== undefined) {
|
|
333
|
+
return originalInvoke.call(this, input, config);
|
|
334
|
+
}
|
|
335
|
+
const traceId = (0, node_crypto_1.randomUUID)();
|
|
336
|
+
const startedAt = new Date().toISOString();
|
|
337
|
+
const startMs = Date.now();
|
|
338
|
+
const agentName = this.name ?? 'langchain';
|
|
339
|
+
await visibe.apiClient.createTrace({
|
|
340
|
+
trace_id: traceId,
|
|
341
|
+
name: agentName,
|
|
342
|
+
framework: 'langchain',
|
|
343
|
+
started_at: startedAt,
|
|
344
|
+
...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
|
|
345
|
+
});
|
|
346
|
+
const cb = new LangChainCallback({ visibe, traceId, agentName });
|
|
347
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
348
|
+
let result;
|
|
349
|
+
let status = 'completed';
|
|
350
|
+
try {
|
|
351
|
+
result = await exports.activeLangChainStorage.run(cb, () => originalInvoke.call(this, input, _mergeCallbacks(config, cb)));
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
status = 'failed';
|
|
355
|
+
throw err;
|
|
356
|
+
}
|
|
357
|
+
finally {
|
|
358
|
+
visibe.batcher.flush();
|
|
359
|
+
await visibe.apiClient.completeTrace(traceId, {
|
|
360
|
+
status,
|
|
361
|
+
ended_at: new Date().toISOString(),
|
|
362
|
+
duration_ms: Date.now() - startMs,
|
|
363
|
+
llm_call_count: cb.llmCallCount,
|
|
364
|
+
total_cost: cb.totalCost,
|
|
365
|
+
total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
|
|
366
|
+
total_input_tokens: cb.totalInputTokens,
|
|
367
|
+
total_output_tokens: cb.totalOutputTokens,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
};
|
|
372
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
373
|
+
AgentExecutor.prototype.stream = async function* (input, config) {
|
|
374
|
+
if (exports.activeLangChainStorage.getStore() !== undefined) {
|
|
375
|
+
yield* (await originalStream.call(this, input, config));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const traceId = (0, node_crypto_1.randomUUID)();
|
|
379
|
+
const startedAt = new Date().toISOString();
|
|
380
|
+
const startMs = Date.now();
|
|
381
|
+
const agentName = this.name ?? 'langchain';
|
|
382
|
+
await visibe.apiClient.createTrace({
|
|
383
|
+
trace_id: traceId,
|
|
384
|
+
name: agentName,
|
|
385
|
+
framework: 'langchain',
|
|
386
|
+
started_at: startedAt,
|
|
387
|
+
...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
|
|
388
|
+
});
|
|
389
|
+
const cb = new LangChainCallback({ visibe, traceId, agentName });
|
|
390
|
+
let status = 'completed';
|
|
391
|
+
try {
|
|
392
|
+
const gen = await exports.activeLangChainStorage.run(cb, () => originalStream.call(this, input, _mergeCallbacks(config, cb)));
|
|
393
|
+
yield* gen;
|
|
394
|
+
}
|
|
395
|
+
catch (err) {
|
|
396
|
+
status = 'failed';
|
|
397
|
+
throw err;
|
|
398
|
+
}
|
|
399
|
+
finally {
|
|
400
|
+
visibe.batcher.flush();
|
|
401
|
+
await visibe.apiClient.completeTrace(traceId, {
|
|
402
|
+
status,
|
|
403
|
+
ended_at: new Date().toISOString(),
|
|
404
|
+
duration_ms: Date.now() - startMs,
|
|
405
|
+
llm_call_count: cb.llmCallCount,
|
|
406
|
+
total_cost: cb.totalCost,
|
|
407
|
+
total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
|
|
408
|
+
total_input_tokens: cb.totalInputTokens,
|
|
409
|
+
total_output_tokens: cb.totalOutputTokens,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
return () => {
|
|
414
|
+
AgentExecutor.prototype.invoke = originalInvoke;
|
|
415
|
+
AgentExecutor.prototype.stream = originalStream;
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
// ---------------------------------------------------------------------------
|
|
296
419
|
// Private helpers
|
|
297
420
|
// ---------------------------------------------------------------------------
|
|
298
421
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -31,6 +31,8 @@ class LangGraphCallback extends langchain_1.LangChainCallback {
|
|
|
31
31
|
// Use the spanId already assigned by super for this runId.
|
|
32
32
|
const spanId = this.runIdToSpanId.get(runId) ?? this.nextSpanId();
|
|
33
33
|
this.runIdToSpanId.set(runId, spanId);
|
|
34
|
+
// Register agent name so _findAgentName() resolves it for child llm_call / tool_call spans.
|
|
35
|
+
this.runIdToAgentName.set(runId, nodeName);
|
|
34
36
|
this.visibe.batcher.add(this.traceId, this.visibe.buildAgentStartSpan({
|
|
35
37
|
spanId,
|
|
36
38
|
agentName: nodeName,
|
package/dist/esm/index.js
CHANGED
|
@@ -151,12 +151,25 @@ async function patchFramework(framework, client) {
|
|
|
151
151
|
}
|
|
152
152
|
case 'langchain': {
|
|
153
153
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
154
|
-
const { patchRunnableSequence } = await import('./integrations/langchain.js');
|
|
154
|
+
const { patchRunnableSequence, patchAgentExecutor } = await import('./integrations/langchain.js');
|
|
155
155
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
156
156
|
const lcModule = await import('@langchain/core/runnables');
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
const r1 = patchRunnableSequence(lcModule, client);
|
|
158
|
+
// Also patch AgentExecutor (langchain/agents) if installed — AgentExecutor is NOT a
|
|
159
|
+
// RunnableSequence so without this patch each agent loop iteration creates a separate trace.
|
|
160
|
+
let r2;
|
|
161
|
+
try {
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
const agentsModule = await import('langchain/agents');
|
|
164
|
+
r2 = patchAgentExecutor(agentsModule, client);
|
|
165
|
+
}
|
|
166
|
+
catch { /* langchain package not installed — skip */ }
|
|
167
|
+
_lcRestore = () => {
|
|
168
|
+
if (typeof r1 === 'function')
|
|
169
|
+
r1();
|
|
170
|
+
if (typeof r2 === 'function')
|
|
171
|
+
r2();
|
|
172
|
+
};
|
|
160
173
|
break;
|
|
161
174
|
}
|
|
162
175
|
case 'vercel_ai': {
|
|
@@ -27,6 +27,16 @@ export class LangChainCallback {
|
|
|
27
27
|
nextSpanId() {
|
|
28
28
|
return `step_${++this.stepCounter}`;
|
|
29
29
|
}
|
|
30
|
+
// Walk up the run parent chain to find the nearest agent name.
|
|
31
|
+
// Falls back to this.agentName if no ancestor has an associated agent.
|
|
32
|
+
_findAgentName(runId) {
|
|
33
|
+
if (!runId)
|
|
34
|
+
return this.agentName;
|
|
35
|
+
const name = this.runIdToAgentName.get(runId);
|
|
36
|
+
if (name)
|
|
37
|
+
return name;
|
|
38
|
+
return this._findAgentName(this.runIdToParent.get(runId));
|
|
39
|
+
}
|
|
30
40
|
constructor(options) {
|
|
31
41
|
// Required by @langchain/core v1+ for proper callback registration.
|
|
32
42
|
// Without `name`, ensureHandler() wraps via fromMethods() which drops prototype methods.
|
|
@@ -37,6 +47,11 @@ export class LangChainCallback {
|
|
|
37
47
|
this.raiseError = false;
|
|
38
48
|
// Maps LangChain runId → our spanId so we can set parent_span_id.
|
|
39
49
|
this.runIdToSpanId = new Map();
|
|
50
|
+
// Tracks parent run IDs so we can walk up the chain hierarchy.
|
|
51
|
+
this.runIdToParent = new Map();
|
|
52
|
+
// Maps runId → agent name for chains that emitted an agent_start span.
|
|
53
|
+
// Used by _findAgentName() to resolve the correct agent for llm_call / tool_call spans.
|
|
54
|
+
this.runIdToAgentName = new Map();
|
|
40
55
|
// Pending LLM calls: runId → { startMs, model, inputText }
|
|
41
56
|
this.pendingLLMCalls = new Map();
|
|
42
57
|
this.pendingToolCalls = new Map();
|
|
@@ -99,7 +114,7 @@ export class LangChainCallback {
|
|
|
99
114
|
const span = this.visibe.buildLLMSpan({
|
|
100
115
|
spanId,
|
|
101
116
|
parentSpanId,
|
|
102
|
-
agentName: this.
|
|
117
|
+
agentName: this._findAgentName(parentRunId),
|
|
103
118
|
model,
|
|
104
119
|
status: 'success',
|
|
105
120
|
inputTokens,
|
|
@@ -142,7 +157,7 @@ export class LangChainCallback {
|
|
|
142
157
|
spanId,
|
|
143
158
|
parentSpanId,
|
|
144
159
|
toolName: pending?.toolName ?? 'tool',
|
|
145
|
-
agentName: this.
|
|
160
|
+
agentName: this._findAgentName(parentRunId),
|
|
146
161
|
status: 'success',
|
|
147
162
|
durationMs: pending ? Date.now() - pending.startMs : 0,
|
|
148
163
|
inputText: pending?.inputText ?? '',
|
|
@@ -171,12 +186,16 @@ export class LangChainCallback {
|
|
|
171
186
|
if (!this.runIdToSpanId.has(runId)) {
|
|
172
187
|
this.runIdToSpanId.set(runId, this.nextSpanId());
|
|
173
188
|
}
|
|
189
|
+
if (_parentRunId) {
|
|
190
|
+
this.runIdToParent.set(runId, _parentRunId);
|
|
191
|
+
}
|
|
174
192
|
// Emit agent_start for the root chain so LLM spans have a real parent and
|
|
175
193
|
// the agents breakdown is populated. Subclasses that manage their own
|
|
176
194
|
// agent_start spans (LangGraphCallback) set _emitRootAgentStart = false.
|
|
177
195
|
if (this._emitRootAgentStart && !_parentRunId) {
|
|
178
196
|
const spanId = this.runIdToSpanId.get(runId);
|
|
179
197
|
const agentName = _name ?? _chain?.name ?? this.agentName;
|
|
198
|
+
this.runIdToAgentName.set(runId, agentName);
|
|
180
199
|
this.visibe.batcher.add(this.traceId, this.visibe.buildAgentStartSpan({ spanId, agentName }));
|
|
181
200
|
}
|
|
182
201
|
}
|
|
@@ -288,6 +307,109 @@ export function patchRunnableSequence(lcModule, visibe) {
|
|
|
288
307
|
};
|
|
289
308
|
}
|
|
290
309
|
// ---------------------------------------------------------------------------
|
|
310
|
+
// patchAgentExecutor — patches AgentExecutor from `langchain/agents` so the
|
|
311
|
+
// entire multi-step agent loop is captured as ONE trace.
|
|
312
|
+
//
|
|
313
|
+
// AgentExecutor is NOT a RunnableSequence — it extends Runnable directly and
|
|
314
|
+
// calls the inner agent RunnableSequence in a loop. Without this patch each
|
|
315
|
+
// iteration fires patchRunnableSequence and creates a separate trace.
|
|
316
|
+
// ---------------------------------------------------------------------------
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
318
|
+
export function patchAgentExecutor(agentsModule, visibe) {
|
|
319
|
+
const AgentExecutor = agentsModule?.AgentExecutor;
|
|
320
|
+
if (!AgentExecutor)
|
|
321
|
+
return () => { };
|
|
322
|
+
const originalInvoke = AgentExecutor.prototype.invoke;
|
|
323
|
+
const originalStream = AgentExecutor.prototype.stream;
|
|
324
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
325
|
+
AgentExecutor.prototype.invoke = async function (input, config) {
|
|
326
|
+
if (activeLangChainStorage.getStore() !== undefined) {
|
|
327
|
+
return originalInvoke.call(this, input, config);
|
|
328
|
+
}
|
|
329
|
+
const traceId = randomUUID();
|
|
330
|
+
const startedAt = new Date().toISOString();
|
|
331
|
+
const startMs = Date.now();
|
|
332
|
+
const agentName = this.name ?? 'langchain';
|
|
333
|
+
await visibe.apiClient.createTrace({
|
|
334
|
+
trace_id: traceId,
|
|
335
|
+
name: agentName,
|
|
336
|
+
framework: 'langchain',
|
|
337
|
+
started_at: startedAt,
|
|
338
|
+
...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
|
|
339
|
+
});
|
|
340
|
+
const cb = new LangChainCallback({ visibe, traceId, agentName });
|
|
341
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
342
|
+
let result;
|
|
343
|
+
let status = 'completed';
|
|
344
|
+
try {
|
|
345
|
+
result = await activeLangChainStorage.run(cb, () => originalInvoke.call(this, input, _mergeCallbacks(config, cb)));
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
status = 'failed';
|
|
349
|
+
throw err;
|
|
350
|
+
}
|
|
351
|
+
finally {
|
|
352
|
+
visibe.batcher.flush();
|
|
353
|
+
await visibe.apiClient.completeTrace(traceId, {
|
|
354
|
+
status,
|
|
355
|
+
ended_at: new Date().toISOString(),
|
|
356
|
+
duration_ms: Date.now() - startMs,
|
|
357
|
+
llm_call_count: cb.llmCallCount,
|
|
358
|
+
total_cost: cb.totalCost,
|
|
359
|
+
total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
|
|
360
|
+
total_input_tokens: cb.totalInputTokens,
|
|
361
|
+
total_output_tokens: cb.totalOutputTokens,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
return result;
|
|
365
|
+
};
|
|
366
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
367
|
+
AgentExecutor.prototype.stream = async function* (input, config) {
|
|
368
|
+
if (activeLangChainStorage.getStore() !== undefined) {
|
|
369
|
+
yield* (await originalStream.call(this, input, config));
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const traceId = randomUUID();
|
|
373
|
+
const startedAt = new Date().toISOString();
|
|
374
|
+
const startMs = Date.now();
|
|
375
|
+
const agentName = this.name ?? 'langchain';
|
|
376
|
+
await visibe.apiClient.createTrace({
|
|
377
|
+
trace_id: traceId,
|
|
378
|
+
name: agentName,
|
|
379
|
+
framework: 'langchain',
|
|
380
|
+
started_at: startedAt,
|
|
381
|
+
...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
|
|
382
|
+
});
|
|
383
|
+
const cb = new LangChainCallback({ visibe, traceId, agentName });
|
|
384
|
+
let status = 'completed';
|
|
385
|
+
try {
|
|
386
|
+
const gen = await activeLangChainStorage.run(cb, () => originalStream.call(this, input, _mergeCallbacks(config, cb)));
|
|
387
|
+
yield* gen;
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
status = 'failed';
|
|
391
|
+
throw err;
|
|
392
|
+
}
|
|
393
|
+
finally {
|
|
394
|
+
visibe.batcher.flush();
|
|
395
|
+
await visibe.apiClient.completeTrace(traceId, {
|
|
396
|
+
status,
|
|
397
|
+
ended_at: new Date().toISOString(),
|
|
398
|
+
duration_ms: Date.now() - startMs,
|
|
399
|
+
llm_call_count: cb.llmCallCount,
|
|
400
|
+
total_cost: cb.totalCost,
|
|
401
|
+
total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
|
|
402
|
+
total_input_tokens: cb.totalInputTokens,
|
|
403
|
+
total_output_tokens: cb.totalOutputTokens,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
return () => {
|
|
408
|
+
AgentExecutor.prototype.invoke = originalInvoke;
|
|
409
|
+
AgentExecutor.prototype.stream = originalStream;
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
// ---------------------------------------------------------------------------
|
|
291
413
|
// Private helpers
|
|
292
414
|
// ---------------------------------------------------------------------------
|
|
293
415
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -27,6 +27,8 @@ export class LangGraphCallback extends LangChainCallback {
|
|
|
27
27
|
// Use the spanId already assigned by super for this runId.
|
|
28
28
|
const spanId = this.runIdToSpanId.get(runId) ?? this.nextSpanId();
|
|
29
29
|
this.runIdToSpanId.set(runId, spanId);
|
|
30
|
+
// Register agent name so _findAgentName() resolves it for child llm_call / tool_call spans.
|
|
31
|
+
this.runIdToAgentName.set(runId, nodeName);
|
|
30
32
|
this.visibe.batcher.add(this.traceId, this.visibe.buildAgentStartSpan({
|
|
31
33
|
spanId,
|
|
32
34
|
agentName: nodeName,
|
|
@@ -10,6 +10,8 @@ export declare class LangChainCallback {
|
|
|
10
10
|
protected readonly traceId: string;
|
|
11
11
|
protected readonly agentName: string;
|
|
12
12
|
protected runIdToSpanId: Map<string, string>;
|
|
13
|
+
protected runIdToParent: Map<string, string>;
|
|
14
|
+
protected runIdToAgentName: Map<string, string>;
|
|
13
15
|
protected pendingLLMCalls: Map<string, {
|
|
14
16
|
startMs: number;
|
|
15
17
|
model?: string;
|
|
@@ -23,6 +25,7 @@ export declare class LangChainCallback {
|
|
|
23
25
|
protected stepCounter: number;
|
|
24
26
|
protected nextSpanId(): string;
|
|
25
27
|
protected _emitRootAgentStart: boolean;
|
|
28
|
+
protected _findAgentName(runId?: string): string;
|
|
26
29
|
totalInputTokens: number;
|
|
27
30
|
totalOutputTokens: number;
|
|
28
31
|
totalCost: number;
|
|
@@ -46,3 +49,4 @@ export declare class LangChainCallback {
|
|
|
46
49
|
_onToolSpan?: () => void;
|
|
47
50
|
}
|
|
48
51
|
export declare function patchRunnableSequence(lcModule: any, visibe: Visibe): () => void;
|
|
52
|
+
export declare function patchAgentExecutor(agentsModule: any, visibe: Visibe): () => void;
|
package/package.json
CHANGED