@traccia2/sdk 0.0.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.
Files changed (130) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +503 -0
  3. package/dist/auto.d.ts +27 -0
  4. package/dist/auto.d.ts.map +1 -0
  5. package/dist/auto.js +171 -0
  6. package/dist/auto.js.map +1 -0
  7. package/dist/config/env-config.d.ts +21 -0
  8. package/dist/config/env-config.d.ts.map +1 -0
  9. package/dist/config/env-config.js +111 -0
  10. package/dist/config/env-config.js.map +1 -0
  11. package/dist/config/pricing-config.d.ts +27 -0
  12. package/dist/config/pricing-config.d.ts.map +1 -0
  13. package/dist/config/pricing-config.js +74 -0
  14. package/dist/config/pricing-config.js.map +1 -0
  15. package/dist/config/runtime-config.d.ts +65 -0
  16. package/dist/config/runtime-config.d.ts.map +1 -0
  17. package/dist/config/runtime-config.js +97 -0
  18. package/dist/config/runtime-config.js.map +1 -0
  19. package/dist/context/context.d.ts +29 -0
  20. package/dist/context/context.d.ts.map +1 -0
  21. package/dist/context/context.js +48 -0
  22. package/dist/context/context.js.map +1 -0
  23. package/dist/exporter/console-exporter.d.ts +18 -0
  24. package/dist/exporter/console-exporter.d.ts.map +1 -0
  25. package/dist/exporter/console-exporter.js +39 -0
  26. package/dist/exporter/console-exporter.js.map +1 -0
  27. package/dist/exporter/http-exporter.d.ts +57 -0
  28. package/dist/exporter/http-exporter.d.ts.map +1 -0
  29. package/dist/exporter/http-exporter.js +181 -0
  30. package/dist/exporter/http-exporter.js.map +1 -0
  31. package/dist/exporter/index.d.ts +7 -0
  32. package/dist/exporter/index.d.ts.map +1 -0
  33. package/dist/exporter/index.js +12 -0
  34. package/dist/exporter/index.js.map +1 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +32 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/integrations/index.d.ts +9 -0
  40. package/dist/integrations/index.d.ts.map +1 -0
  41. package/dist/integrations/index.js +16 -0
  42. package/dist/integrations/index.js.map +1 -0
  43. package/dist/integrations/langchain-callback.d.ts +72 -0
  44. package/dist/integrations/langchain-callback.d.ts.map +1 -0
  45. package/dist/integrations/langchain-callback.js +201 -0
  46. package/dist/integrations/langchain-callback.js.map +1 -0
  47. package/dist/integrations/langgraph-instrumentation.d.ts +57 -0
  48. package/dist/integrations/langgraph-instrumentation.d.ts.map +1 -0
  49. package/dist/integrations/langgraph-instrumentation.js +162 -0
  50. package/dist/integrations/langgraph-instrumentation.js.map +1 -0
  51. package/dist/processor/batch-processor.d.ts +68 -0
  52. package/dist/processor/batch-processor.d.ts.map +1 -0
  53. package/dist/processor/batch-processor.js +150 -0
  54. package/dist/processor/batch-processor.js.map +1 -0
  55. package/dist/processor/cost-processor.d.ts +16 -0
  56. package/dist/processor/cost-processor.d.ts.map +1 -0
  57. package/dist/processor/cost-processor.js +50 -0
  58. package/dist/processor/cost-processor.js.map +1 -0
  59. package/dist/processor/index.d.ts +9 -0
  60. package/dist/processor/index.d.ts.map +1 -0
  61. package/dist/processor/index.js +18 -0
  62. package/dist/processor/index.js.map +1 -0
  63. package/dist/processor/logging-processor.d.ts +13 -0
  64. package/dist/processor/logging-processor.d.ts.map +1 -0
  65. package/dist/processor/logging-processor.js +26 -0
  66. package/dist/processor/logging-processor.js.map +1 -0
  67. package/dist/processor/sampler.d.ts +20 -0
  68. package/dist/processor/sampler.d.ts.map +1 -0
  69. package/dist/processor/sampler.js +33 -0
  70. package/dist/processor/sampler.js.map +1 -0
  71. package/dist/processor/token-counter.d.ts +13 -0
  72. package/dist/processor/token-counter.d.ts.map +1 -0
  73. package/dist/processor/token-counter.js +40 -0
  74. package/dist/processor/token-counter.js.map +1 -0
  75. package/dist/tracer/index.d.ts +8 -0
  76. package/dist/tracer/index.d.ts.map +1 -0
  77. package/dist/tracer/index.js +15 -0
  78. package/dist/tracer/index.js.map +1 -0
  79. package/dist/tracer/provider.d.ts +59 -0
  80. package/dist/tracer/provider.d.ts.map +1 -0
  81. package/dist/tracer/provider.js +114 -0
  82. package/dist/tracer/provider.js.map +1 -0
  83. package/dist/tracer/span-context.d.ts +23 -0
  84. package/dist/tracer/span-context.d.ts.map +1 -0
  85. package/dist/tracer/span-context.js +34 -0
  86. package/dist/tracer/span-context.js.map +1 -0
  87. package/dist/tracer/span.d.ts +49 -0
  88. package/dist/tracer/span.d.ts.map +1 -0
  89. package/dist/tracer/span.js +118 -0
  90. package/dist/tracer/span.js.map +1 -0
  91. package/dist/tracer/tracer.d.ts +28 -0
  92. package/dist/tracer/tracer.d.ts.map +1 -0
  93. package/dist/tracer/tracer.js +75 -0
  94. package/dist/tracer/tracer.js.map +1 -0
  95. package/dist/types.d.ts +135 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +16 -0
  98. package/dist/types.js.map +1 -0
  99. package/package.json +79 -0
  100. package/src/__tests__/exporter.test.ts +62 -0
  101. package/src/__tests__/integrations-langchain.test.ts +384 -0
  102. package/src/__tests__/integrations-langgraph.test.ts +479 -0
  103. package/src/__tests__/processor.test.ts +89 -0
  104. package/src/__tests__/span.test.ts +103 -0
  105. package/src/__tests__/tracer.test.ts +89 -0
  106. package/src/auto.ts +198 -0
  107. package/src/config/env-config.ts +93 -0
  108. package/src/config/pricing-config.ts +84 -0
  109. package/src/config/runtime-config.ts +108 -0
  110. package/src/context/context.ts +52 -0
  111. package/src/exporter/console-exporter.ts +38 -0
  112. package/src/exporter/http-exporter.ts +188 -0
  113. package/src/exporter/index.ts +7 -0
  114. package/src/index.ts +51 -0
  115. package/src/integrations/README.md +287 -0
  116. package/src/integrations/index.ts +13 -0
  117. package/src/integrations/langchain-callback.ts +229 -0
  118. package/src/integrations/langgraph-instrumentation.ts +174 -0
  119. package/src/processor/batch-processor.ts +180 -0
  120. package/src/processor/cost-processor.ts +57 -0
  121. package/src/processor/index.ts +9 -0
  122. package/src/processor/logging-processor.ts +26 -0
  123. package/src/processor/sampler.ts +35 -0
  124. package/src/processor/token-counter.ts +42 -0
  125. package/src/tracer/index.ts +8 -0
  126. package/src/tracer/provider.ts +130 -0
  127. package/src/tracer/span-context.ts +46 -0
  128. package/src/tracer/span.ts +145 -0
  129. package/src/tracer/tracer.ts +100 -0
  130. package/src/types.ts +155 -0
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Tests for LangChain integration (TraciaCallbackHandler)
3
+ */
4
+
5
+ import { TraciaCallbackHandler } from '../integrations/langchain-callback';
6
+ import { startTracing, stopTracing } from '../auto';
7
+
8
+ describe('TraciaCallbackHandler', () => {
9
+ beforeEach(() => {
10
+ startTracing({
11
+ enableTokenCounting: false,
12
+ enableCostTracking: false,
13
+ });
14
+ });
15
+
16
+ afterEach(() => {
17
+ stopTracing();
18
+ });
19
+
20
+ describe('handleLLMStart', () => {
21
+ it('should create a span for LLM invocation', async () => {
22
+ const handler = new TraciaCallbackHandler();
23
+ const mockLLM = {
24
+ name: 'gpt-4',
25
+ _modelType: 'openai',
26
+ };
27
+
28
+ await handler.handleLLMStart(mockLLM, ['prompt1', 'prompt2'], 'run-1');
29
+
30
+ // Verify span was created in the handler's span map
31
+ expect(handler['spanStack'].has('run-1')).toBe(true);
32
+ });
33
+
34
+ it('should capture LLM model name in attributes', async () => {
35
+ const handler = new TraciaCallbackHandler();
36
+ const mockLLM = {
37
+ name: 'claude-3',
38
+ _modelType: 'anthropic',
39
+ };
40
+
41
+ await handler.handleLLMStart(mockLLM, ['test prompt'], 'run-2');
42
+
43
+ const span = handler['spanStack'].get('run-2');
44
+ expect(span?.attributes?.model).toMatch(/claude-3|anthropic/);
45
+ });
46
+
47
+ it('should capture prompt count', async () => {
48
+ const handler = new TraciaCallbackHandler();
49
+ const mockLLM = { name: 'test-model' };
50
+ const prompts = ['p1', 'p2', 'p3'];
51
+
52
+ await handler.handleLLMStart(mockLLM, prompts, 'run-3');
53
+
54
+ const span = handler['spanStack'].get('run-3');
55
+ expect(span?.attributes?.prompt_count).toBe(3);
56
+ });
57
+
58
+ it('should handle missing model name gracefully', async () => {
59
+ const handler = new TraciaCallbackHandler();
60
+ const mockLLM = {}; // No name or _modelType
61
+
62
+ await handler.handleLLMStart(mockLLM, ['prompt'], 'run-4');
63
+
64
+ const span = handler['spanStack'].get('run-4');
65
+ expect(span?.attributes?.model).toBe('unknown');
66
+ });
67
+ });
68
+
69
+ describe('handleLLMEnd', () => {
70
+ it('should end LLM span and record token counts', async () => {
71
+ const handler = new TraciaCallbackHandler();
72
+ const mockLLM = { name: 'gpt-4' };
73
+
74
+ // Start span
75
+ await handler.handleLLMStart(mockLLM, ['prompt'], 'run-5');
76
+
77
+ // End span
78
+ const mockOutput = {
79
+ generations: [[{ text: 'response', generation_info: { usage: { prompt_tokens: 10, completion_tokens: 5 } } }]],
80
+ };
81
+ await handler.handleLLMEnd(mockOutput, 'run-5');
82
+
83
+ // Verify span was removed after ending
84
+ expect(handler['spanStack'].has('run-5')).toBe(false);
85
+ });
86
+
87
+ it('should record output length', async () => {
88
+ const handler = new TraciaCallbackHandler();
89
+ const mockLLM = { name: 'test' };
90
+
91
+ await handler.handleLLMStart(mockLLM, ['prompt'], 'run-6');
92
+
93
+ const output = {
94
+ generations: [[{ text: 'This is a test response that has some length to it' }]],
95
+ };
96
+ await handler.handleLLMEnd(output, 'run-6');
97
+
98
+ // Span should be ended
99
+ expect(handler['spanStack'].has('run-6')).toBe(false);
100
+ });
101
+ });
102
+
103
+ describe('handleChainStart', () => {
104
+ it('should create a span for chain execution', async () => {
105
+ const handler = new TraciaCallbackHandler();
106
+ const mockChain = {
107
+ name: 'test-chain',
108
+ _chainType: 'stuff',
109
+ };
110
+
111
+ await handler.handleChainStart(mockChain, { input: 'test' }, 'chain-1');
112
+
113
+ expect(handler['spanStack'].has('chain-1')).toBe(true);
114
+ });
115
+
116
+ it('should capture chain name and type', async () => {
117
+ const handler = new TraciaCallbackHandler();
118
+ const mockChain = {
119
+ name: 'qa-chain',
120
+ _chainType: 'retrieval_qa',
121
+ };
122
+
123
+ await handler.handleChainStart(mockChain, { query: 'test' }, 'chain-2');
124
+
125
+ const span = handler['spanStack'].get('chain-2');
126
+ expect(span?.attributes?.chain_name).toBe('qa-chain');
127
+ expect(span?.attributes?.chain_type).toBe('retrieval_qa');
128
+ });
129
+
130
+ it('should record input keys', async () => {
131
+ const handler = new TraciaCallbackHandler();
132
+ const mockChain = { name: 'chain' };
133
+ const inputs = { key1: 'value1', key2: 'value2' };
134
+
135
+ await handler.handleChainStart(mockChain, inputs, 'chain-3');
136
+
137
+ const span = handler['spanStack'].get('chain-3');
138
+ expect(span?.attributes?.input_keys).toContain('key1');
139
+ expect(span?.attributes?.input_keys).toContain('key2');
140
+ });
141
+ });
142
+
143
+ describe('handleChainEnd', () => {
144
+ it('should end chain span and record output', async () => {
145
+ const handler = new TraciaCallbackHandler();
146
+ const mockChain = { name: 'chain' };
147
+
148
+ await handler.handleChainStart(mockChain, { input: 'test' }, 'chain-4');
149
+
150
+ const output = { output: 'result' };
151
+ await handler.handleChainEnd(output, 'chain-4');
152
+
153
+ expect(handler['spanStack'].has('chain-4')).toBe(false);
154
+ });
155
+ });
156
+
157
+ describe('handleToolStart', () => {
158
+ it('should create a span for tool invocation', async () => {
159
+ const handler = new TraciaCallbackHandler();
160
+ const mockTool = {
161
+ name: 'search-api',
162
+ };
163
+
164
+ await handler.handleToolStart(mockTool, 'search query', 'tool-1');
165
+
166
+ expect(handler['spanStack'].has('tool-1')).toBe(true);
167
+ });
168
+
169
+ it('should capture tool name', async () => {
170
+ const handler = new TraciaCallbackHandler();
171
+ const mockTool = { name: 'calculator' };
172
+
173
+ await handler.handleToolStart(mockTool, '2+2', 'tool-2');
174
+
175
+ const span = handler['spanStack'].get('tool-2');
176
+ expect(span?.attributes?.tool_name).toBe('calculator');
177
+ });
178
+
179
+ it('should record input length', async () => {
180
+ const handler = new TraciaCallbackHandler();
181
+ const mockTool = { name: 'tool' };
182
+ const input = 'test input with some length';
183
+
184
+ await handler.handleToolStart(mockTool, input, 'tool-3');
185
+
186
+ const span = handler['spanStack'].get('tool-3');
187
+ expect(span?.attributes?.input_length).toBeGreaterThan(0);
188
+ });
189
+ });
190
+
191
+ describe('handleToolEnd', () => {
192
+ it('should end tool span', async () => {
193
+ const handler = new TraciaCallbackHandler();
194
+ const mockTool = { name: 'tool' };
195
+
196
+ await handler.handleToolStart(mockTool, 'input', 'tool-4');
197
+ await handler.handleToolEnd('output', 'tool-4');
198
+
199
+ expect(handler['spanStack'].has('tool-4')).toBe(false);
200
+ });
201
+
202
+ it('should record output length', async () => {
203
+ const handler = new TraciaCallbackHandler();
204
+ const mockTool = { name: 'tool' };
205
+
206
+ await handler.handleToolStart(mockTool, 'input', 'tool-5');
207
+ const output = 'This is the tool output response';
208
+ await handler.handleToolEnd(output, 'tool-5');
209
+
210
+ expect(handler['spanStack'].has('tool-5')).toBe(false);
211
+ });
212
+ });
213
+
214
+ describe('handleAgentAction', () => {
215
+ it('should update existing span on agent action', async () => {
216
+ const handler = new TraciaCallbackHandler();
217
+ const mockChain = { name: 'chain' };
218
+
219
+ // Start a span first
220
+ await handler.handleChainStart(mockChain, {}, 'agent-1');
221
+
222
+ // Then handle agent action
223
+ const mockAction = {
224
+ tool: 'search',
225
+ toolInput: 'query',
226
+ };
227
+ await handler.handleAgentAction(mockAction, 'agent-1');
228
+
229
+ // Span should still exist
230
+ expect(handler['spanStack'].has('agent-1')).toBe(true);
231
+ });
232
+
233
+ it('should record agent action details', async () => {
234
+ const handler = new TraciaCallbackHandler();
235
+ const mockChain = { name: 'chain' };
236
+
237
+ // Start a span first
238
+ await handler.handleChainStart(mockChain, {}, 'agent-2');
239
+
240
+ // Then handle agent action
241
+ const mockAction = {
242
+ tool: 'calculator',
243
+ toolInput: '42 / 7',
244
+ };
245
+ await handler.handleAgentAction(mockAction, 'agent-2');
246
+
247
+ // Span should have agent action recorded
248
+ const span = handler['spanStack'].get('agent-2');
249
+ expect(span).toBeDefined();
250
+ });
251
+ });
252
+
253
+ describe('handleAgentFinish', () => {
254
+ it('should end agent span on finish', async () => {
255
+ const handler = new TraciaCallbackHandler();
256
+
257
+ // Create a span first
258
+ const mockAction = { tool: 'test', toolInput: 'input' };
259
+ await handler.handleAgentAction(mockAction, 'agent-3');
260
+
261
+ // Finish agent
262
+ const finish = { output: 'final result' };
263
+ await handler.handleAgentFinish(finish, 'agent-3');
264
+
265
+ expect(handler['spanStack'].has('agent-3')).toBe(false);
266
+ });
267
+
268
+ it('should record final output', async () => {
269
+ const handler = new TraciaCallbackHandler();
270
+ const mockAction = { tool: 'test', toolInput: 'input' };
271
+
272
+ await handler.handleAgentAction(mockAction, 'agent-4');
273
+
274
+ const finish = { output: 'completed result' };
275
+ await handler.handleAgentFinish(finish, 'agent-4');
276
+
277
+ expect(handler['spanStack'].has('agent-4')).toBe(false);
278
+ });
279
+ });
280
+
281
+ describe('Error Handling', () => {
282
+ it('should handle LLM errors gracefully', async () => {
283
+ const handler = new TraciaCallbackHandler();
284
+ const mockLLM = { name: 'llm' };
285
+
286
+ await handler.handleLLMStart(mockLLM, ['prompt'], 'error-1');
287
+
288
+ const error = new Error('LLM failed');
289
+ await handler.handleLLMError?.(error, 'error-1');
290
+
291
+ // Span should still be cleaned up
292
+ expect(handler['spanStack'].has('error-1')).toBe(false);
293
+ });
294
+
295
+ it('should handle chain errors gracefully', async () => {
296
+ const handler = new TraciaCallbackHandler();
297
+ const mockChain = { name: 'chain' };
298
+
299
+ await handler.handleChainStart(mockChain, {}, 'error-2');
300
+
301
+ const error = new Error('Chain failed');
302
+ await handler.handleChainError?.(error, 'error-2');
303
+
304
+ expect(handler['spanStack'].has('error-2')).toBe(false);
305
+ });
306
+
307
+ it('should handle tool errors gracefully', async () => {
308
+ const handler = new TraciaCallbackHandler();
309
+ const mockTool = { name: 'tool' };
310
+
311
+ await handler.handleToolStart(mockTool, 'input', 'error-3');
312
+
313
+ const error = new Error('Tool failed');
314
+ await handler.handleToolError?.(error, 'error-3');
315
+
316
+ expect(handler['spanStack'].has('error-3')).toBe(false);
317
+ });
318
+ });
319
+
320
+ describe('Span Nesting', () => {
321
+ it('should handle nested spans (chain containing LLM)', async () => {
322
+ const handler = new TraciaCallbackHandler();
323
+
324
+ // Start chain
325
+ const chain = { name: 'chain' };
326
+ await handler.handleChainStart(chain, {}, 'chain-outer');
327
+
328
+ // Start LLM inside chain
329
+ const llm = { name: 'llm' };
330
+ await handler.handleLLMStart(llm, ['prompt'], 'llm-inner');
331
+
332
+ // Both should exist
333
+ expect(handler['spanStack'].has('chain-outer')).toBe(true);
334
+ expect(handler['spanStack'].has('llm-inner')).toBe(true);
335
+
336
+ // End LLM first
337
+ await handler.handleLLMEnd({ generations: [[{ text: 'response' }]] }, 'llm-inner');
338
+ expect(handler['spanStack'].has('llm-inner')).toBe(false);
339
+
340
+ // Chain should still exist
341
+ expect(handler['spanStack'].has('chain-outer')).toBe(true);
342
+
343
+ // End chain
344
+ await handler.handleChainEnd({ output: 'result' }, 'chain-outer');
345
+ expect(handler['spanStack'].has('chain-outer')).toBe(false);
346
+ });
347
+
348
+ it('should handle multiple concurrent spans', async () => {
349
+ const handler = new TraciaCallbackHandler();
350
+
351
+ // Start multiple spans
352
+ const chain1 = { name: 'chain1' };
353
+ const chain2 = { name: 'chain2' };
354
+
355
+ await handler.handleChainStart(chain1, {}, 'c1');
356
+ await handler.handleChainStart(chain2, {}, 'c2');
357
+
358
+ expect(handler['spanStack'].has('c1')).toBe(true);
359
+ expect(handler['spanStack'].has('c2')).toBe(true);
360
+
361
+ // End one
362
+ await handler.handleChainEnd({ output: 'r1' }, 'c1');
363
+
364
+ // Other should still exist
365
+ expect(handler['spanStack'].has('c1')).toBe(false);
366
+ expect(handler['spanStack'].has('c2')).toBe(true);
367
+ });
368
+ });
369
+
370
+ describe('Integration with Tracer', () => {
371
+ it('should use the SDK tracer', () => {
372
+ const handler = new TraciaCallbackHandler();
373
+ expect(handler['tracer']).toBeDefined();
374
+ });
375
+
376
+ it('should handle unavailable tracer gracefully', async () => {
377
+ const handler = new TraciaCallbackHandler();
378
+
379
+ // Should not throw even if operations fail
380
+ const mockLLM = { name: 'llm' };
381
+ await expect(handler.handleLLMStart(mockLLM, ['prompt'], 'test')).resolves.not.toThrow();
382
+ });
383
+ });
384
+ });