@traccia2/sdk 0.0.5 → 0.0.7

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.
@@ -6,31 +6,7 @@
6
6
 
7
7
  import { ISpan } from '../types';
8
8
  import { getTracer } from '../auto';
9
-
10
- // Try to import BaseCallbackHandler from different LangChain versions
11
- let BaseCallbackHandler: any = class {
12
- ignoreAgent = false;
13
- ignoreChain = false;
14
- ignoreLLM = false;
15
- ignoreRetriever = false;
16
- ignoreToolUse = false;
17
- };
18
-
19
- try {
20
- // Try LangChain 0.2.x+
21
- // eslint-disable-next-line @typescript-eslint/no-var-requires
22
- const { BaseCallbackHandler: Handler } = require('@langchain/core/callbacks/base');
23
- BaseCallbackHandler = Handler;
24
- } catch {
25
- try {
26
- // Try older LangChain versions
27
- // eslint-disable-next-line @typescript-eslint/no-var-requires
28
- const { BaseCallbackHandler: Handler } = require('langchain/callbacks');
29
- BaseCallbackHandler = Handler;
30
- } catch {
31
- // Fallback to basic implementation - user likely has LangChain installed
32
- }
33
- }
9
+ import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
34
10
 
35
11
  /**
36
12
  * LangChain Callback Handler for Traccia SDK.
@@ -41,17 +17,19 @@ try {
41
17
  *
42
18
  * @example
43
19
  * import { ChatOpenAI } from '@langchain/openai';
44
- * import { TraciaCallbackHandler } from '@traccia/sdk/integrations';
20
+ * import { TracciaCallbackHandler } from '@traccia/sdk/integrations';
45
21
  *
46
- * const handler = new TraciaCallbackHandler();
22
+ * const handler = new TracciaCallbackHandler();
47
23
  * const model = new ChatOpenAI({ callbacks: [handler] });
48
24
  *
49
25
  * const response = await model.invoke({ input: 'Hello!' });
50
26
  * // Automatically traced with spans for LLM calls, tokens, latency, etc.
51
27
  */
52
- export class TraciaCallbackHandler extends BaseCallbackHandler {
28
+ export class TracciaCallbackHandler extends BaseCallbackHandler {
29
+ name = 'TracciaCallbackHandler';
53
30
  private tracer = getTracer('langchain');
54
31
  private spanStack: Map<string, ISpan> = new Map();
32
+ private streamingStartTimes: Record<string, Date> = {};
55
33
 
56
34
  /**
57
35
  * Extract model name from LLM instance, checking multiple property locations.
@@ -125,23 +103,47 @@ export class TraciaCallbackHandler extends BaseCallbackHandler {
125
103
  if (span) {
126
104
  try {
127
105
  // Try multiple ways to get token usage
128
- // OpenAI format
106
+ // OpenAI format and new @langchain/core format
129
107
  const tokenUsage =
130
108
  output?.llmOutput?.token_usage ||
109
+ output?.llmOutput?.tokenUsage ||
131
110
  output?.token_usage ||
132
111
  output?.metadata?.token_usage;
133
112
 
134
113
  if (tokenUsage) {
135
- if (tokenUsage.prompt_tokens !== undefined) {
136
- span.setAttribute('llm.tokens.prompt', tokenUsage.prompt_tokens);
114
+ // Handle standard token counts
115
+ const promptTokens = tokenUsage.prompt_tokens ?? tokenUsage.promptTokens;
116
+ const completionTokens = tokenUsage.completion_tokens ?? tokenUsage.completionTokens;
117
+ const totalTokens = tokenUsage.total_tokens ?? tokenUsage.totalTokens;
118
+
119
+ if (promptTokens !== undefined) {
120
+ span.setAttribute('llm.tokens.prompt', promptTokens);
137
121
  }
138
- if (tokenUsage.completion_tokens !== undefined) {
139
- span.setAttribute('llm.tokens.completion', tokenUsage.completion_tokens);
122
+ if (completionTokens !== undefined) {
123
+ span.setAttribute('llm.tokens.completion', completionTokens);
140
124
  }
141
- const totalTokens = (tokenUsage.prompt_tokens || 0) + (tokenUsage.completion_tokens || 0);
142
- if (totalTokens > 0) {
125
+ if (totalTokens !== undefined) {
143
126
  span.setAttribute('llm.tokens.total', totalTokens);
144
127
  }
128
+
129
+ // Handle detailed token breakdown for models like GPT-4o vision
130
+ // input_token_details contains breakdown of prompt token usage
131
+ if (tokenUsage.input_token_details && typeof tokenUsage.input_token_details === 'object') {
132
+ for (const [key, value] of Object.entries(tokenUsage.input_token_details)) {
133
+ if (typeof value === 'number') {
134
+ span.setAttribute(`llm.tokens.input_${key}`, value);
135
+ }
136
+ }
137
+ }
138
+
139
+ // output_token_details contains breakdown of completion token usage
140
+ if (tokenUsage.output_token_details && typeof tokenUsage.output_token_details === 'object') {
141
+ for (const [key, value] of Object.entries(tokenUsage.output_token_details)) {
142
+ if (typeof value === 'number') {
143
+ span.setAttribute(`llm.tokens.output_${key}`, value);
144
+ }
145
+ }
146
+ }
145
147
  }
146
148
 
147
149
  // Capture output text length
@@ -187,6 +189,29 @@ export class TraciaCallbackHandler extends BaseCallbackHandler {
187
189
  }
188
190
  }
189
191
 
192
+ /**
193
+ * Handle LLM new token - called when a new token is generated during streaming.
194
+ * Tracks first token latency and token count for streaming scenarios.
195
+ */
196
+ public async handleLLMNewToken(
197
+ _token: string,
198
+ _idx?: any,
199
+ runId?: string
200
+ ): Promise<void> {
201
+ if (runId && !(runId in this.streamingStartTimes)) {
202
+ // Record the time of the first streaming token
203
+ this.streamingStartTimes[runId] = new Date();
204
+ const span = this.spanStack.get(runId);
205
+ if (span) {
206
+ try {
207
+ span.setAttribute('stream.first_token_generated', true);
208
+ } catch (error) {
209
+ // Silently fail
210
+ }
211
+ }
212
+ }
213
+ }
214
+
190
215
  /**
191
216
  * Handle chain start - called when a chain begins execution.
192
217
  */
@@ -360,6 +385,14 @@ export class TraciaCallbackHandler extends BaseCallbackHandler {
360
385
  return this.handleLLMError(error, runId);
361
386
  }
362
387
 
388
+ public async onLLMNewToken(
389
+ _token: string,
390
+ idx?: any,
391
+ runId?: string
392
+ ): Promise<void> {
393
+ return this.handleLLMNewToken(_token, idx, runId);
394
+ }
395
+
363
396
  public async onChainStart(
364
397
  chain: any,
365
398
  inputs: any,