judgeval 0.1.33

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 (51) hide show
  1. package/LICENSE.md +202 -0
  2. package/README.md +340 -0
  3. package/dist/clients.d.ts +7 -0
  4. package/dist/clients.js +78 -0
  5. package/dist/clients.js.map +1 -0
  6. package/dist/common/integrations/langgraph.d.ts +40 -0
  7. package/dist/common/integrations/langgraph.js +444 -0
  8. package/dist/common/integrations/langgraph.js.map +1 -0
  9. package/dist/common/logger-instance.d.ts +3 -0
  10. package/dist/common/logger-instance.js +64 -0
  11. package/dist/common/logger-instance.js.map +1 -0
  12. package/dist/common/logger.d.ts +54 -0
  13. package/dist/common/logger.js +221 -0
  14. package/dist/common/logger.js.map +1 -0
  15. package/dist/common/tracer.d.ts +205 -0
  16. package/dist/common/tracer.js +1035 -0
  17. package/dist/common/tracer.js.map +1 -0
  18. package/dist/constants.d.ts +51 -0
  19. package/dist/constants.js +344 -0
  20. package/dist/constants.js.map +1 -0
  21. package/dist/data/example.d.ts +70 -0
  22. package/dist/data/example.js +125 -0
  23. package/dist/data/example.js.map +1 -0
  24. package/dist/data/result.d.ts +51 -0
  25. package/dist/data/result.js +83 -0
  26. package/dist/data/result.js.map +1 -0
  27. package/dist/evaluation-run.d.ts +44 -0
  28. package/dist/evaluation-run.js +136 -0
  29. package/dist/evaluation-run.js.map +1 -0
  30. package/dist/index.d.ts +10 -0
  31. package/dist/index.js +73 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/judgment-client.d.ts +179 -0
  34. package/dist/judgment-client.js +1038 -0
  35. package/dist/judgment-client.js.map +1 -0
  36. package/dist/rules.d.ts +120 -0
  37. package/dist/rules.js +322 -0
  38. package/dist/rules.js.map +1 -0
  39. package/dist/run-evaluation.d.ts +78 -0
  40. package/dist/run-evaluation.js +618 -0
  41. package/dist/run-evaluation.js.map +1 -0
  42. package/dist/scorers/api-scorer.d.ts +79 -0
  43. package/dist/scorers/api-scorer.js +291 -0
  44. package/dist/scorers/api-scorer.js.map +1 -0
  45. package/dist/scorers/base-scorer.d.ts +100 -0
  46. package/dist/scorers/base-scorer.js +190 -0
  47. package/dist/scorers/base-scorer.js.map +1 -0
  48. package/dist/scorers/exact-match-scorer.d.ts +10 -0
  49. package/dist/scorers/exact-match-scorer.js +84 -0
  50. package/dist/scorers/exact-match-scorer.js.map +1 -0
  51. package/package.json +88 -0
@@ -0,0 +1,1035 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.currentSpanAsyncLocalStorage = exports.currentTraceAsyncLocalStorage = exports.TraceManagerClient = exports.TraceClient = exports.Tracer = exports.wrap = void 0;
16
+ // Core Node.js imports
17
+ const async_hooks_1 = require("async_hooks");
18
+ const uuid_1 = require("uuid");
19
+ // Installed SDKs
20
+ const openai_1 = __importDefault(require("openai"));
21
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
22
+ const together_ai_1 = __importDefault(require("together-ai")); // Use default import
23
+ // Local Imports
24
+ const constants_1 = require("../constants");
25
+ const logger_instance_1 = __importDefault(require("./logger-instance")); // Use the shared winston logger instance
26
+ // --- API Interaction Client ---
27
+ /**
28
+ * Client for interacting with Judgment trace API endpoints.
29
+ */
30
+ class TraceManagerClient {
31
+ constructor(apiKey, organizationId) {
32
+ if (!apiKey) {
33
+ throw new Error("TraceManagerClient requires a Judgment API key.");
34
+ }
35
+ if (!organizationId) {
36
+ throw new Error("TraceManagerClient requires a Judgment Organization ID.");
37
+ }
38
+ this.apiKey = apiKey;
39
+ this.organizationId = organizationId;
40
+ }
41
+ _fetch(url_1) {
42
+ return __awaiter(this, arguments, void 0, function* (url, options = {}) {
43
+ const headers = Object.assign({ 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}`, 'X-Organization-Id': this.organizationId }, (options.headers || {}));
44
+ try {
45
+ // Use isomorphic fetch (available globally in modern Node.js and browsers)
46
+ const response = yield fetch(url, Object.assign(Object.assign({}, options), { headers: headers }));
47
+ if (!response.ok) {
48
+ const errorBody = yield response.text();
49
+ console.error(`API Error (${response.status}) for ${options.method || 'GET'} ${url}: ${errorBody}`);
50
+ throw new Error(`Judgment API request failed: ${response.status} ${response.statusText} - ${errorBody}`);
51
+ }
52
+ // Handle cases where the response might be empty (e.g., 204 No Content on DELETE)
53
+ if (response.status === 204) {
54
+ return null; // Indicate success with no content
55
+ }
56
+ return yield response.json();
57
+ }
58
+ catch (error) {
59
+ console.error(`Network or fetch error during ${options.method || 'GET'} ${url}:`, error);
60
+ // Re-throw or handle as appropriate for the application context
61
+ throw error;
62
+ }
63
+ });
64
+ }
65
+ fetchTrace(traceId) {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ return this._fetch(constants_1.JUDGMENT_TRACES_FETCH_API_URL, {
68
+ method: 'POST',
69
+ body: JSON.stringify({ trace_id: traceId }),
70
+ });
71
+ });
72
+ }
73
+ saveTrace(traceData, emptySave) {
74
+ return __awaiter(this, void 0, void 0, function* () {
75
+ const response = yield this._fetch(constants_1.JUDGMENT_TRACES_SAVE_API_URL, {
76
+ method: 'POST',
77
+ body: JSON.stringify(traceData),
78
+ });
79
+ // Optionally log the UI URL like the Python version
80
+ if (!emptySave && (response === null || response === void 0 ? void 0 : response.ui_results_url)) {
81
+ // Use console.info or a dedicated logger for user-facing messages
82
+ // Note: We can't replicate Rich library's colored link easily in standard console
83
+ console.info(`
84
+ 🔍 View trace: ${response.ui_results_url}
85
+ `);
86
+ }
87
+ return response;
88
+ });
89
+ }
90
+ deleteTrace(traceId) {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ // Assuming DELETE method is correct based on REST principles for the delete endpoint
93
+ return this._fetch(constants_1.JUDGMENT_TRACES_DELETE_API_URL, {
94
+ method: 'DELETE',
95
+ body: JSON.stringify({ trace_ids: [traceId] }),
96
+ });
97
+ });
98
+ }
99
+ deleteTraces(traceIds) {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ return this._fetch(constants_1.JUDGMENT_TRACES_DELETE_API_URL, {
102
+ method: 'DELETE',
103
+ body: JSON.stringify({ trace_ids: traceIds }),
104
+ });
105
+ });
106
+ }
107
+ addTraceToEvalQueue(traceData) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ // Ensure traceData has the necessary structure for the queue endpoint
110
+ return this._fetch(constants_1.JUDGMENT_TRACES_ADD_TO_EVAL_QUEUE_API_URL, {
111
+ method: 'POST',
112
+ body: JSON.stringify(traceData), // Send the full trace data as per Python impl
113
+ });
114
+ });
115
+ }
116
+ }
117
+ exports.TraceManagerClient = TraceManagerClient;
118
+ // --- Context Management ---
119
+ // Holds the active TraceClient instance for the current async context
120
+ const currentTraceAsyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
121
+ exports.currentTraceAsyncLocalStorage = currentTraceAsyncLocalStorage;
122
+ // Holds the ID of the currently active span within a trace
123
+ const currentSpanAsyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
124
+ exports.currentSpanAsyncLocalStorage = currentSpanAsyncLocalStorage;
125
+ // --- Helper Functions ---
126
+ // Helper function to sanitize names (e.g., replace spaces with underscores)
127
+ function sanitizeName(name) {
128
+ // Replace spaces with underscores and remove potentially problematic characters
129
+ // You can adjust the regex further if other characters cause issues.
130
+ return name.replace(/\s+/g, '_').replace(/[^a-zA-Z0-9_.-]/g, '');
131
+ }
132
+ // --- Core Trace Classes ---
133
+ /**
134
+ * Represents an ongoing trace context.
135
+ */
136
+ class TraceClient {
137
+ constructor(config) {
138
+ var _a, _b, _c, _d, _e;
139
+ // Internal state
140
+ this.entries = [];
141
+ this.spanDepths = {};
142
+ this.traceManager = null; // Can be null if monitoring disabled
143
+ this.traceId = config.traceId || (0, uuid_1.v4)();
144
+ this.originalName = config.name || 'default_trace'; // Store original
145
+ this.name = sanitizeName(this.originalName); // Use sanitized name internally
146
+ // If the sanitized name is empty, fallback to a default
147
+ if (!this.name) {
148
+ console.warn(`Original trace name "${this.originalName}" sanitized to empty string. Using default_trace_${this.traceId.substring(0, 8)}.`);
149
+ this.name = `default_trace_${this.traceId.substring(0, 8)}`;
150
+ }
151
+ this.projectName = (_a = config.projectName) !== null && _a !== void 0 ? _a : config.tracer.projectName;
152
+ this.overwrite = (_b = config.overwrite) !== null && _b !== void 0 ? _b : false;
153
+ this.rules = (_c = config.rules) !== null && _c !== void 0 ? _c : [];
154
+ // Determine effective monitoring status based on tracer and API keys
155
+ let effectiveMonitoring = (_d = config.enableMonitoring) !== null && _d !== void 0 ? _d : config.tracer.enableMonitoring;
156
+ if (effectiveMonitoring && (!config.apiKey || !config.organizationId)) {
157
+ console.warn(`TraceClient ${this.traceId}: Monitoring requires JUDGMENT_API_KEY and JUDGMENT_ORG_ID. Disabling monitoring for this trace.`);
158
+ effectiveMonitoring = false;
159
+ }
160
+ this.enableMonitoring = effectiveMonitoring;
161
+ // Evaluations depend on monitoring
162
+ this.enableEvaluations = effectiveMonitoring && ((_e = config.enableEvaluations) !== null && _e !== void 0 ? _e : config.tracer.enableEvaluations);
163
+ this.parentTraceId = config.parentTraceId;
164
+ this.parentName = config.parentName;
165
+ this.apiKey = config.apiKey;
166
+ this.organizationId = config.organizationId;
167
+ this.startTime = Date.now() / 1000;
168
+ if (this.enableMonitoring) {
169
+ this.traceManager = new TraceManagerClient(this.apiKey, this.organizationId);
170
+ }
171
+ }
172
+ addEntry(entry) {
173
+ if (!this.enableMonitoring)
174
+ return;
175
+ entry.timestamp = entry.timestamp || Date.now() / 1000;
176
+ this.entries.push(entry);
177
+ }
178
+ recordInput(inputs) {
179
+ var _a, _b;
180
+ const spanId = currentSpanAsyncLocalStorage.getStore();
181
+ if (!spanId || !this.enableMonitoring)
182
+ return;
183
+ const enterEntry = this.entries.find(e => e.span_id === spanId && e.type === 'enter');
184
+ const functionName = (enterEntry === null || enterEntry === void 0 ? void 0 : enterEntry.function) || 'unknown_function';
185
+ const depth = (_b = (_a = enterEntry === null || enterEntry === void 0 ? void 0 : enterEntry.depth) !== null && _a !== void 0 ? _a : this.spanDepths[spanId]) !== null && _b !== void 0 ? _b : 0;
186
+ const spanType = (enterEntry === null || enterEntry === void 0 ? void 0 : enterEntry.span_type) || 'span';
187
+ this.addEntry({
188
+ type: 'input',
189
+ span_id: spanId,
190
+ inputs,
191
+ function: functionName,
192
+ depth: depth,
193
+ span_type: spanType
194
+ });
195
+ }
196
+ recordOutput(output) {
197
+ var _a, _b, _c;
198
+ const spanId = currentSpanAsyncLocalStorage.getStore();
199
+ if (!spanId || !this.enableMonitoring)
200
+ return;
201
+ const enterEntry = this.entries.find(e => e.span_id === spanId && e.type === 'enter');
202
+ const functionName = (enterEntry === null || enterEntry === void 0 ? void 0 : enterEntry.function) || 'unknown_function';
203
+ const depth = (_b = (_a = enterEntry === null || enterEntry === void 0 ? void 0 : enterEntry.depth) !== null && _a !== void 0 ? _a : this.spanDepths[spanId]) !== null && _b !== void 0 ? _b : 0;
204
+ const spanType = (enterEntry === null || enterEntry === void 0 ? void 0 : enterEntry.span_type) || 'span';
205
+ let entryType = 'output';
206
+ let outputData = output;
207
+ if (output instanceof Error) {
208
+ entryType = 'error';
209
+ outputData = {
210
+ name: output.name,
211
+ message: output.message,
212
+ stack: (_c = output.stack) === null || _c === void 0 ? void 0 : _c.substring(0, 1000)
213
+ };
214
+ }
215
+ else if (output === null || output === void 0 ? void 0 : output.error) {
216
+ entryType = 'error';
217
+ outputData = output;
218
+ }
219
+ this.addEntry({
220
+ type: entryType,
221
+ span_id: spanId,
222
+ output: outputData,
223
+ function: functionName,
224
+ depth: depth,
225
+ span_type: spanType
226
+ });
227
+ }
228
+ runInSpan(name, options, func) {
229
+ return __awaiter(this, void 0, void 0, function* () {
230
+ var _a;
231
+ if (!this.enableMonitoring) {
232
+ const result = func();
233
+ return result instanceof Promise ? yield result : result;
234
+ }
235
+ const startTime = Date.now() / 1000;
236
+ const spanId = (0, uuid_1.v4)();
237
+ const parentSpanId = currentSpanAsyncLocalStorage.getStore();
238
+ const spanType = options.spanType || 'span';
239
+ let currentDepth = 0;
240
+ if (parentSpanId && this.spanDepths[parentSpanId] !== undefined) {
241
+ currentDepth = this.spanDepths[parentSpanId] + 1;
242
+ }
243
+ this.spanDepths[spanId] = currentDepth;
244
+ this.addEntry({
245
+ type: 'enter',
246
+ function: name,
247
+ span_id: spanId,
248
+ depth: currentDepth,
249
+ timestamp: startTime,
250
+ span_type: spanType,
251
+ parent_span_id: parentSpanId
252
+ });
253
+ let result;
254
+ try {
255
+ result = yield currentSpanAsyncLocalStorage.run(spanId, () => __awaiter(this, void 0, void 0, function* () {
256
+ const res = func();
257
+ return res instanceof Promise ? yield res : res;
258
+ }));
259
+ return result;
260
+ }
261
+ catch (error) {
262
+ this.recordOutput({
263
+ error: String(error),
264
+ error_details: error instanceof Error
265
+ ? { name: error.name, message: error.message, stack: (_a = error.stack) === null || _a === void 0 ? void 0 : _a.substring(0, 500) }
266
+ : { detail: String(error) }
267
+ });
268
+ throw error;
269
+ }
270
+ finally {
271
+ const endTime = Date.now() / 1000;
272
+ const duration = endTime - startTime;
273
+ this.addEntry({
274
+ type: 'exit',
275
+ function: name,
276
+ span_id: spanId,
277
+ depth: currentDepth,
278
+ timestamp: endTime,
279
+ duration: duration,
280
+ span_type: spanType
281
+ });
282
+ delete this.spanDepths[spanId];
283
+ }
284
+ });
285
+ }
286
+ getDuration() {
287
+ return (Date.now() / 1000) - this.startTime;
288
+ }
289
+ condenseTrace(rawEntries) {
290
+ var _a, _b, _c, _d, _e;
291
+ const spansById = {};
292
+ for (const entry of rawEntries) {
293
+ const spanId = entry.span_id;
294
+ if (!spanId)
295
+ continue;
296
+ if (!spansById[spanId]) {
297
+ spansById[spanId] = {
298
+ span_id: spanId,
299
+ function: entry.function || 'unknown',
300
+ depth: (_a = entry.depth) !== null && _a !== void 0 ? _a : 0,
301
+ timestamp: (_b = entry.timestamp) !== null && _b !== void 0 ? _b : 0,
302
+ parent_span_id: entry.parent_span_id,
303
+ span_type: entry.span_type || 'span',
304
+ inputs: null,
305
+ output: null,
306
+ evaluation_runs: [],
307
+ duration: null,
308
+ children: []
309
+ };
310
+ }
311
+ const currentSpanData = spansById[spanId];
312
+ switch (entry.type) {
313
+ case 'enter':
314
+ currentSpanData.function = entry.function || currentSpanData.function;
315
+ currentSpanData.depth = (_c = entry.depth) !== null && _c !== void 0 ? _c : currentSpanData.depth;
316
+ currentSpanData.timestamp = (_d = entry.timestamp) !== null && _d !== void 0 ? _d : currentSpanData.timestamp;
317
+ currentSpanData.parent_span_id = entry.parent_span_id;
318
+ currentSpanData.span_type = entry.span_type || currentSpanData.span_type;
319
+ currentSpanData.start_time = entry.timestamp;
320
+ break;
321
+ case 'exit':
322
+ currentSpanData.duration = (_e = entry.duration) !== null && _e !== void 0 ? _e : currentSpanData.duration;
323
+ currentSpanData.end_time = entry.timestamp;
324
+ if (currentSpanData.duration === null && currentSpanData.start_time && currentSpanData.end_time) {
325
+ currentSpanData.duration = currentSpanData.end_time - currentSpanData.start_time;
326
+ }
327
+ break;
328
+ case 'input':
329
+ if (currentSpanData.inputs === null && entry.inputs) {
330
+ currentSpanData.inputs = entry.inputs;
331
+ }
332
+ else if (typeof currentSpanData.inputs === 'object' && typeof entry.inputs === 'object') {
333
+ currentSpanData.inputs = Object.assign(Object.assign({}, currentSpanData.inputs), entry.inputs);
334
+ }
335
+ break;
336
+ case 'output':
337
+ case 'error':
338
+ currentSpanData.output = entry.output;
339
+ break;
340
+ case 'evaluation':
341
+ if (entry.evaluation_runs) {
342
+ currentSpanData.evaluation_runs.push(...entry.evaluation_runs);
343
+ }
344
+ break;
345
+ }
346
+ }
347
+ const spansList = Object.values(spansById).map(span => {
348
+ if (span.duration === null && span.start_time && span.end_time) {
349
+ span.duration = span.end_time - span.start_time;
350
+ }
351
+ delete span.start_time;
352
+ delete span.end_time;
353
+ return span;
354
+ });
355
+ const childrenMap = {};
356
+ const roots = [];
357
+ const spanMap = {};
358
+ const sortedCondensedList = [];
359
+ const visited = new Set();
360
+ for (const span of spansList) {
361
+ spanMap[span.span_id] = span;
362
+ const parentId = span.parent_span_id;
363
+ if (parentId === undefined || parentId === null) {
364
+ roots.push(span);
365
+ }
366
+ else {
367
+ if (!childrenMap[parentId]) {
368
+ childrenMap[parentId] = [];
369
+ }
370
+ childrenMap[parentId].push(span);
371
+ }
372
+ }
373
+ roots.sort((a, b) => a.timestamp - b.timestamp);
374
+ for (const parentId in childrenMap) {
375
+ childrenMap[parentId].sort((a, b) => a.timestamp - b.timestamp);
376
+ }
377
+ function buildFlatListDfs(span) {
378
+ if (visited.has(span.span_id))
379
+ return;
380
+ visited.add(span.span_id);
381
+ sortedCondensedList.push(span);
382
+ const children = childrenMap[span.span_id] || [];
383
+ for (const child of children) {
384
+ buildFlatListDfs(child);
385
+ }
386
+ }
387
+ for (const rootSpan of roots) {
388
+ buildFlatListDfs(rootSpan);
389
+ }
390
+ for (const span of spansList) {
391
+ if (!visited.has(span.span_id)) {
392
+ console.warn(`Orphaned span detected: ${span.span_id}, adding to end of list.`);
393
+ buildFlatListDfs(span);
394
+ }
395
+ }
396
+ return sortedCondensedList;
397
+ }
398
+ save() {
399
+ return __awaiter(this, arguments, void 0, function* (emptySave = false) {
400
+ if (!this.enableMonitoring || !this.traceManager) {
401
+ return null;
402
+ }
403
+ const totalDuration = this.getDuration();
404
+ const condensedEntries = this.condenseTrace(this.entries);
405
+ const tokenCounts = {
406
+ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0,
407
+ prompt_tokens_cost_usd: 0.0, completion_tokens_cost_usd: 0.0, total_cost_usd: 0.0
408
+ };
409
+ condensedEntries.forEach(entry => {
410
+ var _a, _b;
411
+ if (entry.span_type === 'llm' && ((_a = entry.output) === null || _a === void 0 ? void 0 : _a.usage)) {
412
+ const usage = entry.output.usage;
413
+ let promptTokens = 0;
414
+ let completionTokens = 0;
415
+ if (usage.prompt_tokens !== undefined || usage.completion_tokens !== undefined) {
416
+ promptTokens = usage.prompt_tokens || 0;
417
+ completionTokens = usage.completion_tokens || 0;
418
+ }
419
+ else if (usage.input_tokens !== undefined || usage.output_tokens !== undefined) {
420
+ promptTokens = usage.input_tokens || 0;
421
+ completionTokens = usage.output_tokens || 0;
422
+ usage.prompt_tokens = promptTokens;
423
+ usage.completion_tokens = completionTokens;
424
+ delete usage.input_tokens;
425
+ delete usage.output_tokens;
426
+ }
427
+ tokenCounts.prompt_tokens += promptTokens;
428
+ tokenCounts.completion_tokens += completionTokens;
429
+ tokenCounts.total_tokens += usage.total_tokens || (promptTokens + completionTokens);
430
+ const modelName = ((_b = entry.inputs) === null || _b === void 0 ? void 0 : _b.model) || "";
431
+ if (modelName) {
432
+ try {
433
+ const promptCost = 0.0;
434
+ const completionCost = 0.0;
435
+ const callTotalCost = promptCost + completionCost;
436
+ usage.prompt_tokens_cost_usd = promptCost;
437
+ usage.completion_tokens_cost_usd = completionCost;
438
+ usage.total_cost_usd = callTotalCost;
439
+ tokenCounts.prompt_tokens_cost_usd += promptCost;
440
+ tokenCounts.completion_tokens_cost_usd += completionCost;
441
+ tokenCounts.total_cost_usd += callTotalCost;
442
+ }
443
+ catch (e) {
444
+ console.warn(`Error calculating cost for model '${modelName}':`, e);
445
+ usage.prompt_tokens_cost_usd = null;
446
+ usage.completion_tokens_cost_usd = null;
447
+ usage.total_cost_usd = null;
448
+ }
449
+ }
450
+ else {
451
+ usage.prompt_tokens_cost_usd = null;
452
+ usage.completion_tokens_cost_usd = null;
453
+ usage.total_cost_usd = null;
454
+ }
455
+ }
456
+ });
457
+ // Convert rules array to a dictionary (Record<string, Rule>)
458
+ const rulesDict = {};
459
+ this.rules.forEach(rule => {
460
+ var _a;
461
+ // Use rule_id if available, otherwise fallback to name
462
+ const key = (_a = rule.rule_id) !== null && _a !== void 0 ? _a : rule.name;
463
+ rulesDict[key] = rule;
464
+ });
465
+ const traceData = {
466
+ trace_id: this.traceId,
467
+ name: this.name,
468
+ project_name: this.projectName,
469
+ created_at: new Date(this.startTime * 1000).toISOString(),
470
+ duration: totalDuration,
471
+ token_counts: tokenCounts,
472
+ entries: condensedEntries,
473
+ rules: rulesDict,
474
+ empty_save: emptySave,
475
+ overwrite: this.overwrite,
476
+ parent_trace_id: this.parentTraceId,
477
+ parent_name: this.parentName
478
+ };
479
+ try {
480
+ yield this.traceManager.saveTrace(traceData, emptySave);
481
+ logger_instance_1.default.info(`Trace ${this.traceId} saved successfully.`);
482
+ if (!emptySave && this.enableEvaluations) {
483
+ try {
484
+ yield this.traceManager.addTraceToEvalQueue(traceData);
485
+ logger_instance_1.default.info(`Trace ${this.traceId} added to evaluation queue.`);
486
+ }
487
+ catch (evalError) {
488
+ logger_instance_1.default.warn(`Failed to add trace ${this.traceId} to evaluation queue.`, { error: evalError instanceof Error ? evalError.message : String(evalError) });
489
+ }
490
+ }
491
+ return { traceId: this.traceId, traceData };
492
+ }
493
+ catch (error) {
494
+ logger_instance_1.default.error(`Failed to save trace ${this.traceId}.`, { error: error instanceof Error ? error.message : String(error) });
495
+ return null;
496
+ }
497
+ });
498
+ }
499
+ print() {
500
+ if (!this.enableMonitoring) {
501
+ // Keep console.log for direct user output when print() is called
502
+ console.log("Monitoring was disabled. No trace entries recorded.");
503
+ return;
504
+ }
505
+ if (this.entries.length === 0) {
506
+ // Keep console.log for direct user output when print() is called
507
+ console.log("No trace entries recorded.");
508
+ return;
509
+ }
510
+ // Keep console.log for direct user output when print() is called
511
+ console.log(`\n--- Trace Details: ${this.name} (ID: ${this.traceId}) ---`);
512
+ this.entries.forEach(entry => {
513
+ var _a;
514
+ const indent = " ".repeat((_a = entry.depth) !== null && _a !== void 0 ? _a : 0);
515
+ const timeStr = entry.timestamp ? `@ ${new Date(entry.timestamp * 1000).toISOString()}` : '';
516
+ const shortSpanId = entry.span_id ? `(id: ${entry.span_id.substring(0, 8)}...)` : '';
517
+ const shortParentId = entry.parent_span_id ? `(parent: ${entry.parent_span_id.substring(0, 8)}...)` : '';
518
+ try {
519
+ switch (entry.type) {
520
+ case 'enter':
521
+ console.log(`${indent}→ ${entry.function || 'unknown'} ${shortSpanId} ${shortParentId} [${entry.span_type || 'span'}] ${timeStr}`);
522
+ break;
523
+ case 'exit':
524
+ const durationStr = entry.duration !== undefined ? `(${entry.duration.toFixed(3)}s)` : '';
525
+ // Keep console.log
526
+ console.log(`${indent}← ${entry.function || 'unknown'} ${shortSpanId} ${durationStr} ${timeStr}`);
527
+ break;
528
+ case 'input':
529
+ let inputStr = JSON.stringify(entry.inputs);
530
+ if (inputStr && inputStr.length > 200) {
531
+ inputStr = inputStr.substring(0, 197) + '...';
532
+ }
533
+ // Keep console.log
534
+ console.log(`${indent} Input (for ${shortSpanId}): ${inputStr || '{}'}`);
535
+ break;
536
+ case 'output':
537
+ case 'error':
538
+ let outputStr = JSON.stringify(entry.output);
539
+ if (outputStr && outputStr.length > 200) {
540
+ outputStr = outputStr.substring(0, 197) + '...';
541
+ }
542
+ const prefix = entry.type === 'error' ? 'Error' : 'Output';
543
+ // Keep console.log
544
+ console.log(`${indent} ${prefix} (for ${shortSpanId}): ${outputStr || 'null'}`);
545
+ break;
546
+ case 'evaluation':
547
+ let evalStr = JSON.stringify(entry.evaluation_runs);
548
+ if (evalStr && evalStr.length > 200) {
549
+ evalStr = evalStr.substring(0, 197) + '...';
550
+ }
551
+ // Keep console.log
552
+ console.log(`${indent} Evaluation (for ${shortSpanId}): ${evalStr || '[]'}`);
553
+ break;
554
+ default:
555
+ // Keep console.log
556
+ console.log(`${indent}? Unknown entry type: ${JSON.stringify(entry)}`);
557
+ }
558
+ }
559
+ catch (stringifyError) {
560
+ const errorMessage = stringifyError instanceof Error ? stringifyError.message : String(stringifyError);
561
+ // Keep console.log
562
+ console.log(`${indent}! Error formatting entry: ${errorMessage}`);
563
+ console.log(`${indent} Raw entry:`, entry);
564
+ }
565
+ });
566
+ // Keep console.log
567
+ console.log(`--- End Trace: ${this.name} ---`);
568
+ }
569
+ delete() {
570
+ return __awaiter(this, void 0, void 0, function* () {
571
+ if (!this.enableMonitoring || !this.traceManager) {
572
+ logger_instance_1.default.warn(`Cannot delete trace ${this.traceId}, monitoring disabled or manager missing.`);
573
+ return null;
574
+ }
575
+ try {
576
+ const result = yield this.traceManager.deleteTrace(this.traceId);
577
+ logger_instance_1.default.info(`Trace ${this.traceId} deleted successfully.`);
578
+ return result;
579
+ }
580
+ catch (error) {
581
+ logger_instance_1.default.error(`Failed to delete trace ${this.traceId}.`, { error: error instanceof Error ? error.message : String(error) });
582
+ throw error; // Re-throw after logging
583
+ }
584
+ });
585
+ }
586
+ /**
587
+ * Asynchronously evaluate an example using the provided scorers,
588
+ * embedding the evaluation request into the trace data.
589
+ * Ported from the Python SDK's async_evaluate method.
590
+ *
591
+ * @param scorers Array of scorers to use for evaluation (currently assumes APIJudgmentScorer)
592
+ * @param options Evaluation options including input, outputs, and metadata
593
+ * @returns Promise that resolves when the evaluation entry has been added to the trace
594
+ */
595
+ asyncEvaluate(scorers_1) {
596
+ return __awaiter(this, arguments, void 0, function* (
597
+ // TODO: Allow JudgevalScorer type if rules are not used?
598
+ scorers, options = {}) {
599
+ var _a;
600
+ if (!this.enableEvaluations) {
601
+ logger_instance_1.default.warn("Evaluations are disabled. Skipping async evaluation.");
602
+ return;
603
+ }
604
+ if (!scorers || scorers.length === 0) {
605
+ logger_instance_1.default.warn("No scorers provided. Skipping async evaluation.");
606
+ return;
607
+ }
608
+ const startTime = Date.now() / 1000; // Record start time in seconds
609
+ // Create example structure matching Python/backend expectations
610
+ const example = {
611
+ input: options.input || "",
612
+ actual_output: options.actualOutput || "",
613
+ expected_output: options.expectedOutput || "",
614
+ context: options.context || [],
615
+ retrieval_context: options.retrievalContext || [],
616
+ tools_called: options.toolsCalled || [],
617
+ expected_tools: options.expectedTools || [],
618
+ additional_metadata: options.additionalMetadata || {},
619
+ trace_id: this.traceId
620
+ };
621
+ try {
622
+ // Get the current span ID from the context
623
+ const currentSpanId = currentSpanAsyncLocalStorage.getStore();
624
+ if (!currentSpanId) {
625
+ logger_instance_1.default.warn("No active span found for async evaluation. Evaluation will not be associated with a specific step.");
626
+ // Decide if we should proceed or return. For now, proceed without span association.
627
+ // return;
628
+ }
629
+ // Determine function name and depth (best effort if spanId is missing)
630
+ let functionName = "unknown_function";
631
+ let entrySpanType = "evaluation";
632
+ let currentDepth = 0;
633
+ if (currentSpanId) {
634
+ currentDepth = (_a = this.spanDepths[currentSpanId]) !== null && _a !== void 0 ? _a : 0;
635
+ for (let i = this.entries.length - 1; i >= 0; i--) {
636
+ const entry = this.entries[i];
637
+ if (entry.span_id === currentSpanId && entry.type === 'enter') {
638
+ functionName = entry.function || "unknown_function";
639
+ // Keep span_type as 'evaluation' for the entry itself
640
+ break;
641
+ }
642
+ }
643
+ }
644
+ // --- Create evaluation run name (similar to Python) ---
645
+ // Capitalize scorer names
646
+ const scorerNames = scorers.map(scorer => {
647
+ var _a;
648
+ // Attempt to get score_type, fallback to class name or Unknown
649
+ const name = (scorer === null || scorer === void 0 ? void 0 : scorer.scoreType) || ((_a = scorer === null || scorer === void 0 ? void 0 : scorer.constructor) === null || _a === void 0 ? void 0 : _a.name) || "Unknown";
650
+ return name.charAt(0).toUpperCase() + name.slice(1);
651
+ }).join(',');
652
+ // Use trace name and shortened span ID (or trace ID if no span)
653
+ const idPart = currentSpanId ? currentSpanId.substring(0, 8) : this.traceId.substring(0, 8);
654
+ const evalName = `${this.name.charAt(0).toUpperCase() + this.name.slice(1)}-${idPart}-[${scorerNames}]`;
655
+ // --- End eval name creation ---
656
+ // Process rules (currently just using this.rules directly)
657
+ const loadedRules = this.rules; // TODO: Add ScorerWrapper-like processing if needed in TS
658
+ // Construct the evaluation payload
659
+ const evalRunPayload = {
660
+ organization_id: this.organizationId,
661
+ log_results: options.logResults !== false, // Default to true
662
+ project_name: this.projectName,
663
+ eval_name: evalName,
664
+ examples: [example],
665
+ scorers: scorers, // Pass scorers directly
666
+ model: options.model || "",
667
+ metadata: {}, // Matches Python tracer
668
+ judgment_api_key: this.apiKey,
669
+ override: this.overwrite, // Use trace's overwrite setting
670
+ rules: loadedRules // Pass the processed rules
671
+ };
672
+ // Add evaluation entry using the helper method
673
+ this._addEvalRun(evalRunPayload, startTime);
674
+ }
675
+ catch (error) {
676
+ console.error(`Failed during asyncEvaluate execution: ${error instanceof Error ? error.message : String(error)}`);
677
+ // Decide if we should re-throw or just log
678
+ }
679
+ });
680
+ }
681
+ /**
682
+ * Private helper to add an evaluation entry to the trace.
683
+ * This mirrors the structure of Python's add_eval_run.
684
+ *
685
+ * @param evalRunPayload The constructed payload for the evaluation.
686
+ * @param startTime The start time (in seconds) of the evaluation process.
687
+ */
688
+ _addEvalRun(evalRunPayload, startTime) {
689
+ var _a;
690
+ const currentSpanId = currentSpanAsyncLocalStorage.getStore();
691
+ if (!currentSpanId) {
692
+ // If no span ID, the evaluation entry won't be linked to a specific span
693
+ // This might happen if asyncEvaluate is called outside a runInSpan context
694
+ console.warn("Adding evaluation entry without an active span ID.");
695
+ }
696
+ let functionName = "unknown_function";
697
+ let currentDepth = 0; // Default depth if no span
698
+ if (currentSpanId) {
699
+ currentDepth = (_a = this.spanDepths[currentSpanId]) !== null && _a !== void 0 ? _a : 0;
700
+ // Find the function name associated with the current span_id
701
+ for (let i = this.entries.length - 1; i >= 0; i--) {
702
+ const entry = this.entries[i];
703
+ if (entry.span_id === currentSpanId && entry.type === 'enter') {
704
+ functionName = entry.function || "unknown_function";
705
+ break;
706
+ }
707
+ }
708
+ }
709
+ const duration = (Date.now() / 1000) - startTime;
710
+ // Add evaluation entry to the trace
711
+ this.addEntry({
712
+ type: "evaluation",
713
+ function: functionName,
714
+ span_id: currentSpanId, // May be undefined
715
+ depth: currentDepth,
716
+ timestamp: Date.now() / 1000,
717
+ evaluation_runs: [evalRunPayload], // Embed the payload
718
+ duration: duration,
719
+ span_type: "evaluation"
720
+ });
721
+ }
722
+ // OPTIONAL: Add a method to get the original name if needed elsewhere
723
+ getOriginalName() {
724
+ return this.originalName;
725
+ }
726
+ }
727
+ exports.TraceClient = TraceClient;
728
+ /**
729
+ * Singleton Tracer class. Manages overall tracing configuration and trace creation.
730
+ */
731
+ class Tracer {
732
+ constructor(config) {
733
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
734
+ this.initialized = false;
735
+ const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
736
+ const envApiKey = isNode ? (_a = process.env) === null || _a === void 0 ? void 0 : _a.JUDGMENT_API_KEY : undefined;
737
+ const envOrgId = isNode ? (_b = process.env) === null || _b === void 0 ? void 0 : _b.JUDGMENT_ORG_ID : undefined;
738
+ const envProjectName = isNode ? (_c = process.env) === null || _c === void 0 ? void 0 : _c.JUDGMENT_PROJECT_NAME : undefined;
739
+ const envMonitoring = isNode ? (_d = process.env) === null || _d === void 0 ? void 0 : _d.JUDGMENT_MONITORING : 'true';
740
+ const envEvaluations = isNode ? (_e = process.env) === null || _e === void 0 ? void 0 : _e.JUDGMENT_EVALUATIONS : 'true';
741
+ this.apiKey = (_g = (_f = config === null || config === void 0 ? void 0 : config.apiKey) !== null && _f !== void 0 ? _f : envApiKey) !== null && _g !== void 0 ? _g : '';
742
+ this.organizationId = (_j = (_h = config === null || config === void 0 ? void 0 : config.organizationId) !== null && _h !== void 0 ? _h : envOrgId) !== null && _j !== void 0 ? _j : '';
743
+ this.projectName = (_l = (_k = config === null || config === void 0 ? void 0 : config.projectName) !== null && _k !== void 0 ? _k : envProjectName) !== null && _l !== void 0 ? _l : 'default_project';
744
+ this.defaultRules = (_m = config === null || config === void 0 ? void 0 : config.rules) !== null && _m !== void 0 ? _m : [];
745
+ let effectiveMonitoring = (_o = config === null || config === void 0 ? void 0 : config.enableMonitoring) !== null && _o !== void 0 ? _o : ((envMonitoring === null || envMonitoring === void 0 ? void 0 : envMonitoring.toLowerCase()) !== 'false');
746
+ if (effectiveMonitoring && (!this.apiKey || !this.organizationId)) {
747
+ console.warn("JUDGMENT_API_KEY or JUDGMENT_ORG_ID missing. Monitoring disabled.");
748
+ effectiveMonitoring = false;
749
+ }
750
+ this.enableMonitoring = effectiveMonitoring;
751
+ this.enableEvaluations = effectiveMonitoring && ((_p = config === null || config === void 0 ? void 0 : config.enableEvaluations) !== null && _p !== void 0 ? _p : ((envEvaluations === null || envEvaluations === void 0 ? void 0 : envEvaluations.toLowerCase()) !== 'false'));
752
+ this.initialized = true;
753
+ }
754
+ static getInstance(config) {
755
+ if (!Tracer.instance) {
756
+ Tracer.instance = new Tracer(config);
757
+ }
758
+ else if (config && !Tracer.instance.initialized) {
759
+ console.warn("Tracer getInstance called with config after implicit initialization. Re-initializing.");
760
+ Tracer.instance = new Tracer(config);
761
+ }
762
+ else if (config && Tracer.instance.initialized) {
763
+ if (config.projectName && config.projectName !== Tracer.instance.projectName) {
764
+ console.warn(`Attempting to re-initialize Tracer with different project_name. Original will be used: '${Tracer.instance.projectName}'.`);
765
+ }
766
+ if (config.rules && config.rules.length > 0 && Tracer.instance.defaultRules.length === 0) {
767
+ try {
768
+ console.warn("Setting default rules on Tracer instance after initial creation.");
769
+ Tracer.instance.defaultRules = config.rules;
770
+ }
771
+ catch (e) {
772
+ console.error("Failed to set default rules after tracer initialization:", e);
773
+ }
774
+ }
775
+ else if (config.rules && JSON.stringify(config.rules) !== JSON.stringify(Tracer.instance.defaultRules)) {
776
+ console.warn("Attempting to change default rules on Tracer after initialization. Original rules will be used.");
777
+ }
778
+ }
779
+ return Tracer.instance;
780
+ }
781
+ getCurrentTrace() {
782
+ return currentTraceAsyncLocalStorage.getStore();
783
+ }
784
+ _startTraceInternal(config) {
785
+ var _a, _b;
786
+ const parentTrace = this.getCurrentTrace();
787
+ const traceSpecificRules = (_a = config.rules) !== null && _a !== void 0 ? _a : [];
788
+ const effectiveRulesMap = new Map();
789
+ this.defaultRules.forEach(rule => { var _a; return effectiveRulesMap.set((_a = rule.rule_id) !== null && _a !== void 0 ? _a : rule.name, rule); });
790
+ traceSpecificRules.forEach(rule => { var _a; return effectiveRulesMap.set((_a = rule.rule_id) !== null && _a !== void 0 ? _a : rule.name, rule); });
791
+ const effectiveRules = Array.from(effectiveRulesMap.values());
792
+ const traceClient = new TraceClient({
793
+ tracer: this,
794
+ name: config.name,
795
+ projectName: (_b = config.projectName) !== null && _b !== void 0 ? _b : this.projectName,
796
+ overwrite: config.overwrite,
797
+ rules: effectiveRules,
798
+ enableMonitoring: this.enableMonitoring,
799
+ enableEvaluations: this.enableEvaluations,
800
+ parentTraceId: parentTrace === null || parentTrace === void 0 ? void 0 : parentTrace.traceId,
801
+ parentName: parentTrace === null || parentTrace === void 0 ? void 0 : parentTrace.name,
802
+ apiKey: this.apiKey,
803
+ organizationId: this.organizationId,
804
+ });
805
+ if (traceClient.enableMonitoring) {
806
+ traceClient.save(true).catch(err => {
807
+ console.error(`>>> Tracer: Error saving empty trace for ${traceClient.traceId}:`, err);
808
+ });
809
+ }
810
+ return traceClient;
811
+ }
812
+ runInTrace(config, func) {
813
+ return __awaiter(this, void 0, void 0, function* () {
814
+ var _a;
815
+ const traceClient = this._startTraceInternal(config);
816
+ const shouldCreateRootSpan = (_a = config.createRootSpan) !== null && _a !== void 0 ? _a : true;
817
+ return yield currentTraceAsyncLocalStorage.run(traceClient, () => __awaiter(this, void 0, void 0, function* () {
818
+ let result;
819
+ try {
820
+ if (shouldCreateRootSpan) {
821
+ result = yield traceClient.runInSpan(config.name, { spanType: 'chain' }, () => __awaiter(this, void 0, void 0, function* () {
822
+ const funcResult = func(traceClient);
823
+ return funcResult instanceof Promise ? yield funcResult : funcResult;
824
+ }));
825
+ }
826
+ else {
827
+ const funcResult = func(traceClient);
828
+ result = funcResult instanceof Promise ? yield funcResult : funcResult;
829
+ }
830
+ if (traceClient.enableMonitoring) {
831
+ yield traceClient.save(false).catch(saveErr => {
832
+ console.error(`Failed to save completed trace '${config.name}' (${traceClient.traceId}):`, saveErr);
833
+ });
834
+ }
835
+ return result;
836
+ }
837
+ catch (error) {
838
+ console.error(`Error during traced execution of '${config.name}' (${traceClient.traceId}):`, error);
839
+ if (traceClient.enableMonitoring) {
840
+ yield traceClient.save(false).catch(saveErr => {
841
+ console.error(`Failed to save trace '${config.name}' after error:`, saveErr);
842
+ });
843
+ }
844
+ throw error;
845
+ }
846
+ }));
847
+ });
848
+ }
849
+ observe(options) {
850
+ if (!this.enableMonitoring) {
851
+ return (func) => func;
852
+ }
853
+ return (func) => {
854
+ const spanName = (options === null || options === void 0 ? void 0 : options.name) || func.name || 'anonymous_function';
855
+ const spanType = (options === null || options === void 0 ? void 0 : options.spanType) || 'span';
856
+ const wrapper = (...args) => {
857
+ const currentTrace = this.getCurrentTrace();
858
+ if (!currentTrace) {
859
+ return this.runInTrace({
860
+ name: spanName,
861
+ createRootSpan: false
862
+ }, (traceClient) => __awaiter(this, void 0, void 0, function* () {
863
+ const executionLogic = () => {
864
+ const result = func(...args);
865
+ return result instanceof Promise ? result : Promise.resolve(result);
866
+ };
867
+ return traceClient.runInSpan(spanName, { spanType }, () => __awaiter(this, void 0, void 0, function* () {
868
+ const serializableArgs = args.map(arg => { try {
869
+ return JSON.parse(JSON.stringify(arg));
870
+ }
871
+ catch (_a) {
872
+ return String(arg);
873
+ } });
874
+ traceClient.recordInput({ args: serializableArgs });
875
+ try {
876
+ const finalResult = yield executionLogic();
877
+ traceClient.recordOutput(finalResult);
878
+ return finalResult;
879
+ }
880
+ catch (error) {
881
+ console.error(`Error captured by observe decorator (root) in span '${spanName}':`, error);
882
+ throw error;
883
+ }
884
+ }));
885
+ }));
886
+ }
887
+ else {
888
+ const executionLogic = () => {
889
+ const result = func(...args);
890
+ return result instanceof Promise ? result : Promise.resolve(result);
891
+ };
892
+ return currentTrace.runInSpan(spanName, { spanType }, () => __awaiter(this, void 0, void 0, function* () {
893
+ const serializableArgs = args.map(arg => { try {
894
+ return JSON.parse(JSON.stringify(arg));
895
+ }
896
+ catch (_a) {
897
+ return String(arg);
898
+ } });
899
+ currentTrace.recordInput({ args: serializableArgs });
900
+ try {
901
+ const finalResult = yield executionLogic();
902
+ currentTrace.recordOutput(finalResult);
903
+ return finalResult;
904
+ }
905
+ catch (error) {
906
+ console.error(`Error captured by observe decorator (nested) in span '${spanName}':`, error);
907
+ throw error;
908
+ }
909
+ }));
910
+ }
911
+ };
912
+ Object.defineProperty(wrapper, 'name', { value: func.name, configurable: true });
913
+ return wrapper;
914
+ };
915
+ }
916
+ }
917
+ exports.Tracer = Tracer;
918
+ // --- Helper Functions for Wrapping LLM Clients --- //
919
+ function _getClientConfig(client) {
920
+ var _a, _b, _c, _d, _e;
921
+ if (client instanceof openai_1.default && typeof ((_b = (_a = client === null || client === void 0 ? void 0 : client.chat) === null || _a === void 0 ? void 0 : _a.completions) === null || _b === void 0 ? void 0 : _b.create) === 'function') {
922
+ return { spanName: "OPENAI_API_CALL", originalMethod: client.chat.completions.create.bind(client.chat.completions) };
923
+ }
924
+ else if (client instanceof sdk_1.default && typeof ((_c = client === null || client === void 0 ? void 0 : client.messages) === null || _c === void 0 ? void 0 : _c.create) === 'function') {
925
+ return { spanName: "ANTHROPIC_API_CALL", originalMethod: client.messages.create.bind(client.messages) };
926
+ }
927
+ // Use type assertion for older Together AI version
928
+ else if (client instanceof together_ai_1.default && typeof ((_d = client === null || client === void 0 ? void 0 : client.completions) === null || _d === void 0 ? void 0 : _d.create) === 'function') {
929
+ return { spanName: "TOGETHER_API_CALL", originalMethod: client.completions.create.bind(client.completions) };
930
+ }
931
+ logger_instance_1.default.warn("Cannot wrap client: Unsupported type or incompatible SDK structure.", { clientType: (_e = client === null || client === void 0 ? void 0 : client.constructor) === null || _e === void 0 ? void 0 : _e.name });
932
+ return null;
933
+ }
934
+ function _formatInputData(client, args) {
935
+ const params = args[0] || {};
936
+ try {
937
+ // Handle Together client potentially having different input structure
938
+ if (client instanceof openai_1.default || client instanceof together_ai_1.default) {
939
+ return { model: params.model, messages: params.messages, /* other potential params */ };
940
+ }
941
+ else if (client instanceof sdk_1.default) {
942
+ return { model: params.model, messages: params.messages, max_tokens: params.max_tokens, };
943
+ }
944
+ }
945
+ catch (e) {
946
+ logger_instance_1.default.error("Error formatting LLM input:", { error: e instanceof Error ? e.message : String(e), params });
947
+ return { raw_params: params };
948
+ }
949
+ return { raw_params: params };
950
+ }
951
+ function _formatOutputData(client, response) {
952
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
953
+ try {
954
+ // Separate handling for OpenAI and Together, assuming Together might differ
955
+ if (client instanceof openai_1.default && ((_b = (_a = response === null || response === void 0 ? void 0 : response.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message)) {
956
+ const message = response.choices[0].message;
957
+ return { content: message.content, usage: response.usage, };
958
+ }
959
+ else if (client instanceof together_ai_1.default && ((_d = (_c = response === null || response === void 0 ? void 0 : response.choices) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.message)) {
960
+ // Assume Together v0.5.1 has a similar structure for now, but access defensively
961
+ const message = response.choices[0].message;
962
+ return { content: message === null || message === void 0 ? void 0 : message.content, usage: response === null || response === void 0 ? void 0 : response.usage, }; // Optional chaining for safety
963
+ }
964
+ else if (client instanceof sdk_1.default && ((_e = response === null || response === void 0 ? void 0 : response.content) === null || _e === void 0 ? void 0 : _e[0])) {
965
+ const textContent = response.content.filter((block) => block.type === 'text').map((block) => block.text).join('');
966
+ // Reconstruct usage for Anthropic if needed
967
+ const usage = {
968
+ input_tokens: (_f = response.usage) === null || _f === void 0 ? void 0 : _f.input_tokens,
969
+ output_tokens: (_g = response.usage) === null || _g === void 0 ? void 0 : _g.output_tokens,
970
+ total_tokens: (((_h = response.usage) === null || _h === void 0 ? void 0 : _h.input_tokens) || 0) + (((_j = response.usage) === null || _j === void 0 ? void 0 : _j.output_tokens) || 0)
971
+ };
972
+ return { content: textContent, usage: usage, };
973
+ }
974
+ }
975
+ catch (e) {
976
+ logger_instance_1.default.error("Error formatting LLM output:", { error: e instanceof Error ? e.message : String(e) });
977
+ return { formatting_error: String(e), raw_response: response };
978
+ }
979
+ // Return raw if structure doesn't match known patterns
980
+ return { raw_response: response };
981
+ }
982
+ // --- The Wrap Function --- //
983
+ function wrap(client) {
984
+ var _a, _b, _c;
985
+ const tracer = Tracer.getInstance();
986
+ if (!tracer.enableMonitoring) {
987
+ logger_instance_1.default.info("Global monitoring disabled, client wrapping skipped.");
988
+ return client;
989
+ }
990
+ const config = _getClientConfig(client);
991
+ if (!config) {
992
+ return client;
993
+ }
994
+ const { spanName, originalMethod } = config;
995
+ const tracedMethod = (...args) => __awaiter(this, void 0, void 0, function* () {
996
+ const currentTrace = tracer.getCurrentTrace();
997
+ if (!currentTrace || !currentTrace.enableMonitoring) {
998
+ return originalMethod(...args);
999
+ }
1000
+ return yield currentTrace.runInSpan(spanName, { spanType: 'llm' }, () => __awaiter(this, void 0, void 0, function* () {
1001
+ const inputData = _formatInputData(client, args);
1002
+ currentTrace.recordInput(inputData);
1003
+ try {
1004
+ const response = yield originalMethod(...args);
1005
+ const outputData = _formatOutputData(client, response);
1006
+ currentTrace.recordOutput(outputData);
1007
+ return response;
1008
+ }
1009
+ catch (error) {
1010
+ currentTrace.recordOutput(error); // Record error object in output
1011
+ throw error;
1012
+ }
1013
+ }));
1014
+ });
1015
+ // Apply the wrapper
1016
+ if (client instanceof openai_1.default && ((_a = client.chat) === null || _a === void 0 ? void 0 : _a.completions)) {
1017
+ client.chat.completions.create = tracedMethod;
1018
+ }
1019
+ else if (client instanceof sdk_1.default && client.messages) {
1020
+ client.messages.create = tracedMethod;
1021
+ }
1022
+ // Use type assertion for older Together AI version
1023
+ else if (client instanceof together_ai_1.default && client.completions) {
1024
+ client.completions.create = tracedMethod;
1025
+ }
1026
+ else {
1027
+ // Log if we couldn't apply the wrapper despite getting a config
1028
+ logger_instance_1.default.error("Failed to apply wrapper: Could not find method to replace after config check.", { clientType: (_b = client === null || client === void 0 ? void 0 : client.constructor) === null || _b === void 0 ? void 0 : _b.name });
1029
+ return client;
1030
+ }
1031
+ logger_instance_1.default.info(`Successfully wrapped client: ${(_c = client === null || client === void 0 ? void 0 : client.constructor) === null || _c === void 0 ? void 0 : _c.name}`);
1032
+ return client;
1033
+ }
1034
+ exports.wrap = wrap;
1035
+ //# sourceMappingURL=tracer.js.map