@evalgate/sdk 2.0.0

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 (141) hide show
  1. package/CHANGELOG.md +638 -0
  2. package/README.md +398 -0
  3. package/dist/assertions.d.ts +189 -0
  4. package/dist/assertions.js +662 -0
  5. package/dist/batch.d.ts +68 -0
  6. package/dist/batch.js +179 -0
  7. package/dist/cache.d.ts +65 -0
  8. package/dist/cache.js +131 -0
  9. package/dist/cli/api.d.ts +108 -0
  10. package/dist/cli/api.js +132 -0
  11. package/dist/cli/baseline.d.ts +10 -0
  12. package/dist/cli/baseline.js +172 -0
  13. package/dist/cli/check.d.ts +73 -0
  14. package/dist/cli/check.js +355 -0
  15. package/dist/cli/ci-context.d.ts +6 -0
  16. package/dist/cli/ci-context.js +112 -0
  17. package/dist/cli/ci.d.ts +45 -0
  18. package/dist/cli/ci.js +192 -0
  19. package/dist/cli/config.d.ts +30 -0
  20. package/dist/cli/config.js +230 -0
  21. package/dist/cli/constants.d.ts +15 -0
  22. package/dist/cli/constants.js +18 -0
  23. package/dist/cli/diff.d.ts +173 -0
  24. package/dist/cli/diff.js +685 -0
  25. package/dist/cli/discover.d.ts +84 -0
  26. package/dist/cli/discover.js +419 -0
  27. package/dist/cli/doctor.d.ts +88 -0
  28. package/dist/cli/doctor.js +675 -0
  29. package/dist/cli/env.d.ts +21 -0
  30. package/dist/cli/env.js +42 -0
  31. package/dist/cli/explain.d.ts +58 -0
  32. package/dist/cli/explain.js +561 -0
  33. package/dist/cli/formatters/github.d.ts +8 -0
  34. package/dist/cli/formatters/github.js +135 -0
  35. package/dist/cli/formatters/human.d.ts +6 -0
  36. package/dist/cli/formatters/human.js +110 -0
  37. package/dist/cli/formatters/json.d.ts +6 -0
  38. package/dist/cli/formatters/json.js +10 -0
  39. package/dist/cli/formatters/pr-comment.d.ts +12 -0
  40. package/dist/cli/formatters/pr-comment.js +103 -0
  41. package/dist/cli/formatters/types.d.ts +103 -0
  42. package/dist/cli/formatters/types.js +8 -0
  43. package/dist/cli/gate.d.ts +21 -0
  44. package/dist/cli/gate.js +179 -0
  45. package/dist/cli/impact-analysis.d.ts +63 -0
  46. package/dist/cli/impact-analysis.js +252 -0
  47. package/dist/cli/index.d.ts +9 -0
  48. package/dist/cli/index.js +332 -0
  49. package/dist/cli/init.d.ts +16 -0
  50. package/dist/cli/init.js +292 -0
  51. package/dist/cli/manifest.d.ts +103 -0
  52. package/dist/cli/manifest.js +282 -0
  53. package/dist/cli/migrate.d.ts +41 -0
  54. package/dist/cli/migrate.js +349 -0
  55. package/dist/cli/policy-packs.d.ts +23 -0
  56. package/dist/cli/policy-packs.js +89 -0
  57. package/dist/cli/print-config.d.ts +29 -0
  58. package/dist/cli/print-config.js +270 -0
  59. package/dist/cli/profiles.d.ts +28 -0
  60. package/dist/cli/profiles.js +30 -0
  61. package/dist/cli/reason-codes.d.ts +17 -0
  62. package/dist/cli/reason-codes.js +19 -0
  63. package/dist/cli/regression-gate.d.ts +15 -0
  64. package/dist/cli/regression-gate.js +341 -0
  65. package/dist/cli/render/snippet.d.ts +5 -0
  66. package/dist/cli/render/snippet.js +15 -0
  67. package/dist/cli/render/sort.d.ts +10 -0
  68. package/dist/cli/render/sort.js +24 -0
  69. package/dist/cli/report/build-check-report.d.ts +19 -0
  70. package/dist/cli/report/build-check-report.js +132 -0
  71. package/dist/cli/run.d.ts +101 -0
  72. package/dist/cli/run.js +395 -0
  73. package/dist/cli/share.d.ts +17 -0
  74. package/dist/cli/share.js +91 -0
  75. package/dist/cli/upgrade.d.ts +15 -0
  76. package/dist/cli/upgrade.js +492 -0
  77. package/dist/cli/workspace.d.ts +31 -0
  78. package/dist/cli/workspace.js +68 -0
  79. package/dist/client.d.ts +368 -0
  80. package/dist/client.js +893 -0
  81. package/dist/client.request.test.d.ts +1 -0
  82. package/dist/client.request.test.js +232 -0
  83. package/dist/context.d.ts +134 -0
  84. package/dist/context.js +215 -0
  85. package/dist/errors.d.ts +82 -0
  86. package/dist/errors.js +298 -0
  87. package/dist/export.d.ts +195 -0
  88. package/dist/export.js +344 -0
  89. package/dist/index.d.ts +44 -0
  90. package/dist/index.js +153 -0
  91. package/dist/integrations/anthropic.d.ts +91 -0
  92. package/dist/integrations/anthropic.js +163 -0
  93. package/dist/integrations/openai-eval.d.ts +57 -0
  94. package/dist/integrations/openai-eval.js +232 -0
  95. package/dist/integrations/openai.d.ts +92 -0
  96. package/dist/integrations/openai.js +160 -0
  97. package/dist/local.d.ts +39 -0
  98. package/dist/local.js +148 -0
  99. package/dist/logger.d.ts +128 -0
  100. package/dist/logger.js +227 -0
  101. package/dist/matchers/index.d.ts +1 -0
  102. package/dist/matchers/index.js +6 -0
  103. package/dist/matchers/to-pass-gate.d.ts +29 -0
  104. package/dist/matchers/to-pass-gate.js +35 -0
  105. package/dist/pagination.d.ts +74 -0
  106. package/dist/pagination.js +139 -0
  107. package/dist/regression.d.ts +100 -0
  108. package/dist/regression.js +44 -0
  109. package/dist/runtime/adapters/config-to-dsl.d.ts +33 -0
  110. package/dist/runtime/adapters/config-to-dsl.js +400 -0
  111. package/dist/runtime/adapters/testsuite-to-dsl.d.ts +63 -0
  112. package/dist/runtime/adapters/testsuite-to-dsl.js +276 -0
  113. package/dist/runtime/context.d.ts +26 -0
  114. package/dist/runtime/context.js +74 -0
  115. package/dist/runtime/eval.d.ts +46 -0
  116. package/dist/runtime/eval.js +244 -0
  117. package/dist/runtime/execution-mode.d.ts +80 -0
  118. package/dist/runtime/execution-mode.js +357 -0
  119. package/dist/runtime/executor.d.ts +16 -0
  120. package/dist/runtime/executor.js +152 -0
  121. package/dist/runtime/registry.d.ts +78 -0
  122. package/dist/runtime/registry.js +403 -0
  123. package/dist/runtime/run-report.d.ts +200 -0
  124. package/dist/runtime/run-report.js +222 -0
  125. package/dist/runtime/types.d.ts +356 -0
  126. package/dist/runtime/types.js +76 -0
  127. package/dist/snapshot.d.ts +176 -0
  128. package/dist/snapshot.js +322 -0
  129. package/dist/streaming.d.ts +173 -0
  130. package/dist/streaming.js +268 -0
  131. package/dist/testing.d.ts +273 -0
  132. package/dist/testing.js +317 -0
  133. package/dist/types.d.ts +754 -0
  134. package/dist/types.js +54 -0
  135. package/dist/utils/input-hash.d.ts +8 -0
  136. package/dist/utils/input-hash.js +41 -0
  137. package/dist/version.d.ts +7 -0
  138. package/dist/version.js +10 -0
  139. package/dist/workflows.d.ts +389 -0
  140. package/dist/workflows.js +671 -0
  141. package/package.json +117 -0
@@ -0,0 +1,671 @@
1
+ "use strict";
2
+ /**
3
+ * Workflow Tracer SDK
4
+ * Multi-agent workflow instrumentation, decision tracking, and cost capture
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { WorkflowTracer } from '@evalgate/sdk';
9
+ *
10
+ * const tracer = new WorkflowTracer(client, { organizationId: 123 });
11
+ *
12
+ * // Start a workflow
13
+ * const workflow = await tracer.startWorkflow('Customer Support Pipeline');
14
+ *
15
+ * // Record agent spans and handoffs
16
+ * const span1 = await tracer.startAgentSpan('RouterAgent', { input: query });
17
+ * await tracer.recordDecision({
18
+ * agent: 'RouterAgent',
19
+ * chosen: 'delegate_to_technical',
20
+ * alternatives: [{ action: 'delegate_to_billing', confidence: 0.3 }],
21
+ * reasoning: 'Query contains technical keywords'
22
+ * });
23
+ * await tracer.recordHandoff('RouterAgent', 'TechnicalAgent', { issue: 'API error' });
24
+ * await tracer.endAgentSpan(span1, { result: 'delegated' });
25
+ *
26
+ * // End workflow with final output
27
+ * await tracer.endWorkflow({ resolution: 'Issue resolved' });
28
+ * ```
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.WorkflowTracer = void 0;
32
+ exports.traceLangChainAgent = traceLangChainAgent;
33
+ exports.traceCrewAI = traceCrewAI;
34
+ exports.traceAutoGen = traceAutoGen;
35
+ exports.createWorkflowTracer = createWorkflowTracer;
36
+ exports.traceWorkflowStep = traceWorkflowStep;
37
+ const context_1 = require("./context");
38
+ // ============================================================================
39
+ // MAIN CLASS - WorkflowTracer
40
+ // ============================================================================
41
+ /**
42
+ * WorkflowTracer - Instrument multi-agent workflows with tracing, decision auditing, and cost tracking
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const tracer = new WorkflowTracer(client, { organizationId: 123 });
47
+ *
48
+ * // Simple workflow
49
+ * await tracer.startWorkflow('Data Processing Pipeline');
50
+ *
51
+ * const agentSpan = await tracer.startAgentSpan('DataAgent', { source: 'api' });
52
+ * // ... agent work ...
53
+ * await tracer.endAgentSpan(agentSpan, { processed: 100 });
54
+ *
55
+ * await tracer.endWorkflow({ status: 'success' });
56
+ * ```
57
+ */
58
+ class WorkflowTracer {
59
+ constructor(client, options = {}) {
60
+ this.currentWorkflow = null;
61
+ this.activeSpans = new Map();
62
+ this.handoffs = [];
63
+ this.decisions = [];
64
+ this.costs = [];
65
+ this.spanCounter = 0;
66
+ this.client = client;
67
+ this.options = {
68
+ organizationId: options.organizationId || client.getOrganizationId() || 0,
69
+ autoCalculateCost: options.autoCalculateCost ?? true,
70
+ tracePrefix: options.tracePrefix || "workflow",
71
+ captureFullPayloads: options.captureFullPayloads ?? true,
72
+ debug: options.debug ?? false,
73
+ };
74
+ }
75
+ // ==========================================================================
76
+ // WORKFLOW LIFECYCLE
77
+ // ==========================================================================
78
+ /**
79
+ * Start a new workflow
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const workflow = await tracer.startWorkflow('Customer Support Flow', {
84
+ * nodes: [
85
+ * { id: 'router', type: 'agent', name: 'RouterAgent' },
86
+ * { id: 'technical', type: 'agent', name: 'TechnicalAgent' },
87
+ * ],
88
+ * edges: [{ from: 'router', to: 'technical', condition: 'is_technical' }],
89
+ * entrypoint: 'router'
90
+ * });
91
+ * ```
92
+ */
93
+ async startWorkflow(name, definition, metadata) {
94
+ if (this.currentWorkflow) {
95
+ throw new Error("A workflow is already active. Call endWorkflow() first.");
96
+ }
97
+ const traceId = `${this.options.tracePrefix}-${Date.now()}-${this.generateId()}`;
98
+ const startedAt = new Date().toISOString();
99
+ // Create the trace
100
+ const trace = await this.client.traces.create({
101
+ name: `Workflow: ${name}`,
102
+ traceId,
103
+ organizationId: this.options.organizationId,
104
+ status: "pending",
105
+ metadata: (0, context_1.mergeWithContext)({
106
+ workflowName: name,
107
+ definition,
108
+ ...metadata,
109
+ }),
110
+ });
111
+ this.currentWorkflow = {
112
+ id: 0, // Will be set after API call returns
113
+ traceId: trace.id,
114
+ name,
115
+ startedAt,
116
+ definition,
117
+ metadata,
118
+ };
119
+ // Reset state
120
+ this.handoffs = [];
121
+ this.decisions = [];
122
+ this.costs = [];
123
+ this.activeSpans.clear();
124
+ this.spanCounter = 0;
125
+ this.log("Started workflow", { name, traceId: trace.id });
126
+ return this.currentWorkflow;
127
+ }
128
+ /**
129
+ * End the current workflow
130
+ */
131
+ async endWorkflow(output, status = "completed") {
132
+ if (!this.currentWorkflow) {
133
+ throw new Error("No active workflow. Call startWorkflow() first.");
134
+ }
135
+ const durationMs = Date.now() - new Date(this.currentWorkflow.startedAt).getTime();
136
+ // Calculate total cost
137
+ const totalCost = this.costs.reduce((sum, cost) => sum + parseFloat(cost.totalCost), 0);
138
+ // Update the original trace with completion data
139
+ await this.client.traces.update(this.currentWorkflow.traceId, {
140
+ status: status === "completed" ? "success" : "error",
141
+ durationMs,
142
+ metadata: (0, context_1.mergeWithContext)({
143
+ workflowName: this.currentWorkflow.name,
144
+ output,
145
+ status,
146
+ totalCost: totalCost.toFixed(6),
147
+ handoffCount: this.handoffs.length,
148
+ decisionCount: this.decisions.length,
149
+ agentCount: new Set(this.handoffs.map((h) => h.toAgent)).size + 1,
150
+ retryCount: this.costs.filter((c) => c.isRetry).length,
151
+ handoffs: this.handoffs,
152
+ decisions: this.decisions,
153
+ costs: this.costs,
154
+ }),
155
+ });
156
+ this.log("Ended workflow", {
157
+ name: this.currentWorkflow.name,
158
+ status,
159
+ durationMs,
160
+ totalCost: totalCost.toFixed(6),
161
+ });
162
+ this.currentWorkflow = null;
163
+ }
164
+ // ==========================================================================
165
+ // AGENT SPANS
166
+ // ==========================================================================
167
+ /**
168
+ * Start an agent span within the workflow
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const span = await tracer.startAgentSpan('RouterAgent', {
173
+ * input: userQuery
174
+ * });
175
+ * ```
176
+ */
177
+ async startAgentSpan(agentName, input, parentSpanId) {
178
+ if (!this.currentWorkflow) {
179
+ throw new Error("No active workflow. Call startWorkflow() first.");
180
+ }
181
+ const spanId = `span-${++this.spanCounter}-${this.generateId()}`;
182
+ const startTime = new Date().toISOString();
183
+ const spanContext = {
184
+ spanId,
185
+ agentName,
186
+ startTime,
187
+ parentSpanId,
188
+ metadata: input,
189
+ };
190
+ this.activeSpans.set(spanId, spanContext);
191
+ // Create span via API
192
+ await this.client.traces.createSpan(this.currentWorkflow.traceId, {
193
+ name: `Agent: ${agentName}`,
194
+ spanId,
195
+ type: "agent",
196
+ parentSpanId,
197
+ startTime,
198
+ metadata: (0, context_1.mergeWithContext)({
199
+ agentName,
200
+ ...(this.options.captureFullPayloads ? { input } : {}),
201
+ }),
202
+ });
203
+ this.log("Started agent span", { agentName, spanId });
204
+ return spanContext;
205
+ }
206
+ /**
207
+ * End an agent span
208
+ */
209
+ async endAgentSpan(span, output, error) {
210
+ if (!this.currentWorkflow) {
211
+ throw new Error("No active workflow.");
212
+ }
213
+ const endTime = new Date().toISOString();
214
+ const durationMs = new Date(endTime).getTime() - new Date(span.startTime).getTime();
215
+ // Update span via API (create completion record)
216
+ await this.client.traces.createSpan(this.currentWorkflow.traceId, {
217
+ name: `Agent: ${span.agentName}`,
218
+ spanId: `${span.spanId}-end`,
219
+ type: "agent",
220
+ parentSpanId: span.spanId,
221
+ startTime: span.startTime,
222
+ endTime,
223
+ durationMs,
224
+ metadata: (0, context_1.mergeWithContext)({
225
+ agentName: span.agentName,
226
+ ...(this.options.captureFullPayloads ? { output } : {}),
227
+ ...(error ? { error } : {}),
228
+ }),
229
+ });
230
+ this.activeSpans.delete(span.spanId);
231
+ this.log("Ended agent span", {
232
+ agentName: span.agentName,
233
+ spanId: span.spanId,
234
+ durationMs,
235
+ });
236
+ }
237
+ // ==========================================================================
238
+ // HANDOFFS
239
+ // ==========================================================================
240
+ /**
241
+ * Record a handoff between agents
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * await tracer.recordHandoff(
246
+ * 'RouterAgent',
247
+ * 'TechnicalAgent',
248
+ * { issueType: 'api_error', priority: 'high' },
249
+ * 'delegation'
250
+ * );
251
+ * ```
252
+ */
253
+ async recordHandoff(fromAgent, toAgent, context, handoffType = "delegation") {
254
+ if (!this.currentWorkflow) {
255
+ throw new Error("No active workflow. Call startWorkflow() first.");
256
+ }
257
+ const handoff = {
258
+ fromAgent,
259
+ toAgent,
260
+ handoffType,
261
+ context,
262
+ timestamp: new Date().toISOString(),
263
+ };
264
+ this.handoffs.push(handoff);
265
+ // Also create a span for the handoff
266
+ const spanId = `handoff-${this.handoffs.length}-${this.generateId()}`;
267
+ await this.client.traces.createSpan(this.currentWorkflow.traceId, {
268
+ name: `Handoff: ${fromAgent || "start"} → ${toAgent}`,
269
+ spanId,
270
+ type: "handoff",
271
+ startTime: handoff.timestamp,
272
+ endTime: handoff.timestamp,
273
+ durationMs: 0,
274
+ metadata: (0, context_1.mergeWithContext)({
275
+ handoffType,
276
+ fromAgent,
277
+ toAgent,
278
+ context,
279
+ }),
280
+ });
281
+ this.log("Recorded handoff", { fromAgent, toAgent, handoffType });
282
+ }
283
+ // ==========================================================================
284
+ // DECISION AUDITING
285
+ // ==========================================================================
286
+ /**
287
+ * Record a decision made by an agent
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * await tracer.recordDecision({
292
+ * agent: 'RouterAgent',
293
+ * type: 'route',
294
+ * chosen: 'technical_support',
295
+ * alternatives: [
296
+ * { action: 'billing_support', confidence: 0.3, reasoning: 'No billing keywords' },
297
+ * { action: 'general_support', confidence: 0.1, reasoning: 'Fallback option' }
298
+ * ],
299
+ * reasoning: 'Query contains technical terms like "API", "error", "endpoint"',
300
+ * confidence: 85,
301
+ * contextFactors: ['keyword_match', 'user_history']
302
+ * });
303
+ * ```
304
+ */
305
+ async recordDecision(params) {
306
+ if (!this.currentWorkflow) {
307
+ throw new Error("No active workflow. Call startWorkflow() first.");
308
+ }
309
+ this.decisions.push(params);
310
+ // Create a span for the decision
311
+ const spanId = `decision-${this.decisions.length}-${this.generateId()}`;
312
+ const timestamp = new Date().toISOString();
313
+ await this.client.traces.createSpan(this.currentWorkflow.traceId, {
314
+ name: `Decision: ${params.agent} chose ${params.chosen}`,
315
+ spanId,
316
+ type: "decision",
317
+ startTime: timestamp,
318
+ endTime: timestamp,
319
+ durationMs: 0,
320
+ metadata: (0, context_1.mergeWithContext)({
321
+ isDecisionPoint: true,
322
+ agentName: params.agent,
323
+ decisionType: params.type,
324
+ chosen: params.chosen,
325
+ alternatives: params.alternatives,
326
+ reasoning: params.reasoning,
327
+ confidence: params.confidence,
328
+ contextFactors: params.contextFactors,
329
+ inputContext: params.inputContext,
330
+ }),
331
+ });
332
+ this.log("Recorded decision", {
333
+ agent: params.agent,
334
+ type: params.type,
335
+ chosen: params.chosen,
336
+ confidence: params.confidence,
337
+ });
338
+ }
339
+ // ==========================================================================
340
+ // COST TRACKING
341
+ // ==========================================================================
342
+ /**
343
+ * Record cost for an LLM call or operation
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * await tracer.recordCost({
348
+ * provider: 'openai',
349
+ * model: 'gpt-4',
350
+ * inputTokens: 500,
351
+ * outputTokens: 200,
352
+ * category: 'llm',
353
+ * isRetry: false
354
+ * });
355
+ * ```
356
+ */
357
+ async recordCost(params) {
358
+ const totalTokens = params.inputTokens + params.outputTokens;
359
+ // Calculate cost based on known pricing (can be extended)
360
+ const pricing = this.getModelPricing(params.provider, params.model);
361
+ const inputCost = (params.inputTokens / 1000000) * pricing.inputPricePerMillion;
362
+ const outputCost = (params.outputTokens / 1000000) * pricing.outputPricePerMillion;
363
+ const totalCost = inputCost + outputCost;
364
+ const costRecord = {
365
+ ...params,
366
+ totalTokens,
367
+ category: params.category || "llm",
368
+ inputCost: inputCost.toFixed(6),
369
+ outputCost: outputCost.toFixed(6),
370
+ totalCost: totalCost.toFixed(6),
371
+ };
372
+ this.costs.push(costRecord);
373
+ // Also record as a span if in an active workflow
374
+ if (this.currentWorkflow) {
375
+ const spanId = `cost-${this.costs.length}-${this.generateId()}`;
376
+ const timestamp = new Date().toISOString();
377
+ await this.client.traces.createSpan(this.currentWorkflow.traceId, {
378
+ name: `Cost: ${params.provider}/${params.model}`,
379
+ spanId,
380
+ type: "cost",
381
+ startTime: timestamp,
382
+ endTime: timestamp,
383
+ durationMs: 0,
384
+ metadata: (0, context_1.mergeWithContext)({
385
+ costRecord,
386
+ }),
387
+ });
388
+ }
389
+ this.log("Recorded cost", {
390
+ provider: params.provider,
391
+ model: params.model,
392
+ totalTokens,
393
+ totalCost: costRecord.totalCost,
394
+ });
395
+ return costRecord;
396
+ }
397
+ /**
398
+ * Get total cost for the current workflow
399
+ */
400
+ getTotalCost() {
401
+ return this.costs.reduce((sum, cost) => sum + parseFloat(cost.totalCost), 0);
402
+ }
403
+ /**
404
+ * Get cost breakdown by category
405
+ */
406
+ getCostBreakdown() {
407
+ const breakdown = {
408
+ llm: 0,
409
+ tool: 0,
410
+ embedding: 0,
411
+ other: 0,
412
+ };
413
+ for (const cost of this.costs) {
414
+ const category = cost.category || "other";
415
+ breakdown[category] += parseFloat(cost.totalCost);
416
+ }
417
+ return breakdown;
418
+ }
419
+ // ==========================================================================
420
+ // UTILITY METHODS
421
+ // ==========================================================================
422
+ /**
423
+ * Get known pricing for a model (can be extended or fetched from API)
424
+ */
425
+ getModelPricing(provider, model) {
426
+ // Default pricing (can be extended with API lookup)
427
+ const knownPricing = {
428
+ // OpenAI
429
+ "openai/gpt-4": {
430
+ inputPricePerMillion: 30.0,
431
+ outputPricePerMillion: 60.0,
432
+ },
433
+ "openai/gpt-4-turbo": {
434
+ inputPricePerMillion: 10.0,
435
+ outputPricePerMillion: 30.0,
436
+ },
437
+ "openai/gpt-4o": {
438
+ inputPricePerMillion: 5.0,
439
+ outputPricePerMillion: 15.0,
440
+ },
441
+ "openai/gpt-4o-mini": {
442
+ inputPricePerMillion: 0.15,
443
+ outputPricePerMillion: 0.6,
444
+ },
445
+ "openai/gpt-3.5-turbo": {
446
+ inputPricePerMillion: 0.5,
447
+ outputPricePerMillion: 1.5,
448
+ },
449
+ // Anthropic
450
+ "anthropic/claude-3-opus": {
451
+ inputPricePerMillion: 15.0,
452
+ outputPricePerMillion: 75.0,
453
+ },
454
+ "anthropic/claude-3-sonnet": {
455
+ inputPricePerMillion: 3.0,
456
+ outputPricePerMillion: 15.0,
457
+ },
458
+ "anthropic/claude-3-haiku": {
459
+ inputPricePerMillion: 0.25,
460
+ outputPricePerMillion: 1.25,
461
+ },
462
+ "anthropic/claude-3.5-sonnet": {
463
+ inputPricePerMillion: 3.0,
464
+ outputPricePerMillion: 15.0,
465
+ },
466
+ // Google
467
+ "google/gemini-pro": {
468
+ inputPricePerMillion: 0.5,
469
+ outputPricePerMillion: 1.5,
470
+ },
471
+ "google/gemini-1.5-pro": {
472
+ inputPricePerMillion: 3.5,
473
+ outputPricePerMillion: 10.5,
474
+ },
475
+ "google/gemini-1.5-flash": {
476
+ inputPricePerMillion: 0.075,
477
+ outputPricePerMillion: 0.3,
478
+ },
479
+ };
480
+ const key = `${provider}/${model}`;
481
+ return (knownPricing[key] || {
482
+ inputPricePerMillion: 1.0,
483
+ outputPricePerMillion: 3.0,
484
+ });
485
+ }
486
+ /**
487
+ * Generate a unique ID
488
+ */
489
+ generateId() {
490
+ return Math.random().toString(36).substring(2, 11);
491
+ }
492
+ /**
493
+ * Log if debug mode is enabled
494
+ */
495
+ log(message, data) {
496
+ if (this.options.debug) {
497
+ console.log(`[WorkflowTracer] ${message}`, data || "");
498
+ }
499
+ }
500
+ /**
501
+ * Get current workflow context
502
+ */
503
+ getCurrentWorkflow() {
504
+ return this.currentWorkflow;
505
+ }
506
+ /**
507
+ * Check if a workflow is active
508
+ */
509
+ isWorkflowActive() {
510
+ return this.currentWorkflow !== null;
511
+ }
512
+ /**
513
+ * Get all recorded handoffs
514
+ */
515
+ getHandoffs() {
516
+ return [...this.handoffs];
517
+ }
518
+ /**
519
+ * Get all recorded decisions
520
+ */
521
+ getDecisions() {
522
+ return [...this.decisions];
523
+ }
524
+ /**
525
+ * Get all recorded costs
526
+ */
527
+ getCosts() {
528
+ return [...this.costs];
529
+ }
530
+ }
531
+ exports.WorkflowTracer = WorkflowTracer;
532
+ // ============================================================================
533
+ // FRAMEWORK INTEGRATIONS
534
+ // ============================================================================
535
+ /**
536
+ * Wrap a LangChain agent for automatic workflow tracing
537
+ *
538
+ * @example
539
+ * ```typescript
540
+ * import { AgentExecutor } from 'langchain/agents';
541
+ *
542
+ * const executor = new AgentExecutor({ ... });
543
+ * const tracedExecutor = traceLangChainAgent(executor, tracer);
544
+ *
545
+ * const result = await tracedExecutor.invoke({ input: 'Hello' });
546
+ * ```
547
+ */
548
+ function traceLangChainAgent(executor, tracer, options = {}) {
549
+ const agentName = options.agentName || "LangChainAgent";
550
+ const originalInvoke = executor.invoke?.bind(executor);
551
+ const originalCall = executor.call?.bind(executor);
552
+ if (originalInvoke) {
553
+ executor.invoke = async (input, config) => {
554
+ const span = await tracer.startAgentSpan(agentName, { input });
555
+ try {
556
+ const result = await originalInvoke(input, config);
557
+ await tracer.endAgentSpan(span, { output: result });
558
+ return result;
559
+ }
560
+ catch (error) {
561
+ await tracer.endAgentSpan(span, undefined, error instanceof Error ? error.message : String(error));
562
+ throw error;
563
+ }
564
+ };
565
+ }
566
+ if (originalCall) {
567
+ executor.call = async (input, config) => {
568
+ const span = await tracer.startAgentSpan(agentName, { input });
569
+ try {
570
+ const result = await originalCall(input, config);
571
+ await tracer.endAgentSpan(span, { output: result });
572
+ return result;
573
+ }
574
+ catch (error) {
575
+ await tracer.endAgentSpan(span, undefined, error instanceof Error ? error.message : String(error));
576
+ throw error;
577
+ }
578
+ };
579
+ }
580
+ return executor;
581
+ }
582
+ /**
583
+ * Create a traced wrapper for CrewAI crews
584
+ *
585
+ * @example
586
+ * ```typescript
587
+ * const tracedCrew = traceCrewAI(crew, tracer, {
588
+ * crewName: 'ResearchCrew'
589
+ * });
590
+ *
591
+ * const result = await tracedCrew.kickoff({ topic: 'AI Safety' });
592
+ * ```
593
+ */
594
+ function traceCrewAI(crew, tracer, options = {}) {
595
+ const crewName = options.crewName || "CrewAI";
596
+ const originalKickoff = crew.kickoff?.bind(crew);
597
+ if (originalKickoff) {
598
+ crew.kickoff = async (input) => {
599
+ await tracer.startWorkflow(`${crewName} Execution`);
600
+ const span = await tracer.startAgentSpan(crewName, { input });
601
+ try {
602
+ const result = await originalKickoff(input);
603
+ await tracer.endAgentSpan(span, { output: result });
604
+ await tracer.endWorkflow({ result }, "completed");
605
+ return result;
606
+ }
607
+ catch (error) {
608
+ await tracer.endAgentSpan(span, undefined, error instanceof Error ? error.message : String(error));
609
+ await tracer.endWorkflow({ error: error instanceof Error ? error.message : String(error) }, "failed");
610
+ throw error;
611
+ }
612
+ };
613
+ }
614
+ return crew;
615
+ }
616
+ /**
617
+ * Create a traced wrapper for AutoGen conversations
618
+ *
619
+ * @example
620
+ * ```typescript
621
+ * const tracedConversation = traceAutoGen(conversation, tracer, {
622
+ * conversationName: 'CodeReview'
623
+ * });
624
+ * ```
625
+ */
626
+ function traceAutoGen(conversation, tracer, options = {}) {
627
+ const conversationName = options.conversationName || "AutoGenConversation";
628
+ const originalInitiateChat = conversation.initiate_chat?.bind(conversation);
629
+ if (originalInitiateChat) {
630
+ conversation.initiate_chat = async (...args) => {
631
+ await tracer.startWorkflow(`${conversationName}`);
632
+ const span = await tracer.startAgentSpan(conversationName, { args });
633
+ try {
634
+ const result = await originalInitiateChat(...args);
635
+ await tracer.endAgentSpan(span, { output: result });
636
+ await tracer.endWorkflow({ result }, "completed");
637
+ return result;
638
+ }
639
+ catch (error) {
640
+ await tracer.endAgentSpan(span, undefined, error instanceof Error ? error.message : String(error));
641
+ await tracer.endWorkflow({ error: error instanceof Error ? error.message : String(error) }, "failed");
642
+ throw error;
643
+ }
644
+ };
645
+ }
646
+ return conversation;
647
+ }
648
+ // ============================================================================
649
+ // UTILITY FUNCTIONS
650
+ // ============================================================================
651
+ /**
652
+ * Create a workflow tracer from an existing client
653
+ */
654
+ function createWorkflowTracer(client, options) {
655
+ return new WorkflowTracer(client, options);
656
+ }
657
+ /**
658
+ * Helper to trace an async function as a workflow step
659
+ */
660
+ async function traceWorkflowStep(tracer, agentName, fn, input) {
661
+ const span = await tracer.startAgentSpan(agentName, input);
662
+ try {
663
+ const result = await fn();
664
+ await tracer.endAgentSpan(span, { result });
665
+ return result;
666
+ }
667
+ catch (error) {
668
+ await tracer.endAgentSpan(span, undefined, error instanceof Error ? error.message : String(error));
669
+ throw error;
670
+ }
671
+ }