@visibe.ai/node 0.1.25 → 0.1.27

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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LangChainCallback = exports.LANGGRAPH_INTERNAL_NODES = exports.activeLangChainStorage = void 0;
4
4
  exports.patchRunnableSequence = patchRunnableSequence;
5
5
  exports.patchAgentExecutor = patchAgentExecutor;
6
+ exports.serializeInput = serializeInput;
6
7
  const node_async_hooks_1 = require("node:async_hooks");
7
8
  const node_crypto_1 = require("node:crypto");
8
9
  const utils_1 = require("../utils");
@@ -23,8 +24,19 @@ function extractTokenUsage(output) {
23
24
  outputTokens: usage?.completionTokens ?? usage?.output_tokens ?? 0,
24
25
  };
25
26
  }
26
- // Internal LangGraph system node names — never emit agent_start spans for these.
27
- exports.LANGGRAPH_INTERNAL_NODES = new Set(['__start__', '__end__', 'LangGraph']);
27
+ // Internal LangGraph/LangChain node names — never emit agent_start spans for these.
28
+ // Includes LangGraph system nodes and LangChain Runnable primitives that wrap
29
+ // routing functions (e.g. addConditionalEdges wraps the condition in a RunnableLambda).
30
+ exports.LANGGRAPH_INTERNAL_NODES = new Set([
31
+ '__start__',
32
+ '__end__',
33
+ 'LangGraph',
34
+ 'RunnableLambda',
35
+ 'RunnableSequence',
36
+ 'RunnableParallel',
37
+ 'RunnablePassthrough',
38
+ 'RunnableBranch',
39
+ ]);
28
40
  // ---------------------------------------------------------------------------
29
41
  // LangChainCallback
30
42
  // ---------------------------------------------------------------------------
@@ -68,6 +80,8 @@ class LangChainCallback {
68
80
  this.totalOutputTokens = 0;
69
81
  this.totalCost = 0;
70
82
  this.llmCallCount = 0;
83
+ // First model seen across all LLM calls in this trace — set on first handleLLMEnd.
84
+ this.firstModel = undefined;
71
85
  this.visibe = options.visibe;
72
86
  this.traceId = options.traceId;
73
87
  this.agentName = options.agentName;
@@ -133,6 +147,8 @@ class LangChainCallback {
133
147
  this.totalOutputTokens += outputTokens;
134
148
  this.totalCost += cost;
135
149
  this.llmCallCount++;
150
+ if (!this.firstModel)
151
+ this.firstModel = model;
136
152
  this._onLLMSpan?.(inputTokens, outputTokens, cost);
137
153
  }
138
154
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -239,6 +255,7 @@ function patchRunnableSequence(lcModule, visibe) {
239
255
  name: 'langchain',
240
256
  framework: 'langchain',
241
257
  started_at: startedAt,
258
+ prompt: serializeInput(input),
242
259
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
243
260
  });
244
261
  const cb = new LangChainCallback({ visibe, traceId, agentName: 'langchain' });
@@ -263,6 +280,7 @@ function patchRunnableSequence(lcModule, visibe) {
263
280
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
264
281
  total_input_tokens: cb.totalInputTokens,
265
282
  total_output_tokens: cb.totalOutputTokens,
283
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
266
284
  });
267
285
  }
268
286
  return result;
@@ -281,6 +299,7 @@ function patchRunnableSequence(lcModule, visibe) {
281
299
  name: 'langchain',
282
300
  framework: 'langchain',
283
301
  started_at: startedAt,
302
+ prompt: serializeInput(input),
284
303
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
285
304
  });
286
305
  const cb = new LangChainCallback({ visibe, traceId, agentName: 'langchain' });
@@ -304,6 +323,7 @@ function patchRunnableSequence(lcModule, visibe) {
304
323
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
305
324
  total_input_tokens: cb.totalInputTokens,
306
325
  total_output_tokens: cb.totalOutputTokens,
326
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
307
327
  });
308
328
  }
309
329
  };
@@ -341,6 +361,7 @@ function patchAgentExecutor(agentsModule, visibe) {
341
361
  name: agentName,
342
362
  framework: 'langchain',
343
363
  started_at: startedAt,
364
+ prompt: serializeInput(input),
344
365
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
345
366
  });
346
367
  const cb = new LangChainCallback({ visibe, traceId, agentName });
@@ -365,6 +386,7 @@ function patchAgentExecutor(agentsModule, visibe) {
365
386
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
366
387
  total_input_tokens: cb.totalInputTokens,
367
388
  total_output_tokens: cb.totalOutputTokens,
389
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
368
390
  });
369
391
  }
370
392
  return result;
@@ -384,6 +406,7 @@ function patchAgentExecutor(agentsModule, visibe) {
384
406
  name: agentName,
385
407
  framework: 'langchain',
386
408
  started_at: startedAt,
409
+ prompt: serializeInput(input),
387
410
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
388
411
  });
389
412
  const cb = new LangChainCallback({ visibe, traceId, agentName });
@@ -407,6 +430,7 @@ function patchAgentExecutor(agentsModule, visibe) {
407
430
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
408
431
  total_input_tokens: cb.totalInputTokens,
409
432
  total_output_tokens: cb.totalOutputTokens,
433
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
410
434
  });
411
435
  }
412
436
  };
@@ -425,3 +449,37 @@ function _mergeCallbacks(config, cb) {
425
449
  const existing = Array.isArray(config.callbacks) ? config.callbacks : [];
426
450
  return { ...config, callbacks: [...existing, cb] };
427
451
  }
452
+ // Serialize a graph/chain input to a prompt string for the trace header.
453
+ // Handles strings, common object shapes, and falls back to JSON.
454
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
455
+ function serializeInput(input, limit = 2000) {
456
+ if (!input)
457
+ return undefined;
458
+ let s;
459
+ if (typeof input === 'string') {
460
+ s = input;
461
+ }
462
+ else if (typeof input === 'object') {
463
+ // Try common single-field patterns first.
464
+ for (const key of ['task', 'prompt', 'input', 'query', 'question', 'text', 'content']) {
465
+ if (typeof input[key] === 'string') {
466
+ s = input[key];
467
+ break;
468
+ }
469
+ }
470
+ if (!s) {
471
+ // HumanMessage / messages array — grab the last message content.
472
+ if (Array.isArray(input.messages) && input.messages.length > 0) {
473
+ const last = input.messages[input.messages.length - 1];
474
+ s = typeof last?.content === 'string' ? last.content : JSON.stringify(last?.content ?? '');
475
+ }
476
+ else {
477
+ s = JSON.stringify(input);
478
+ }
479
+ }
480
+ }
481
+ else {
482
+ s = String(input);
483
+ }
484
+ return s.length > limit ? s.slice(0, limit) + '…' : s;
485
+ }
@@ -68,6 +68,7 @@ function patchCompiledStateGraph(lgModule, visibe) {
68
68
  name: graphName,
69
69
  framework: 'langgraph',
70
70
  started_at: startedAt,
71
+ prompt: (0, langchain_1.serializeInput)(input),
71
72
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
72
73
  });
73
74
  // Collect node names from the graph's node registry.
@@ -98,6 +99,7 @@ function patchCompiledStateGraph(lgModule, visibe) {
98
99
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
99
100
  total_input_tokens: cb.totalInputTokens,
100
101
  total_output_tokens: cb.totalOutputTokens,
102
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
101
103
  });
102
104
  }
103
105
  return result;
@@ -119,6 +121,7 @@ function patchCompiledStateGraph(lgModule, visibe) {
119
121
  name: graphName,
120
122
  framework: 'langgraph',
121
123
  started_at: startedAt,
124
+ prompt: (0, langchain_1.serializeInput)(input),
122
125
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
123
126
  });
124
127
  const nodeNames = _extractNodeNames(this);
@@ -150,6 +153,7 @@ function patchCompiledStateGraph(lgModule, visibe) {
150
153
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
151
154
  total_input_tokens: cb.totalInputTokens,
152
155
  total_output_tokens: cb.totalOutputTokens,
156
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
153
157
  });
154
158
  }
155
159
  };
@@ -18,8 +18,19 @@ function extractTokenUsage(output) {
18
18
  outputTokens: usage?.completionTokens ?? usage?.output_tokens ?? 0,
19
19
  };
20
20
  }
21
- // Internal LangGraph system node names — never emit agent_start spans for these.
22
- export const LANGGRAPH_INTERNAL_NODES = new Set(['__start__', '__end__', 'LangGraph']);
21
+ // Internal LangGraph/LangChain node names — never emit agent_start spans for these.
22
+ // Includes LangGraph system nodes and LangChain Runnable primitives that wrap
23
+ // routing functions (e.g. addConditionalEdges wraps the condition in a RunnableLambda).
24
+ export const LANGGRAPH_INTERNAL_NODES = new Set([
25
+ '__start__',
26
+ '__end__',
27
+ 'LangGraph',
28
+ 'RunnableLambda',
29
+ 'RunnableSequence',
30
+ 'RunnableParallel',
31
+ 'RunnablePassthrough',
32
+ 'RunnableBranch',
33
+ ]);
23
34
  // ---------------------------------------------------------------------------
24
35
  // LangChainCallback
25
36
  // ---------------------------------------------------------------------------
@@ -63,6 +74,8 @@ export class LangChainCallback {
63
74
  this.totalOutputTokens = 0;
64
75
  this.totalCost = 0;
65
76
  this.llmCallCount = 0;
77
+ // First model seen across all LLM calls in this trace — set on first handleLLMEnd.
78
+ this.firstModel = undefined;
66
79
  this.visibe = options.visibe;
67
80
  this.traceId = options.traceId;
68
81
  this.agentName = options.agentName;
@@ -128,6 +141,8 @@ export class LangChainCallback {
128
141
  this.totalOutputTokens += outputTokens;
129
142
  this.totalCost += cost;
130
143
  this.llmCallCount++;
144
+ if (!this.firstModel)
145
+ this.firstModel = model;
131
146
  this._onLLMSpan?.(inputTokens, outputTokens, cost);
132
147
  }
133
148
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -233,6 +248,7 @@ export function patchRunnableSequence(lcModule, visibe) {
233
248
  name: 'langchain',
234
249
  framework: 'langchain',
235
250
  started_at: startedAt,
251
+ prompt: serializeInput(input),
236
252
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
237
253
  });
238
254
  const cb = new LangChainCallback({ visibe, traceId, agentName: 'langchain' });
@@ -257,6 +273,7 @@ export function patchRunnableSequence(lcModule, visibe) {
257
273
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
258
274
  total_input_tokens: cb.totalInputTokens,
259
275
  total_output_tokens: cb.totalOutputTokens,
276
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
260
277
  });
261
278
  }
262
279
  return result;
@@ -275,6 +292,7 @@ export function patchRunnableSequence(lcModule, visibe) {
275
292
  name: 'langchain',
276
293
  framework: 'langchain',
277
294
  started_at: startedAt,
295
+ prompt: serializeInput(input),
278
296
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
279
297
  });
280
298
  const cb = new LangChainCallback({ visibe, traceId, agentName: 'langchain' });
@@ -298,6 +316,7 @@ export function patchRunnableSequence(lcModule, visibe) {
298
316
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
299
317
  total_input_tokens: cb.totalInputTokens,
300
318
  total_output_tokens: cb.totalOutputTokens,
319
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
301
320
  });
302
321
  }
303
322
  };
@@ -335,6 +354,7 @@ export function patchAgentExecutor(agentsModule, visibe) {
335
354
  name: agentName,
336
355
  framework: 'langchain',
337
356
  started_at: startedAt,
357
+ prompt: serializeInput(input),
338
358
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
339
359
  });
340
360
  const cb = new LangChainCallback({ visibe, traceId, agentName });
@@ -359,6 +379,7 @@ export function patchAgentExecutor(agentsModule, visibe) {
359
379
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
360
380
  total_input_tokens: cb.totalInputTokens,
361
381
  total_output_tokens: cb.totalOutputTokens,
382
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
362
383
  });
363
384
  }
364
385
  return result;
@@ -378,6 +399,7 @@ export function patchAgentExecutor(agentsModule, visibe) {
378
399
  name: agentName,
379
400
  framework: 'langchain',
380
401
  started_at: startedAt,
402
+ prompt: serializeInput(input),
381
403
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
382
404
  });
383
405
  const cb = new LangChainCallback({ visibe, traceId, agentName });
@@ -401,6 +423,7 @@ export function patchAgentExecutor(agentsModule, visibe) {
401
423
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
402
424
  total_input_tokens: cb.totalInputTokens,
403
425
  total_output_tokens: cb.totalOutputTokens,
426
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
404
427
  });
405
428
  }
406
429
  };
@@ -419,3 +442,37 @@ function _mergeCallbacks(config, cb) {
419
442
  const existing = Array.isArray(config.callbacks) ? config.callbacks : [];
420
443
  return { ...config, callbacks: [...existing, cb] };
421
444
  }
445
+ // Serialize a graph/chain input to a prompt string for the trace header.
446
+ // Handles strings, common object shapes, and falls back to JSON.
447
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
448
+ export function serializeInput(input, limit = 2000) {
449
+ if (!input)
450
+ return undefined;
451
+ let s;
452
+ if (typeof input === 'string') {
453
+ s = input;
454
+ }
455
+ else if (typeof input === 'object') {
456
+ // Try common single-field patterns first.
457
+ for (const key of ['task', 'prompt', 'input', 'query', 'question', 'text', 'content']) {
458
+ if (typeof input[key] === 'string') {
459
+ s = input[key];
460
+ break;
461
+ }
462
+ }
463
+ if (!s) {
464
+ // HumanMessage / messages array — grab the last message content.
465
+ if (Array.isArray(input.messages) && input.messages.length > 0) {
466
+ const last = input.messages[input.messages.length - 1];
467
+ s = typeof last?.content === 'string' ? last.content : JSON.stringify(last?.content ?? '');
468
+ }
469
+ else {
470
+ s = JSON.stringify(input);
471
+ }
472
+ }
473
+ }
474
+ else {
475
+ s = String(input);
476
+ }
477
+ return s.length > limit ? s.slice(0, limit) + '…' : s;
478
+ }
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { LangChainCallback, activeLangChainStorage, LANGGRAPH_INTERNAL_NODES } from './langchain.js';
2
+ import { LangChainCallback, activeLangChainStorage, LANGGRAPH_INTERNAL_NODES, serializeInput } from './langchain.js';
3
3
  // ---------------------------------------------------------------------------
4
4
  // LangGraphCallback
5
5
  // Extends LangChainCallback and adds node-level agent_start spans.
@@ -63,6 +63,7 @@ export function patchCompiledStateGraph(lgModule, visibe) {
63
63
  name: graphName,
64
64
  framework: 'langgraph',
65
65
  started_at: startedAt,
66
+ prompt: serializeInput(input),
66
67
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
67
68
  });
68
69
  // Collect node names from the graph's node registry.
@@ -93,6 +94,7 @@ export function patchCompiledStateGraph(lgModule, visibe) {
93
94
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
94
95
  total_input_tokens: cb.totalInputTokens,
95
96
  total_output_tokens: cb.totalOutputTokens,
97
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
96
98
  });
97
99
  }
98
100
  return result;
@@ -114,6 +116,7 @@ export function patchCompiledStateGraph(lgModule, visibe) {
114
116
  name: graphName,
115
117
  framework: 'langgraph',
116
118
  started_at: startedAt,
119
+ prompt: serializeInput(input),
117
120
  ...(visibe.sessionId ? { session_id: visibe.sessionId } : {}),
118
121
  });
119
122
  const nodeNames = _extractNodeNames(this);
@@ -145,6 +148,7 @@ export function patchCompiledStateGraph(lgModule, visibe) {
145
148
  total_tokens: cb.totalInputTokens + cb.totalOutputTokens,
146
149
  total_input_tokens: cb.totalInputTokens,
147
150
  total_output_tokens: cb.totalOutputTokens,
151
+ ...(cb.firstModel ? { model: cb.firstModel } : {}),
148
152
  });
149
153
  }
150
154
  };
@@ -30,6 +30,7 @@ export declare class LangChainCallback {
30
30
  totalOutputTokens: number;
31
31
  totalCost: number;
32
32
  llmCallCount: number;
33
+ firstModel: string | undefined;
33
34
  constructor(options: {
34
35
  visibe: Visibe;
35
36
  traceId: string;
@@ -50,3 +51,4 @@ export declare class LangChainCallback {
50
51
  }
51
52
  export declare function patchRunnableSequence(lcModule: any, visibe: Visibe): () => void;
52
53
  export declare function patchAgentExecutor(agentsModule: any, visibe: Visibe): () => void;
54
+ export declare function serializeInput(input: any, limit?: number): string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visibe.ai/node",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "AI Agent Observability — Track OpenAI, LangChain, LangGraph, Bedrock, Vercel AI, Anthropic",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",