societyai 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 (114) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +879 -0
  4. package/dist/builder.d.ts +181 -0
  5. package/dist/builder.d.ts.map +1 -0
  6. package/dist/builder.js +667 -0
  7. package/dist/builder.js.map +1 -0
  8. package/dist/config.d.ts +43 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +11 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/context.d.ts +107 -0
  13. package/dist/context.d.ts.map +1 -0
  14. package/dist/context.js +319 -0
  15. package/dist/context.js.map +1 -0
  16. package/dist/errors.d.ts +31 -0
  17. package/dist/errors.d.ts.map +1 -0
  18. package/dist/errors.js +85 -0
  19. package/dist/errors.js.map +1 -0
  20. package/dist/events.d.ts +219 -0
  21. package/dist/events.d.ts.map +1 -0
  22. package/dist/events.js +395 -0
  23. package/dist/events.js.map +1 -0
  24. package/dist/graph.d.ts +104 -0
  25. package/dist/graph.d.ts.map +1 -0
  26. package/dist/graph.js +366 -0
  27. package/dist/graph.js.map +1 -0
  28. package/dist/index.d.ts +28 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +113 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/logger.d.ts +13 -0
  33. package/dist/logger.d.ts.map +1 -0
  34. package/dist/logger.js +78 -0
  35. package/dist/logger.js.map +1 -0
  36. package/dist/memory.d.ts +146 -0
  37. package/dist/memory.d.ts.map +1 -0
  38. package/dist/memory.js +353 -0
  39. package/dist/memory.js.map +1 -0
  40. package/dist/metrics.d.ts +143 -0
  41. package/dist/metrics.d.ts.map +1 -0
  42. package/dist/metrics.js +271 -0
  43. package/dist/metrics.js.map +1 -0
  44. package/dist/middleware.d.ts +147 -0
  45. package/dist/middleware.d.ts.map +1 -0
  46. package/dist/middleware.js +484 -0
  47. package/dist/middleware.js.map +1 -0
  48. package/dist/models.d.ts +32 -0
  49. package/dist/models.d.ts.map +1 -0
  50. package/dist/models.js +211 -0
  51. package/dist/models.js.map +1 -0
  52. package/dist/patterns.d.ts +6 -0
  53. package/dist/patterns.d.ts.map +1 -0
  54. package/dist/patterns.js +68 -0
  55. package/dist/patterns.js.map +1 -0
  56. package/dist/pipeline.d.ts +84 -0
  57. package/dist/pipeline.d.ts.map +1 -0
  58. package/dist/pipeline.js +569 -0
  59. package/dist/pipeline.js.map +1 -0
  60. package/dist/retry.d.ts +5 -0
  61. package/dist/retry.d.ts.map +1 -0
  62. package/dist/retry.js +70 -0
  63. package/dist/retry.js.map +1 -0
  64. package/dist/society.d.ts +94 -0
  65. package/dist/society.d.ts.map +1 -0
  66. package/dist/society.js +721 -0
  67. package/dist/society.js.map +1 -0
  68. package/dist/strategies.d.ts +55 -0
  69. package/dist/strategies.d.ts.map +1 -0
  70. package/dist/strategies.js +678 -0
  71. package/dist/strategies.js.map +1 -0
  72. package/dist/tools.d.ts +88 -0
  73. package/dist/tools.d.ts.map +1 -0
  74. package/dist/tools.js +366 -0
  75. package/dist/tools.js.map +1 -0
  76. package/dist/types.d.ts +213 -0
  77. package/dist/types.d.ts.map +1 -0
  78. package/dist/types.js +19 -0
  79. package/dist/types.js.map +1 -0
  80. package/dist/validation.d.ts +64 -0
  81. package/dist/validation.d.ts.map +1 -0
  82. package/dist/validation.js +334 -0
  83. package/dist/validation.js.map +1 -0
  84. package/dist/worker-pool.d.ts +17 -0
  85. package/dist/worker-pool.d.ts.map +1 -0
  86. package/dist/worker-pool.js +80 -0
  87. package/dist/worker-pool.js.map +1 -0
  88. package/docs/README.md +468 -0
  89. package/docs/advanced.md +616 -0
  90. package/docs/aggregation-strategies.md +926 -0
  91. package/docs/api-reference.md +771 -0
  92. package/docs/architecture.md +648 -0
  93. package/docs/context-system.md +642 -0
  94. package/docs/event-system.md +1047 -0
  95. package/docs/examples.md +576 -0
  96. package/docs/getting-started.md +564 -0
  97. package/docs/graph-execution.md +389 -0
  98. package/docs/memory-system.md +497 -0
  99. package/docs/metrics-observability.md +560 -0
  100. package/docs/middleware-system.md +1038 -0
  101. package/docs/migration.md +296 -0
  102. package/docs/pipeline-patterns.md +761 -0
  103. package/docs/structured-output.md +612 -0
  104. package/docs/tool-calling.md +491 -0
  105. package/docs/workflows.md +740 -0
  106. package/examples/README.md +234 -0
  107. package/examples/advanced-patterns.ts +115 -0
  108. package/examples/complete-integration.ts +327 -0
  109. package/examples/graph-workflow.ts +161 -0
  110. package/examples/memory-system.ts +155 -0
  111. package/examples/metrics-tracking.ts +243 -0
  112. package/examples/structured-output.ts +231 -0
  113. package/examples/tool-calling.ts +163 -0
  114. package/package.json +94 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Example: Using SocietyGraph for Complex Workflows
3
+ *
4
+ * This example demonstrates how to use the graph-based execution engine
5
+ * to create a sophisticated code review workflow with conditional branching,
6
+ * loops, and parallel execution.
7
+ */
8
+
9
+ import {
10
+ GraphBuilder,
11
+ NodeType,
12
+ AgentBuilder,
13
+ RoleBuilder,
14
+ StandardModelBase,
15
+ } from '../src';
16
+
17
+ // Mock AI Model for demonstration
18
+ class MockModel extends StandardModelBase {
19
+ constructor(name: string) {
20
+ super({ name }, async (prompt: unknown) => {
21
+ // Simulate AI response
22
+ const promptStr = typeof prompt === 'string' ? prompt : JSON.stringify(prompt);
23
+
24
+ if (promptStr.includes('analyze')) {
25
+ return 'The code looks good but needs better error handling.';
26
+ } else if (promptStr.includes('valid')) {
27
+ return 'valid: true\nThe improvements have been applied successfully.';
28
+ } else if (promptStr.includes('fix')) {
29
+ return 'Added try-catch blocks and improved error messages.';
30
+ }
31
+
32
+ return 'Task completed successfully.';
33
+ });
34
+ }
35
+ }
36
+
37
+ async function runGraphExample(): Promise<void> {
38
+ console.log('=== Graph-Based Workflow Example ===\n');
39
+
40
+ // Create AI models
41
+ const model = new MockModel('code-analyzer');
42
+
43
+ // Create agent roles
44
+ const analyzerRole = RoleBuilder.create()
45
+ .withId('analyzer')
46
+ .withName('Code Analyzer')
47
+ .withSystemPrompt('You analyze code and identify issues.')
48
+ .build();
49
+
50
+ const fixerRole = RoleBuilder.create()
51
+ .withId('fixer')
52
+ .withName('Code Fixer')
53
+ .withSystemPrompt('You fix code issues.')
54
+ .build();
55
+
56
+ const validatorRole = RoleBuilder.create()
57
+ .withId('validator')
58
+ .withName('Code Validator')
59
+ .withSystemPrompt('You validate code fixes.')
60
+ .build();
61
+
62
+ // Create agents
63
+ const agents = [
64
+ AgentBuilder.create()
65
+ .withId('analyzer-1')
66
+ .withRole(analyzerRole)
67
+ .withModel(model)
68
+ .build(),
69
+ AgentBuilder.create()
70
+ .withId('fixer-1')
71
+ .withRole(fixerRole)
72
+ .withModel(model)
73
+ .build(),
74
+ AgentBuilder.create()
75
+ .withId('validator-1')
76
+ .withRole(validatorRole)
77
+ .withModel(model)
78
+ .build(),
79
+ ];
80
+
81
+ // Build the graph
82
+ const graph = GraphBuilder.create()
83
+ // Start node
84
+ .addNode('start', NodeType.START)
85
+
86
+ // Analyze the code
87
+ .addNode('analyze', NodeType.AGENT, { agentId: 'analyzer-1' })
88
+
89
+ // Conditional: Does it need fixing?
90
+ .addNode('needs-fix', NodeType.CONDITION, {
91
+ condition: (result) => !result.includes('looks good'),
92
+ })
93
+
94
+ // Fix the code
95
+ .addNode('fix', NodeType.AGENT, { agentId: 'fixer-1' })
96
+
97
+ // Validate the fix
98
+ .addNode('validate', NodeType.AGENT, { agentId: 'validator-1' })
99
+
100
+ // Conditional: Is it valid?
101
+ .addNode('is-valid', NodeType.CONDITION, {
102
+ condition: (result) => result.includes('valid: true'),
103
+ })
104
+
105
+ // Transform for final output
106
+ .addNode('format', NodeType.TRANSFORM, {
107
+ transformer: (result) => `✓ Code Review Complete:\n${result}`,
108
+ })
109
+
110
+ // End node
111
+ .addNode('end', NodeType.END)
112
+
113
+ // Connect the nodes
114
+ .addEdge('start', 'analyze')
115
+ .addEdge('analyze', 'needs-fix')
116
+
117
+ // Conditional edges
118
+ .addConditionalEdge({
119
+ from: 'needs-fix',
120
+ condition: (result) => !result.includes('looks good'),
121
+ truePath: 'fix',
122
+ falsePath: 'format',
123
+ })
124
+
125
+ .addEdge('fix', 'validate')
126
+ .addEdge('validate', 'is-valid')
127
+
128
+ // Loop back if validation fails (max 3 iterations)
129
+ .addConditionalEdge({
130
+ from: 'is-valid',
131
+ condition: (result) => result.includes('valid: true'),
132
+ truePath: 'format',
133
+ falsePath: 'fix',
134
+ })
135
+
136
+ .addEdge('format', 'end')
137
+
138
+ .build();
139
+
140
+ // Execute the graph
141
+ console.log('Visualizing graph structure:');
142
+ console.log(graph.visualize());
143
+ console.log('\nExecuting workflow...\n');
144
+
145
+ const result = await graph.execute(
146
+ 'Analyze this TypeScript function for potential issues',
147
+ agents
148
+ );
149
+
150
+ console.log('Result:', result.output);
151
+ console.log('\nExecution path:', result.executionPath.join(' → '));
152
+ console.log('Duration:', result.duration, 'ms');
153
+ console.log('Success:', result.success);
154
+ }
155
+
156
+ // Run the example
157
+ if (require.main === module) {
158
+ runGraphExample().catch(console.error);
159
+ }
160
+
161
+ export { runGraphExample };
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Example: Memory System
3
+ *
4
+ * This example demonstrates the multi-level memory system including
5
+ * short-term, long-term, and entity memory.
6
+ */
7
+
8
+ import {
9
+ MemoryBuilder,
10
+ } from '../src';
11
+
12
+ async function runMemoryExample(): Promise<void> {
13
+ console.log('=== Memory System Example ===\n');
14
+
15
+ // Create memory system
16
+ const memory = MemoryBuilder.create()
17
+ .withShortTermMemory({
18
+ maxMessages: 10,
19
+ summarizeAfter: 20,
20
+ decayRate: 0.1,
21
+ })
22
+ .withLongTermMemory({
23
+ maxEntries: 100,
24
+ })
25
+ .build();
26
+
27
+ console.log('--- Short-Term Memory ---');
28
+
29
+ // Add conversation history
30
+ await memory.add('User asked about TypeScript features', {
31
+ type: 'conversation',
32
+ importance: 0.7,
33
+ });
34
+
35
+ await memory.add('Explained TypeScript generics', {
36
+ type: 'conversation',
37
+ importance: 0.8,
38
+ });
39
+
40
+ await memory.add('User wants to learn about decorators', {
41
+ type: 'conversation',
42
+ importance: 0.9,
43
+ });
44
+
45
+ const shortTerm = memory.getShortTerm();
46
+ const recentMemories = shortTerm.getRecent(5);
47
+
48
+ console.log(`Recent memories: ${recentMemories.length}`);
49
+ recentMemories.forEach(m => {
50
+ console.log(`- ${m.content} (importance: ${m.importance?.toFixed(2)})`);
51
+ });
52
+
53
+ console.log('\n--- Long-Term Memory ---');
54
+
55
+ // Add facts to long-term memory
56
+ await memory.add('TypeScript is a typed superset of JavaScript', {
57
+ type: 'fact',
58
+ importance: 1.0,
59
+ });
60
+
61
+ await memory.add('TypeScript compiles to plain JavaScript', {
62
+ type: 'fact',
63
+ importance: 0.9,
64
+ });
65
+
66
+ await memory.add('Generics provide type-safe reusable components', {
67
+ type: 'fact',
68
+ importance: 0.8,
69
+ });
70
+
71
+ // Retrieve relevant facts
72
+ const context = await memory.retrieve('TypeScript generics', {
73
+ includeShortTerm: true,
74
+ includeLongTerm: true,
75
+ limit: 3,
76
+ });
77
+
78
+ console.log('Retrieved context for "TypeScript generics":');
79
+ console.log(context);
80
+
81
+ console.log('\n--- Entity Memory ---');
82
+
83
+ const entities = memory.getEntities();
84
+
85
+ // Add entities
86
+ entities.upsert('John Doe', 'person', [
87
+ 'Prefers TypeScript over JavaScript',
88
+ 'Learning about decorators',
89
+ 'Works as a software engineer',
90
+ ]);
91
+
92
+ entities.upsert('React', 'framework', [
93
+ 'Popular UI library',
94
+ 'Works well with TypeScript',
95
+ 'Uses JSX syntax',
96
+ ]);
97
+
98
+ entities.upsert('TypeScript', 'language', [
99
+ 'Statically typed',
100
+ 'Compiles to JavaScript',
101
+ 'Developed by Microsoft',
102
+ ]);
103
+
104
+ // Search entities
105
+ const foundEntities = entities.search('TypeScript');
106
+ console.log(`Found ${foundEntities.length} entities related to "TypeScript":`);
107
+
108
+ foundEntities.forEach(entity => {
109
+ console.log(`\n${entity.name} (${entity.type}):`);
110
+ entity.facts.forEach(fact => console.log(` - ${fact}`));
111
+ });
112
+
113
+ // Get entity by type
114
+ const people = entities.getByType('person');
115
+ console.log(`\n${people.length} person entities:`);
116
+ people.forEach(p => console.log(`- ${p.name}`));
117
+
118
+ console.log('\n--- Memory Statistics ---');
119
+
120
+ const stats = memory.getStats();
121
+ console.log('Short-term messages:', stats.shortTerm.messages);
122
+ console.log('Long-term total:', stats.longTerm.total);
123
+ console.log('Long-term by type:', stats.longTerm.byType);
124
+ console.log('Entities total:', stats.entities.total);
125
+ console.log('Entities by type:', stats.entities.byType);
126
+
127
+ console.log('\n--- Advanced: Importance Decay ---');
128
+
129
+ // Simulate time passing
130
+ shortTerm.applyDecay();
131
+
132
+ const decayedMemories = shortTerm.getRecent(5);
133
+ console.log('After decay:');
134
+ decayedMemories.forEach(m => {
135
+ console.log(`- ${m.content} (importance: ${m.importance?.toFixed(2)})`);
136
+ });
137
+
138
+ console.log('\n--- Advanced: Entity Updates ---');
139
+
140
+ // Update existing entity with new facts
141
+ entities.upsert('John Doe', 'person', [
142
+ 'Completed TypeScript decorators tutorial',
143
+ ]);
144
+
145
+ const john = entities.get('John Doe', 'person');
146
+ console.log(`\nJohn Doe's facts (${john?.facts.length} total):`);
147
+ john?.facts.forEach(fact => console.log(` - ${fact}`));
148
+ }
149
+
150
+ // Run the example
151
+ if (require.main === module) {
152
+ runMemoryExample().catch(console.error);
153
+ }
154
+
155
+ export { runMemoryExample };
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Example: Metrics and Observability
3
+ *
4
+ * This example demonstrates comprehensive tracking of token usage,
5
+ * execution time, costs, and OpenTelemetry-compatible trace export.
6
+ */
7
+
8
+ import {
9
+ MetricsBuilder,
10
+ MetricsTracker,
11
+ TokenCounter,
12
+ PerformanceProfiler,
13
+ CommonCostConfigs,
14
+ StandardModelBase,
15
+ } from '../src';
16
+
17
+ // Example model with token tracking (for reference)
18
+ // This class demonstrates how to integrate metrics tracking into a custom model
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
+ class TrackedModel extends StandardModelBase {
21
+ constructor(name: string, private tracker: MetricsTracker) {
22
+ super({ name }, async (prompt: unknown) => {
23
+ const promptStr = typeof prompt === 'string' ? prompt : JSON.stringify(prompt);
24
+
25
+ // Simulate processing
26
+ await new Promise(resolve => setTimeout(resolve, 100));
27
+
28
+ const response = `Processed: ${promptStr.substring(0, 50)}...`;
29
+
30
+ // Track tokens
31
+ // Count tokens for tracking
32
+ // const tokens = TokenCounter.count(promptStr, response);
33
+
34
+ return response;
35
+ });
36
+ }
37
+ }
38
+
39
+ async function runMetricsExample(): Promise<void> {
40
+ console.log('=== Metrics and Observability Example ===\n');
41
+
42
+ // Create metrics tracker
43
+ const tracker = MetricsBuilder.create()
44
+ .withTokenTracking()
45
+ .withCostTracking(CommonCostConfigs['gpt-4'])
46
+ .withCostTracking(CommonCostConfigs['claude-3-sonnet'])
47
+ .build();
48
+
49
+ console.log('--- Basic Tracking ---');
50
+
51
+ // Start tracking a workflow
52
+ tracker.start('workflow-1', { userId: 'user123', task: 'analysis' });
53
+
54
+ // Simulate some work
55
+ await new Promise(resolve => setTimeout(resolve, 150));
56
+
57
+ // End tracking with token metrics
58
+ const snapshot1 = tracker.end('workflow-1', {
59
+ tokens: {
60
+ inputTokens: 500,
61
+ outputTokens: 300,
62
+ totalTokens: 800,
63
+ model: 'gpt-4',
64
+ },
65
+ custom: {
66
+ apiCalls: 3,
67
+ cacheHits: 1,
68
+ },
69
+ });
70
+
71
+ console.log('Workflow completed:');
72
+ console.log('- Duration:', snapshot1.execution.duration, 'ms');
73
+ console.log('- Tokens:', snapshot1.tokens?.totalTokens);
74
+ console.log('- Estimated cost:', `$${snapshot1.cost?.totalCost.toFixed(4)}`);
75
+ console.log('- Custom metrics:', snapshot1.custom);
76
+
77
+ // Track multiple workflows
78
+ console.log('\n--- Multiple Workflows ---');
79
+
80
+ for (let i = 0; i < 3; i++) {
81
+ tracker.start(`agent-${i}`);
82
+ await new Promise(resolve => setTimeout(resolve, Math.random() * 100));
83
+
84
+ tracker.end(`agent-${i}`, {
85
+ tokens: {
86
+ inputTokens: Math.floor(Math.random() * 500) + 100,
87
+ outputTokens: Math.floor(Math.random() * 300) + 50,
88
+ totalTokens: 0,
89
+ model: 'claude-3-sonnet',
90
+ },
91
+ });
92
+ }
93
+
94
+ // Get aggregated metrics
95
+ const aggregated = tracker.getAggregated();
96
+
97
+ console.log('Aggregated metrics:');
98
+ console.log('- Total executions:', aggregated.totalExecutions);
99
+ console.log('- Successful:', aggregated.successfulExecutions);
100
+ console.log('- Average duration:', aggregated.averageDuration.toFixed(2), 'ms');
101
+ console.log('- Total tokens:', aggregated.totalTokens);
102
+ console.log('- Total cost:', `$${aggregated.totalCost?.toFixed(4)}`);
103
+
104
+ // Track failure
105
+ console.log('\n--- Failure Tracking ---');
106
+
107
+ tracker.start('failing-workflow');
108
+ await new Promise(resolve => setTimeout(resolve, 50));
109
+
110
+ try {
111
+ throw new Error('Simulated failure');
112
+ } catch (error) {
113
+ tracker.fail('failing-workflow', error as Error);
114
+ }
115
+
116
+ const failedMetrics = tracker.getAggregated();
117
+ console.log('Failed executions:', failedMetrics.failedExecutions);
118
+
119
+ // Performance profiling
120
+ console.log('\n--- Performance Profiling ---');
121
+
122
+ const profiler = new PerformanceProfiler();
123
+
124
+ profiler.mark('start');
125
+ await new Promise(resolve => setTimeout(resolve, 50));
126
+
127
+ profiler.mark('phase-1-complete');
128
+ await new Promise(resolve => setTimeout(resolve, 75));
129
+
130
+ profiler.mark('phase-2-complete');
131
+ await new Promise(resolve => setTimeout(resolve, 25));
132
+
133
+ profiler.mark('end');
134
+
135
+ const phase1Duration = profiler.measure('phase-1', 'start', 'phase-1-complete');
136
+ const phase2Duration = profiler.measure('phase-2', 'phase-1-complete', 'phase-2-complete');
137
+ const totalDuration = profiler.measure('total', 'start', 'end');
138
+
139
+ console.log('Phase 1 duration:', phase1Duration, 'ms');
140
+ console.log('Phase 2 duration:', phase2Duration, 'ms');
141
+ console.log('Total duration:', totalDuration, 'ms');
142
+
143
+ console.log('\nAll measures:', profiler.getMeasures());
144
+
145
+ // Token estimation
146
+ console.log('\n--- Token Estimation ---');
147
+
148
+ const text1 = 'This is a short text message.';
149
+ const text2 = 'This is a much longer text message with more content and details that will result in more tokens being counted.';
150
+
151
+ console.log('Text 1 estimated tokens:', TokenCounter.estimate(text1));
152
+ console.log('Text 2 estimated tokens:', TokenCounter.estimate(text2));
153
+
154
+ const promptTokens = TokenCounter.count(text2, text1);
155
+ console.log('Prompt + response tokens:', promptTokens);
156
+
157
+ // Export metrics
158
+ console.log('\n--- Metrics Export ---');
159
+
160
+ const jsonExport = tracker.export();
161
+ console.log('JSON export length:', jsonExport.length, 'characters');
162
+ console.log('(Truncated preview):', jsonExport.substring(0, 200), '...');
163
+
164
+ // OpenTelemetry export
165
+ const otelTraces = tracker.exportOTel();
166
+ console.log('\nOpenTelemetry traces:', otelTraces.length);
167
+ console.log('Sample trace:');
168
+ console.log({
169
+ name: otelTraces[0]?.name,
170
+ duration: otelTraces[0]?.endTimeUnixNano - otelTraces[0]?.startTimeUnixNano,
171
+ status: otelTraces[0]?.status.code,
172
+ attributes: Object.keys(otelTraces[0]?.attributes || {}),
173
+ });
174
+
175
+ // Filter history
176
+ console.log('\n--- Filtered History ---');
177
+
178
+ const workflow1History = tracker.getHistory({ id: 'workflow-1' });
179
+ console.log('Workflow-1 executions:', workflow1History.length);
180
+
181
+ const successfulHistory = tracker.getHistory({ success: true });
182
+ console.log('Successful executions:', successfulHistory.length);
183
+
184
+ const failedHistory = tracker.getHistory({ success: false });
185
+ console.log('Failed executions:', failedHistory.length);
186
+
187
+ // Per-agent breakdown
188
+ console.log('\n--- Per-Agent Breakdown ---');
189
+
190
+ const byAgent = aggregated.byAgent;
191
+ if (byAgent) {
192
+ for (const [agentId, snapshots] of Object.entries(byAgent)) {
193
+ console.log(`\n${agentId}:`);
194
+ console.log(` - Executions: ${snapshots.length}`);
195
+
196
+ const totalDuration = snapshots.reduce((sum, s) => sum + (s.execution.duration || 0), 0);
197
+ console.log(` - Total duration: ${totalDuration}ms`);
198
+
199
+ const totalTokens = snapshots.reduce((sum, s) => sum + (s.tokens?.totalTokens || 0), 0);
200
+ if (totalTokens > 0) {
201
+ console.log(` - Total tokens: ${totalTokens}`);
202
+ }
203
+
204
+ const totalCost = snapshots.reduce((sum, s) => sum + (s.cost?.totalCost || 0), 0);
205
+ if (totalCost > 0) {
206
+ console.log(` - Total cost: $${totalCost.toFixed(4)}`);
207
+ }
208
+ }
209
+ }
210
+
211
+ // Cost comparison across models
212
+ console.log('\n--- Cost Comparison ---');
213
+
214
+ const models = [
215
+ { name: 'gpt-4', tokens: 1000 },
216
+ { name: 'gpt-4-turbo', tokens: 1000 },
217
+ { name: 'gpt-3.5-turbo', tokens: 1000 },
218
+ { name: 'claude-3-opus', tokens: 1000 },
219
+ { name: 'claude-3-sonnet', tokens: 1000 },
220
+ ];
221
+
222
+ console.log('Cost for 1000 tokens (500 input + 500 output):');
223
+
224
+ for (const model of models) {
225
+ const config = CommonCostConfigs[model.name as keyof typeof CommonCostConfigs];
226
+ if (config) {
227
+ const inputCost = (500 / 1000) * config.inputCostPer1K;
228
+ const outputCost = (500 / 1000) * config.outputCostPer1K;
229
+ const totalCost = inputCost + outputCost;
230
+
231
+ console.log(`- ${model.name}: $${totalCost.toFixed(4)}`);
232
+ }
233
+ }
234
+ }
235
+
236
+ // Run the example
237
+ if (require.main === module) {
238
+ (async (): Promise<void> => {
239
+ await runMetricsExample().catch(console.error);
240
+ })();
241
+ }
242
+
243
+ export { runMetricsExample };