@illuma-ai/observability-langchain 0.1.0 → 0.2.1
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/__tests__/callback-handler.test.d.ts +2 -0
- package/dist/__tests__/callback-handler.test.d.ts.map +1 -0
- package/dist/__tests__/callback-handler.test.js +415 -0
- package/dist/__tests__/callback-handler.test.js.map +1 -0
- package/dist/callback-handler.d.ts +146 -20
- package/dist/callback-handler.d.ts.map +1 -1
- package/dist/callback-handler.js +197 -47
- package/dist/callback-handler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +44 -17
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-handler.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/callback-handler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { ObservabilityCallbackHandler, } from '../callback-handler.js';
|
|
3
|
+
function createMockClient() {
|
|
4
|
+
const events = [];
|
|
5
|
+
return {
|
|
6
|
+
events,
|
|
7
|
+
enqueue: (event) => events.push(event),
|
|
8
|
+
flush: vi.fn().mockResolvedValue(undefined),
|
|
9
|
+
shutdown: vi.fn().mockResolvedValue(undefined),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Helpers
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
/** Create a minimal Serialized descriptor that LangChain passes to callbacks. */
|
|
16
|
+
function serialized(name) {
|
|
17
|
+
return { lc: 1, type: 'not_implemented', id: ['langchain', name] };
|
|
18
|
+
}
|
|
19
|
+
/** Find all events of a given type from the mock client's event log. */
|
|
20
|
+
function eventsOfType(client, type) {
|
|
21
|
+
return client.events.filter((e) => e.type === type);
|
|
22
|
+
}
|
|
23
|
+
/** Return the body of the first event of the given type, or undefined. */
|
|
24
|
+
function firstBody(client, type) {
|
|
25
|
+
return eventsOfType(client, type)[0]?.body;
|
|
26
|
+
}
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Tests
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
describe('ObservabilityCallbackHandler', () => {
|
|
31
|
+
let client;
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
client = createMockClient();
|
|
34
|
+
});
|
|
35
|
+
// =========================================================================
|
|
36
|
+
// Constructor & Initialization
|
|
37
|
+
// =========================================================================
|
|
38
|
+
describe('Constructor & Initialization', () => {
|
|
39
|
+
it('1. creates handler with a client instance', () => {
|
|
40
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
41
|
+
expect(handler).toBeInstanceOf(ObservabilityCallbackHandler);
|
|
42
|
+
});
|
|
43
|
+
it('2. creates handler with clientOptions (lazy construction)', () => {
|
|
44
|
+
// We can't actually construct because @illuma-ai/observability-node
|
|
45
|
+
// may not be installed, so we expect the error about the missing package
|
|
46
|
+
// (which proves it attempted the dynamic require path).
|
|
47
|
+
expect(() => new ObservabilityCallbackHandler({
|
|
48
|
+
clientOptions: { publicKey: 'pk-test', secretKey: 'sk-test' },
|
|
49
|
+
})).toThrow('@illuma-ai/observability-node');
|
|
50
|
+
});
|
|
51
|
+
it('3. throws if neither client nor clientOptions provided', () => {
|
|
52
|
+
expect(() => new ObservabilityCallbackHandler({})).toThrow('requires either a `client` or `clientOptions`');
|
|
53
|
+
});
|
|
54
|
+
it('4. uses custom traceName when provided', async () => {
|
|
55
|
+
const handler = new ObservabilityCallbackHandler({
|
|
56
|
+
client,
|
|
57
|
+
traceName: 'my-custom-trace',
|
|
58
|
+
});
|
|
59
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
60
|
+
const traceBody = firstBody(client, 'trace-create');
|
|
61
|
+
expect(traceBody?.name).toBe('my-custom-trace');
|
|
62
|
+
});
|
|
63
|
+
it('5. uses default traceName when not provided', async () => {
|
|
64
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
65
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
66
|
+
const traceBody = firstBody(client, 'trace-create');
|
|
67
|
+
expect(traceBody?.name).toBe('langchain-run');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// =========================================================================
|
|
71
|
+
// Trace Creation
|
|
72
|
+
// =========================================================================
|
|
73
|
+
describe('Trace Creation', () => {
|
|
74
|
+
it('6. first LLM call creates a trace-create event', async () => {
|
|
75
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
76
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
77
|
+
const traceEvents = eventsOfType(client, 'trace-create');
|
|
78
|
+
expect(traceEvents).toHaveLength(1);
|
|
79
|
+
});
|
|
80
|
+
it('7. trace includes userId when set in options', async () => {
|
|
81
|
+
const handler = new ObservabilityCallbackHandler({
|
|
82
|
+
client,
|
|
83
|
+
userId: 'user-42',
|
|
84
|
+
});
|
|
85
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
86
|
+
const traceBody = firstBody(client, 'trace-create');
|
|
87
|
+
expect(traceBody?.userId).toBe('user-42');
|
|
88
|
+
});
|
|
89
|
+
it('8. trace includes sessionId when set in options', async () => {
|
|
90
|
+
const handler = new ObservabilityCallbackHandler({
|
|
91
|
+
client,
|
|
92
|
+
sessionId: 'sess-99',
|
|
93
|
+
});
|
|
94
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
95
|
+
const traceBody = firstBody(client, 'trace-create');
|
|
96
|
+
expect(traceBody?.sessionId).toBe('sess-99');
|
|
97
|
+
});
|
|
98
|
+
it('9. trace includes environment when set in options', async () => {
|
|
99
|
+
const handler = new ObservabilityCallbackHandler({
|
|
100
|
+
client,
|
|
101
|
+
environment: 'staging',
|
|
102
|
+
});
|
|
103
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
104
|
+
const traceBody = firstBody(client, 'trace-create');
|
|
105
|
+
expect(traceBody?.environment).toBe('staging');
|
|
106
|
+
});
|
|
107
|
+
it('10. trace includes metadata when set in options', async () => {
|
|
108
|
+
const handler = new ObservabilityCallbackHandler({
|
|
109
|
+
client,
|
|
110
|
+
metadata: { team: 'platform', version: '2.1' },
|
|
111
|
+
});
|
|
112
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['hello'], 'run-1');
|
|
113
|
+
const traceBody = firstBody(client, 'trace-create');
|
|
114
|
+
expect(traceBody?.metadata).toEqual({ team: 'platform', version: '2.1' });
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
// =========================================================================
|
|
118
|
+
// LLM Handling
|
|
119
|
+
// =========================================================================
|
|
120
|
+
describe('LLM Handling', () => {
|
|
121
|
+
it('11. handleLLMStart creates a generation-create event', async () => {
|
|
122
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
123
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
124
|
+
const genEvents = eventsOfType(client, 'generation-create');
|
|
125
|
+
expect(genEvents).toHaveLength(1);
|
|
126
|
+
expect(genEvents[0].body.input).toEqual(['prompt']);
|
|
127
|
+
});
|
|
128
|
+
it('12. handleLLMStart extracts model from invocationParams (via metadata)', async () => {
|
|
129
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
130
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1', undefined, undefined, undefined, { ls_model_name: 'gpt-4o' });
|
|
131
|
+
const genBody = firstBody(client, 'generation-create');
|
|
132
|
+
expect(genBody?.model).toBe('gpt-4o');
|
|
133
|
+
});
|
|
134
|
+
it('13. handleLLMStart extracts model from metadata.ls_model_name', async () => {
|
|
135
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
136
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1', undefined, undefined, undefined, { ls_model_name: 'claude-sonnet-4-20250514' });
|
|
137
|
+
const genBody = firstBody(client, 'generation-create');
|
|
138
|
+
expect(genBody?.model).toBe('claude-sonnet-4-20250514');
|
|
139
|
+
});
|
|
140
|
+
it('14. handleLLMStart extracts provider from metadata.ls_provider', async () => {
|
|
141
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
142
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1', undefined, undefined, undefined, { ls_provider: 'openai' });
|
|
143
|
+
const genBody = firstBody(client, 'generation-create');
|
|
144
|
+
expect(genBody?.provider).toBe('openai');
|
|
145
|
+
});
|
|
146
|
+
it('15. handleLLMEnd creates a generation-update event with output', async () => {
|
|
147
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
148
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
149
|
+
const llmResult = {
|
|
150
|
+
generations: [[{ text: 'Hello world', generationInfo: {} }]],
|
|
151
|
+
llmOutput: {},
|
|
152
|
+
};
|
|
153
|
+
await handler.handleLLMEnd(llmResult, 'run-1');
|
|
154
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
155
|
+
expect(updateBody).toBeDefined();
|
|
156
|
+
expect(updateBody?.output).toBe('Hello world');
|
|
157
|
+
});
|
|
158
|
+
it('16. handleLLMEnd extracts token usage (tokenUsage field)', async () => {
|
|
159
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
160
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
161
|
+
const llmResult = {
|
|
162
|
+
generations: [[{ text: 'response', generationInfo: {} }]],
|
|
163
|
+
llmOutput: {
|
|
164
|
+
tokenUsage: {
|
|
165
|
+
promptTokens: 10,
|
|
166
|
+
completionTokens: 20,
|
|
167
|
+
totalTokens: 30,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
await handler.handleLLMEnd(llmResult, 'run-1');
|
|
172
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
173
|
+
const usage = updateBody?.usage;
|
|
174
|
+
expect(usage.promptTokens).toBe(10);
|
|
175
|
+
expect(usage.completionTokens).toBe(20);
|
|
176
|
+
expect(usage.totalTokens).toBe(30);
|
|
177
|
+
});
|
|
178
|
+
it('17. handleLLMEnd maps snake_case tokenUsage fields correctly', async () => {
|
|
179
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
180
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
181
|
+
// Some providers use snake_case token usage
|
|
182
|
+
const llmResult = {
|
|
183
|
+
generations: [[{ text: 'response', generationInfo: {} }]],
|
|
184
|
+
llmOutput: {
|
|
185
|
+
tokenUsage: {
|
|
186
|
+
prompt_tokens: 15,
|
|
187
|
+
completion_tokens: 25,
|
|
188
|
+
total_tokens: 40,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
await handler.handleLLMEnd(llmResult, 'run-1');
|
|
193
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
194
|
+
const usage = updateBody?.usage;
|
|
195
|
+
// The handler maps both camelCase and snake_case variants
|
|
196
|
+
expect(usage.promptTokens).toBe(15);
|
|
197
|
+
expect(usage.completionTokens).toBe(25);
|
|
198
|
+
expect(usage.totalTokens).toBe(40);
|
|
199
|
+
});
|
|
200
|
+
it('18. handleLLMError creates a generation-update with ERROR level', async () => {
|
|
201
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
202
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
203
|
+
await handler.handleLLMError(new Error('Rate limited'), 'run-1');
|
|
204
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
205
|
+
expect(updateBody).toBeDefined();
|
|
206
|
+
expect(updateBody?.level).toBe('ERROR');
|
|
207
|
+
});
|
|
208
|
+
it('19. handleLLMError includes error message in statusMessage', async () => {
|
|
209
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
210
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
211
|
+
await handler.handleLLMError(new Error('Rate limited'), 'run-1');
|
|
212
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
213
|
+
expect(updateBody?.statusMessage).toBe('Rate limited');
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
// =========================================================================
|
|
217
|
+
// Chain Handling
|
|
218
|
+
// =========================================================================
|
|
219
|
+
describe('Chain Handling', () => {
|
|
220
|
+
it('20. handleChainStart creates a chain-create event (not span-create)', async () => {
|
|
221
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
222
|
+
await handler.handleChainStart(serialized('RunnableSequence'), { input: 'test' }, 'chain-1');
|
|
223
|
+
expect(eventsOfType(client, 'chain-create')).toHaveLength(1);
|
|
224
|
+
expect(eventsOfType(client, 'span-create')).toHaveLength(0);
|
|
225
|
+
});
|
|
226
|
+
it('21. handleChainEnd creates a span-update event', async () => {
|
|
227
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
228
|
+
await handler.handleChainStart(serialized('RunnableSequence'), { input: 'test' }, 'chain-1');
|
|
229
|
+
await handler.handleChainEnd({ result: 'done' }, 'chain-1');
|
|
230
|
+
const updateBody = firstBody(client, 'span-update');
|
|
231
|
+
expect(updateBody).toBeDefined();
|
|
232
|
+
expect(updateBody?.output).toEqual({ result: 'done' });
|
|
233
|
+
});
|
|
234
|
+
it('22. handleChainError creates a span-update with ERROR level', async () => {
|
|
235
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
236
|
+
await handler.handleChainStart(serialized('RunnableSequence'), { input: 'test' }, 'chain-1');
|
|
237
|
+
await handler.handleChainError(new Error('Chain failed'), 'chain-1');
|
|
238
|
+
const updateBody = firstBody(client, 'span-update');
|
|
239
|
+
expect(updateBody?.level).toBe('ERROR');
|
|
240
|
+
expect(updateBody?.statusMessage).toBe('Chain failed');
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
// =========================================================================
|
|
244
|
+
// Tool Handling
|
|
245
|
+
// =========================================================================
|
|
246
|
+
describe('Tool Handling', () => {
|
|
247
|
+
it('23. handleToolStart creates a tool-create event (not span-create)', async () => {
|
|
248
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
249
|
+
await handler.handleToolStart(serialized('Calculator'), 'input', 'tool-1');
|
|
250
|
+
expect(eventsOfType(client, 'tool-create')).toHaveLength(1);
|
|
251
|
+
expect(eventsOfType(client, 'span-create')).toHaveLength(0);
|
|
252
|
+
});
|
|
253
|
+
it('24. handleToolEnd creates a span-update event with output', async () => {
|
|
254
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
255
|
+
await handler.handleToolStart(serialized('Calculator'), '2+2', 'tool-1');
|
|
256
|
+
await handler.handleToolEnd('4', 'tool-1');
|
|
257
|
+
const updateBody = firstBody(client, 'span-update');
|
|
258
|
+
expect(updateBody).toBeDefined();
|
|
259
|
+
expect(updateBody?.output).toBe('4');
|
|
260
|
+
});
|
|
261
|
+
it('25. handleToolError creates a span-update with ERROR level', async () => {
|
|
262
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
263
|
+
await handler.handleToolStart(serialized('Calculator'), 'invalid', 'tool-1');
|
|
264
|
+
await handler.handleToolError(new Error('Parse error'), 'tool-1');
|
|
265
|
+
const updateBody = firstBody(client, 'span-update');
|
|
266
|
+
expect(updateBody?.level).toBe('ERROR');
|
|
267
|
+
expect(updateBody?.statusMessage).toBe('Parse error');
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
// =========================================================================
|
|
271
|
+
// Retriever Handling
|
|
272
|
+
// =========================================================================
|
|
273
|
+
describe('Retriever Handling', () => {
|
|
274
|
+
it('26. handleRetrieverStart creates a retriever-create event (not span-create)', async () => {
|
|
275
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
276
|
+
await handler.handleRetrieverStart(serialized('VectorStoreRetriever'), 'search query', 'ret-1');
|
|
277
|
+
expect(eventsOfType(client, 'retriever-create')).toHaveLength(1);
|
|
278
|
+
expect(eventsOfType(client, 'span-create')).toHaveLength(0);
|
|
279
|
+
});
|
|
280
|
+
it('27. handleRetrieverEnd creates a span-update event with documents', async () => {
|
|
281
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
282
|
+
await handler.handleRetrieverStart(serialized('VectorStoreRetriever'), 'search query', 'ret-1');
|
|
283
|
+
const docs = [
|
|
284
|
+
{ pageContent: 'doc1 content', metadata: { source: 'a.pdf' } },
|
|
285
|
+
{ pageContent: 'doc2 content', metadata: { source: 'b.pdf' } },
|
|
286
|
+
];
|
|
287
|
+
await handler.handleRetrieverEnd(docs, 'ret-1');
|
|
288
|
+
const updateBody = firstBody(client, 'span-update');
|
|
289
|
+
expect(updateBody).toBeDefined();
|
|
290
|
+
const output = updateBody?.output;
|
|
291
|
+
expect(output).toHaveLength(2);
|
|
292
|
+
expect(output[0].pageContent).toBe('doc1 content');
|
|
293
|
+
expect(output[1].metadata).toEqual({ source: 'b.pdf' });
|
|
294
|
+
// Also check documentCount in metadata
|
|
295
|
+
const meta = updateBody?.metadata;
|
|
296
|
+
expect(meta?.documentCount).toBe(2);
|
|
297
|
+
});
|
|
298
|
+
it('28. handleRetrieverError creates a span-update with ERROR level', async () => {
|
|
299
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
300
|
+
await handler.handleRetrieverStart(serialized('VectorStoreRetriever'), 'search query', 'ret-1');
|
|
301
|
+
await handler.handleRetrieverError(new Error('Connection timeout'), 'ret-1');
|
|
302
|
+
const updateBody = firstBody(client, 'span-update');
|
|
303
|
+
expect(updateBody?.level).toBe('ERROR');
|
|
304
|
+
expect(updateBody?.statusMessage).toBe('Connection timeout');
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
// =========================================================================
|
|
308
|
+
// Parent-Child Relationships
|
|
309
|
+
// =========================================================================
|
|
310
|
+
describe('Parent-Child Relationships', () => {
|
|
311
|
+
it('29. nested runs preserve parentObservationId', async () => {
|
|
312
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
313
|
+
// Chain is root
|
|
314
|
+
await handler.handleChainStart(serialized('RunnableSequence'), { input: 'test' }, 'chain-1');
|
|
315
|
+
// LLM is child of chain
|
|
316
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'llm-1', 'chain-1');
|
|
317
|
+
const genBody = firstBody(client, 'generation-create');
|
|
318
|
+
expect(genBody?.parentObservationId).toBeDefined();
|
|
319
|
+
});
|
|
320
|
+
it('30. root run has no parentObservationId', async () => {
|
|
321
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
322
|
+
await handler.handleChainStart(serialized('RunnableSequence'), { input: 'test' }, 'chain-1');
|
|
323
|
+
const chainBody = firstBody(client, 'chain-create');
|
|
324
|
+
expect(chainBody?.parentObservationId).toBeUndefined();
|
|
325
|
+
});
|
|
326
|
+
it('31. child LLM run under a chain references the chain observationId', async () => {
|
|
327
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
328
|
+
await handler.handleChainStart(serialized('RunnableSequence'), { input: 'test' }, 'chain-1');
|
|
329
|
+
const chainBody = firstBody(client, 'chain-create');
|
|
330
|
+
const chainObsId = chainBody?.id;
|
|
331
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'llm-1', 'chain-1');
|
|
332
|
+
const genBody = firstBody(client, 'generation-create');
|
|
333
|
+
expect(genBody?.parentObservationId).toBe(chainObsId);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
// =========================================================================
|
|
337
|
+
// Flush & Shutdown
|
|
338
|
+
// =========================================================================
|
|
339
|
+
describe('Flush & Shutdown', () => {
|
|
340
|
+
it('32. flushAsync calls client.flush()', async () => {
|
|
341
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
342
|
+
await handler.flushAsync();
|
|
343
|
+
expect(client.flush).toHaveBeenCalledOnce();
|
|
344
|
+
});
|
|
345
|
+
it('33. handler can be used across multiple sequential calls', async () => {
|
|
346
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
347
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['p1'], 'run-1');
|
|
348
|
+
await handler.handleLLMEnd({
|
|
349
|
+
generations: [[{ text: 'r1', generationInfo: {} }]],
|
|
350
|
+
llmOutput: {},
|
|
351
|
+
}, 'run-1');
|
|
352
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['p2'], 'run-2');
|
|
353
|
+
await handler.handleLLMEnd({
|
|
354
|
+
generations: [[{ text: 'r2', generationInfo: {} }]],
|
|
355
|
+
llmOutput: {},
|
|
356
|
+
}, 'run-2');
|
|
357
|
+
// Should have: 1 trace-create, 2 generation-create, 2 generation-update
|
|
358
|
+
expect(eventsOfType(client, 'trace-create')).toHaveLength(1);
|
|
359
|
+
expect(eventsOfType(client, 'generation-create')).toHaveLength(2);
|
|
360
|
+
expect(eventsOfType(client, 'generation-update')).toHaveLength(2);
|
|
361
|
+
});
|
|
362
|
+
it('34. multiple LLM calls create separate generation events under the same trace', async () => {
|
|
363
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
364
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['p1'], 'run-1');
|
|
365
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['p2'], 'run-2');
|
|
366
|
+
const genEvents = eventsOfType(client, 'generation-create');
|
|
367
|
+
expect(genEvents).toHaveLength(2);
|
|
368
|
+
// Both should share the same traceId
|
|
369
|
+
const traceId1 = genEvents[0].body.traceId;
|
|
370
|
+
const traceId2 = genEvents[1].body.traceId;
|
|
371
|
+
expect(traceId1).toBe(traceId2);
|
|
372
|
+
// But have different observation IDs
|
|
373
|
+
expect(genEvents[0].body.id).not.toBe(genEvents[1].body.id);
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
// =========================================================================
|
|
377
|
+
// Edge Cases
|
|
378
|
+
// =========================================================================
|
|
379
|
+
describe('Edge Cases', () => {
|
|
380
|
+
it('35. handles empty/undefined inputs gracefully', async () => {
|
|
381
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
382
|
+
// Empty prompts array
|
|
383
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), [], 'run-1');
|
|
384
|
+
const genBody = firstBody(client, 'generation-create');
|
|
385
|
+
expect(genBody?.input).toEqual([]);
|
|
386
|
+
// handleLLMEnd with no generations
|
|
387
|
+
const llmResult = {
|
|
388
|
+
generations: [],
|
|
389
|
+
llmOutput: undefined,
|
|
390
|
+
};
|
|
391
|
+
await handler.handleLLMEnd(llmResult, 'run-1');
|
|
392
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
393
|
+
expect(updateBody).toBeDefined();
|
|
394
|
+
// Output falls back to the full generations array when no text is found
|
|
395
|
+
expect(updateBody?.output).toEqual([]);
|
|
396
|
+
});
|
|
397
|
+
it('36. handles missing token usage gracefully (no usage in generation-update)', async () => {
|
|
398
|
+
const handler = new ObservabilityCallbackHandler({ client });
|
|
399
|
+
await handler.handleLLMStart(serialized('ChatOpenAI'), ['prompt'], 'run-1');
|
|
400
|
+
const llmResult = {
|
|
401
|
+
generations: [[{ text: 'response', generationInfo: {} }]],
|
|
402
|
+
llmOutput: {}, // No tokenUsage at all
|
|
403
|
+
};
|
|
404
|
+
await handler.handleLLMEnd(llmResult, 'run-1');
|
|
405
|
+
const updateBody = firstBody(client, 'generation-update');
|
|
406
|
+
expect(updateBody).toBeDefined();
|
|
407
|
+
// Usage object exists but all fields are undefined
|
|
408
|
+
const usage = updateBody?.usage;
|
|
409
|
+
expect(usage.promptTokens).toBeUndefined();
|
|
410
|
+
expect(usage.completionTokens).toBeUndefined();
|
|
411
|
+
expect(usage.totalTokens).toBeUndefined();
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
//# sourceMappingURL=callback-handler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-handler.test.js","sourceRoot":"","sources":["../../src/__tests__/callback-handler.test.ts"],"names":[],"mappings":"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"}
|