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,616 @@
1
+ # Advanced Features
2
+
3
+ Advanced features and best practices for SocietyAI.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Error Handling](#error-handling)
8
+ - [Retry Mechanism](#retry-mechanism)
9
+ - [Timeout & Cancellation](#timeout--cancellation)
10
+ - [Observability](#observability)
11
+ - [Performance Optimization](#performance-optimization)
12
+ - [Testing](#testing)
13
+ - [Production Deployment](#production-deployment)
14
+
15
+ ## Error Handling
16
+
17
+ ### Error Types
18
+
19
+ SocietyAI provides specific error types for different failure scenarios:
20
+
21
+ ```typescript
22
+ import {
23
+ SocietyError,
24
+ ProcessingFailedError,
25
+ TimeoutError,
26
+ InvalidConfigurationError,
27
+ OperationCancelledError,
28
+ } from 'societyai';
29
+
30
+ try {
31
+ const result = await executor.execute(workflow, input);
32
+ } catch (error) {
33
+ if (error instanceof ProcessingFailedError) {
34
+ console.error('AI model processing failed:', error.message);
35
+ // Retry with different model or parameters
36
+ } else if (error instanceof TimeoutError) {
37
+ console.error('Operation timed out');
38
+ // Increase timeout or optimize workflow
39
+ } else if (error instanceof InvalidConfigurationError) {
40
+ console.error('Invalid workflow configuration:', error.message);
41
+ // Fix configuration
42
+ } else if (error instanceof OperationCancelledError) {
43
+ console.log('Operation was cancelled by user');
44
+ // Handle graceful shutdown
45
+ } else {
46
+ console.error('Unexpected error:', error);
47
+ }
48
+ }
49
+ ```
50
+
51
+ ### Step-Level Error Handling
52
+
53
+ Each step result includes success/error information:
54
+
55
+ ```typescript
56
+ const result = await executor.execute(workflow, input);
57
+
58
+ for (const [stepId, stepResults] of result.stepResults) {
59
+ for (const stepResult of stepResults) {
60
+ if (!stepResult.success) {
61
+ console.error(
62
+ `Agent ${stepResult.agentId} failed in step ${stepId}:`,
63
+ stepResult.error?.message
64
+ );
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### Conditional Error Recovery
71
+
72
+ ```typescript
73
+ const workflow = WorkflowConfigBuilder.create()
74
+ .addSteps([
75
+ // Main step
76
+ StepBuilder.create().withId('main').withAgents(['main-agent']).build(),
77
+
78
+ // Error recovery step
79
+ StepBuilder.create()
80
+ .withId('recovery')
81
+ .withAgents(['backup-agent'])
82
+ .withExecutionType('conditional')
83
+ .withCondition((results) => {
84
+ const mainResults = results.get('main');
85
+ return mainResults?.some((r) => !r.success) ?? false;
86
+ })
87
+ .build(),
88
+ ])
89
+ .build();
90
+ ```
91
+
92
+ ### Lifecycle Hook Error Handling
93
+
94
+ ```typescript
95
+ const workflow = WorkflowConfigBuilder.create()
96
+ .onAfterStep(async (step, results, context) => {
97
+ const failures = results.filter((r) => !r.success);
98
+
99
+ if (failures.length > 0) {
100
+ console.error(`Step ${step.id} had ${failures.length} failures`);
101
+
102
+ // Store error info in context
103
+ context.metadata.errors = context.metadata.errors || [];
104
+ context.metadata.errors.push({
105
+ step: step.id,
106
+ failures: failures.map((f) => ({
107
+ agent: f.agentId,
108
+ error: f.error?.message,
109
+ })),
110
+ });
111
+
112
+ // Optionally throw to stop workflow
113
+ if (failures.length === results.length) {
114
+ throw new Error(`All agents failed in step ${step.id}`);
115
+ }
116
+ }
117
+ })
118
+ .build();
119
+ ```
120
+
121
+ ## Retry Mechanism
122
+
123
+ ### Built-in Retry
124
+
125
+ StandardModelBase includes automatic retry with exponential backoff:
126
+
127
+ ```typescript
128
+ import { StandardModelBase, defaultRetryOptions } from 'societyai';
129
+
130
+ const model = new StandardModelBase(
131
+ {
132
+ name: 'MyModel',
133
+ retryOptions: {
134
+ maxRetries: 3,
135
+ initialBackoff: 1000, // 1 second
136
+ maxBackoff: 10000, // 10 seconds
137
+ backoffFactor: 2, // Double each retry
138
+ jitter: true, // Add randomness
139
+ },
140
+ },
141
+ async (prompt) => {
142
+ // Your API call
143
+ return response;
144
+ }
145
+ );
146
+ ```
147
+
148
+ ### Per-Agent Retry Configuration
149
+
150
+ ```typescript
151
+ const agent = AgentBuilder.create()
152
+ .withId('unreliable-agent')
153
+ .withRole(role)
154
+ .withModel(model)
155
+ .withInitialContext({
156
+ retryConfig: {
157
+ maxRetries: 5,
158
+ initialBackoff: 2000,
159
+ },
160
+ })
161
+ .build();
162
+ ```
163
+
164
+ ### Custom Retry Logic
165
+
166
+ ```typescript
167
+ import { withRetry } from 'societyai';
168
+
169
+ const result = await withRetry(
170
+ async () => {
171
+ return await someUnreliableOperation();
172
+ },
173
+ {
174
+ maxRetries: 3,
175
+ initialBackoff: 1000,
176
+ maxBackoff: 5000,
177
+ backoffFactor: 2,
178
+ jitter: true,
179
+ },
180
+ signal // Optional AbortSignal
181
+ );
182
+ ```
183
+
184
+ ## Timeout & Cancellation
185
+
186
+ ### Model-Level Timeout
187
+
188
+ ```typescript
189
+ const model = new StandardModelBase(
190
+ {
191
+ name: 'MyModel',
192
+ timeout: 30000, // 30 seconds
193
+ },
194
+ async (prompt) => {
195
+ return await apiCall(prompt);
196
+ }
197
+ );
198
+ ```
199
+
200
+ ### Workflow-Level Cancellation
201
+
202
+ ```typescript
203
+ const controller = new AbortController();
204
+
205
+ // Set a timeout
206
+ const timeoutId = setTimeout(() => {
207
+ controller.abort();
208
+ }, 60000); // 60 seconds
209
+
210
+ try {
211
+ const result = await executor.execute(workflow, input, controller.signal);
212
+ clearTimeout(timeoutId);
213
+ } catch (error) {
214
+ clearTimeout(timeoutId);
215
+ if (error.name === 'AbortError') {
216
+ console.log('Operation cancelled');
217
+ } else {
218
+ throw error;
219
+ }
220
+ }
221
+ ```
222
+
223
+ ### User-Triggered Cancellation
224
+
225
+ ```typescript
226
+ const controller = new AbortController();
227
+
228
+ // Start long-running operation
229
+ const promise = executor.execute(workflow, input, controller.signal);
230
+
231
+ // User clicks cancel button
232
+ cancelButton.addEventListener('click', () => {
233
+ controller.abort();
234
+ console.log('Cancelling workflow...');
235
+ });
236
+
237
+ try {
238
+ const result = await promise;
239
+ } catch (error) {
240
+ if (error.name === 'AbortError') {
241
+ console.log('User cancelled the operation');
242
+ }
243
+ }
244
+ ```
245
+
246
+ ## Observability
247
+
248
+ ### Complete Observer Implementation
249
+
250
+ ```typescript
251
+ import { SocietyObserver } from 'societyai';
252
+
253
+ class MetricsObserver implements SocietyObserver {
254
+ private startTime: number = 0;
255
+ private agentTimes: Map<number, number> = new Map();
256
+
257
+ onSocietyStart(prompt: string, agentCount: number): void {
258
+ this.startTime = Date.now();
259
+ console.log(`[SOCIETY] Starting with ${agentCount} agents`);
260
+ console.log(`[SOCIETY] Prompt: ${prompt.substring(0, 100)}...`);
261
+ }
262
+
263
+ onAgentStart(agentId: number, modelName: string, prompt: unknown): void {
264
+ this.agentTimes.set(agentId, Date.now());
265
+ console.log(`[AGENT ${agentId}] Started using ${modelName}`);
266
+ }
267
+
268
+ onAgentComplete(agentId: number, modelName: string, result: string): void {
269
+ const duration = Date.now() - (this.agentTimes.get(agentId) || 0);
270
+ console.log(`[AGENT ${agentId}] Completed in ${duration}ms`);
271
+ console.log(`[AGENT ${agentId}] Result length: ${result.length} chars`);
272
+ }
273
+
274
+ onAgentError(agentId: number, modelName: string, error: Error): void {
275
+ const duration = Date.now() - (this.agentTimes.get(agentId) || 0);
276
+ console.error(`[AGENT ${agentId}] Failed after ${duration}ms: ${error.message}`);
277
+ }
278
+
279
+ onPhaseStart(phase: string): void {
280
+ console.log(`[PHASE] Starting: ${phase}`);
281
+ }
282
+
283
+ onPhaseComplete(phase: string): void {
284
+ console.log(`[PHASE] Completed: ${phase}`);
285
+ }
286
+
287
+ onSocietyComplete(finalResult: string): void {
288
+ const totalDuration = Date.now() - this.startTime;
289
+ console.log(`[SOCIETY] Completed in ${totalDuration}ms`);
290
+ console.log(`[SOCIETY] Final result length: ${finalResult.length} chars`);
291
+ }
292
+ }
293
+
294
+ const observer = new MetricsObserver();
295
+ const executor = new DefaultWorkflowExecutor(observer);
296
+ ```
297
+
298
+ ### Logging Configuration
299
+
300
+ ```typescript
301
+ import { setGlobalLogLevel, LogLevel } from 'societyai';
302
+
303
+ // Development
304
+ setGlobalLogLevel(LogLevel.DEBUG);
305
+
306
+ // Production
307
+ setGlobalLogLevel(LogLevel.ERROR);
308
+
309
+ // Silent
310
+ setGlobalLogLevel(LogLevel.SILENT);
311
+ ```
312
+
313
+ ### Custom Logger
314
+
315
+ ```typescript
316
+ import { Logger, LogLevel } from 'societyai';
317
+
318
+ class CustomLogger implements Logger {
319
+ private level: LogLevel = LogLevel.INFO;
320
+
321
+ debug(message: string, ...args: unknown[]): void {
322
+ if (this.level >= LogLevel.DEBUG) {
323
+ // Send to external logging service
324
+ logService.debug(message, ...args);
325
+ }
326
+ }
327
+
328
+ info(message: string, ...args: unknown[]): void {
329
+ if (this.level >= LogLevel.INFO) {
330
+ logService.info(message, ...args);
331
+ }
332
+ }
333
+
334
+ error(message: string, ...args: unknown[]): void {
335
+ if (this.level >= LogLevel.ERROR) {
336
+ logService.error(message, ...args);
337
+ // Alert on errors
338
+ alerting.sendAlert(message);
339
+ }
340
+ }
341
+
342
+ setLevel(level: LogLevel): void {
343
+ this.level = level;
344
+ }
345
+ }
346
+ ```
347
+
348
+ ## Performance Optimization
349
+
350
+ ### 1. Use Parallel Execution
351
+
352
+ ```typescript
353
+ // Slow: Sequential
354
+ const slowStep = StepBuilder.create()
355
+ .withAgents(['agent-1', 'agent-2', 'agent-3'])
356
+ .withExecutionType('sequential')
357
+ .build();
358
+ // Total time: 3 * agent_time
359
+
360
+ // Fast: Parallel
361
+ const fastStep = StepBuilder.create()
362
+ .withAgents(['agent-1', 'agent-2', 'agent-3'])
363
+ .withExecutionType('parallel')
364
+ .build();
365
+ // Total time: max(agent_times)
366
+ ```
367
+
368
+ ### 2. Cache Expensive Results
369
+
370
+ ```typescript
371
+ const workflow = WorkflowConfigBuilder.create()
372
+ .onAfterStep(async (step, results, context) => {
373
+ if (step.id === 'expensive-analysis') {
374
+ // Cache the result
375
+ context.sharedData.set('cached-analysis', results[0].content);
376
+ }
377
+ })
378
+ .addSteps([
379
+ expensiveAnalysisStep,
380
+
381
+ StepBuilder.create()
382
+ .withId('use-cached')
383
+ .withExecutionType('conditional')
384
+ .withCondition((results) => {
385
+ // Skip if we have cached data
386
+ return !context.sharedData.has('cached-analysis');
387
+ })
388
+ .build(),
389
+ ])
390
+ .build();
391
+ ```
392
+
393
+ ### 3. Optimize Collaborative Iterations
394
+
395
+ ```typescript
396
+ // Limit iterations
397
+ const step = StepBuilder.create()
398
+ .withExecutionType('collaborative')
399
+ .withMaxIterations(3) // Not too high
400
+ .withCompletionCondition((results, iteration) => {
401
+ // Exit early when done
402
+ return checkConsensus(results) || iteration >= 2;
403
+ })
404
+ .build();
405
+ ```
406
+
407
+ ### 4. Worker Pool Sizing
408
+
409
+ The worker pool automatically sizes based on the number of agents, but you can optimize by:
410
+
411
+ - Grouping agents with similar workloads
412
+ - Balancing parallel steps
413
+ - Considering API rate limits
414
+
415
+ ### 5. Result Streaming
416
+
417
+ For large outputs, use result transformers to reduce data size:
418
+
419
+ ```typescript
420
+ const step = StepBuilder.create()
421
+ .withResultTransformer((results) => {
422
+ // Only keep essential data
423
+ return results.map((r) => ({
424
+ agentId: r.agentId,
425
+ summary: r.content.substring(0, 500),
426
+ keywords: extractKeywords(r.content),
427
+ }));
428
+ })
429
+ .build();
430
+ ```
431
+
432
+ ## Testing
433
+
434
+ ### Unit Testing Workflows
435
+
436
+ ```typescript
437
+ import { describe, it, expect } from 'jest';
438
+ import {
439
+ WorkflowConfigBuilder,
440
+ StepBuilder,
441
+ AgentBuilder,
442
+ RoleBuilder,
443
+ StandardModelBase,
444
+ DefaultWorkflowExecutor,
445
+ } from 'societyai';
446
+
447
+ // Mock model for testing
448
+ class MockModel extends StandardModelBase {
449
+ constructor(name: string, mockResponse: string) {
450
+ super({ name }, async () => mockResponse);
451
+ }
452
+ }
453
+
454
+ describe('MyWorkflow', () => {
455
+ it('should complete successfully', async () => {
456
+ const model = new MockModel('test', 'Mock response');
457
+
458
+ const role = RoleBuilder.create().withId('test-role').withSystemPrompt('Test prompt').build();
459
+
460
+ const agent = AgentBuilder.create()
461
+ .withId('test-agent')
462
+ .withRole(role)
463
+ .withModel(model)
464
+ .build();
465
+
466
+ const workflow = WorkflowConfigBuilder.create()
467
+ .withId('test-workflow')
468
+ .addAgent(agent)
469
+ .addStep(StepBuilder.create().withId('test-step').withAgents(['test-agent']).build())
470
+ .build();
471
+
472
+ const executor = new DefaultWorkflowExecutor();
473
+ const result = await executor.execute(workflow, 'test input');
474
+
475
+ expect(result.success).toBe(true);
476
+ expect(result.output).toContain('Mock response');
477
+ });
478
+
479
+ it('should handle errors gracefully', async () => {
480
+ const errorModel = new StandardModelBase({ name: 'error-model' }, async () => {
481
+ throw new Error('Test error');
482
+ });
483
+
484
+ // Test error handling...
485
+ });
486
+ });
487
+ ```
488
+
489
+ ### Integration Testing
490
+
491
+ ```typescript
492
+ describe('Integration Tests', () => {
493
+ it('should work with real API', async () => {
494
+ const apiKey = process.env.OPENAI_API_KEY;
495
+ if (!apiKey) {
496
+ console.log('Skipping integration test (no API key)');
497
+ return;
498
+ }
499
+
500
+ const model = new OpenAIModel(apiKey);
501
+ // Test with real model...
502
+ });
503
+ });
504
+ ```
505
+
506
+ ## Production Deployment
507
+
508
+ ### Environment Configuration
509
+
510
+ ```typescript
511
+ // config.ts
512
+ export const config = {
513
+ ai: {
514
+ apiKey: process.env.OPENAI_API_KEY!,
515
+ timeout: parseInt(process.env.AI_TIMEOUT || '30000'),
516
+ maxRetries: parseInt(process.env.AI_MAX_RETRIES || '3'),
517
+ },
518
+ logging: {
519
+ level: process.env.LOG_LEVEL === 'debug' ? LogLevel.DEBUG : LogLevel.INFO,
520
+ },
521
+ workflow: {
522
+ maxConcurrency: parseInt(process.env.MAX_CONCURRENCY || '5'),
523
+ },
524
+ };
525
+ ```
526
+
527
+ ### Monitoring
528
+
529
+ ```typescript
530
+ class ProductionObserver implements SocietyObserver {
531
+ onSocietyStart(prompt: string, agentCount: number): void {
532
+ metrics.increment('workflow.started');
533
+ metrics.gauge('workflow.agent_count', agentCount);
534
+ }
535
+
536
+ onAgentComplete(agentId: number, modelName: string, result: string): void {
537
+ metrics.increment('agent.completed');
538
+ metrics.histogram('agent.result_length', result.length);
539
+ }
540
+
541
+ onAgentError(agentId: number, modelName: string, error: Error): void {
542
+ metrics.increment('agent.error');
543
+ errorTracking.captureException(error);
544
+ }
545
+
546
+ onSocietyComplete(finalResult: string): void {
547
+ metrics.increment('workflow.completed');
548
+ }
549
+ }
550
+ ```
551
+
552
+ ### Rate Limiting
553
+
554
+ ```typescript
555
+ class RateLimitedModel extends StandardModelBase {
556
+ private queue: Array<() => void> = [];
557
+ private activeRequests = 0;
558
+ private maxConcurrent = 5;
559
+
560
+ constructor(baseModel: AIModel) {
561
+ super({ name: baseModel.name() }, async (prompt, signal) => {
562
+ await this.acquireSlot();
563
+ try {
564
+ return await baseModel.process(prompt, signal);
565
+ } finally {
566
+ this.releaseSlot();
567
+ }
568
+ });
569
+ }
570
+
571
+ private async acquireSlot(): Promise<void> {
572
+ if (this.activeRequests < this.maxConcurrent) {
573
+ this.activeRequests++;
574
+ return;
575
+ }
576
+
577
+ return new Promise((resolve) => {
578
+ this.queue.push(resolve);
579
+ });
580
+ }
581
+
582
+ private releaseSlot(): void {
583
+ this.activeRequests--;
584
+ const next = this.queue.shift();
585
+ if (next) {
586
+ this.activeRequests++;
587
+ next();
588
+ }
589
+ }
590
+ }
591
+ ```
592
+
593
+ ### Graceful Shutdown
594
+
595
+ ```typescript
596
+ const controller = new AbortController();
597
+
598
+ process.on('SIGTERM', () => {
599
+ console.log('Received SIGTERM, shutting down gracefully...');
600
+ controller.abort();
601
+ });
602
+
603
+ try {
604
+ await executor.execute(workflow, input, controller.signal);
605
+ } catch (error) {
606
+ if (error.name === 'AbortError') {
607
+ console.log('Workflow cancelled during shutdown');
608
+ }
609
+ }
610
+ ```
611
+
612
+ ---
613
+
614
+ **Next**: [Migration Guide](./migration.md) →
615
+
616
+ **Previous**: [API Reference](./api-reference.md) ←