ai-functions 2.1.1 → 2.3.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 (286) hide show
  1. package/.turbo/turbo-build.log +1 -4
  2. package/CHANGELOG.md +68 -1
  3. package/README.md +397 -157
  4. package/dist/ai-promise.d.ts +50 -3
  5. package/dist/ai-promise.d.ts.map +1 -1
  6. package/dist/ai-promise.js +410 -51
  7. package/dist/ai-promise.js.map +1 -1
  8. package/dist/ai-schemas.d.ts +56 -0
  9. package/dist/ai-schemas.d.ts.map +1 -0
  10. package/dist/ai-schemas.js +53 -0
  11. package/dist/ai-schemas.js.map +1 -0
  12. package/dist/ai.d.ts +16 -242
  13. package/dist/ai.d.ts.map +1 -1
  14. package/dist/ai.js +54 -837
  15. package/dist/ai.js.map +1 -1
  16. package/dist/batch/anthropic.d.ts +6 -4
  17. package/dist/batch/anthropic.d.ts.map +1 -1
  18. package/dist/batch/anthropic.js +83 -145
  19. package/dist/batch/anthropic.js.map +1 -1
  20. package/dist/batch/bedrock.d.ts +8 -30
  21. package/dist/batch/bedrock.d.ts.map +1 -1
  22. package/dist/batch/bedrock.js +155 -338
  23. package/dist/batch/bedrock.js.map +1 -1
  24. package/dist/batch/cloudflare.d.ts +8 -20
  25. package/dist/batch/cloudflare.d.ts.map +1 -1
  26. package/dist/batch/cloudflare.js +68 -189
  27. package/dist/batch/cloudflare.js.map +1 -1
  28. package/dist/batch/google.d.ts +6 -20
  29. package/dist/batch/google.d.ts.map +1 -1
  30. package/dist/batch/google.js +70 -238
  31. package/dist/batch/google.js.map +1 -1
  32. package/dist/batch/index.d.ts +4 -1
  33. package/dist/batch/index.d.ts.map +1 -1
  34. package/dist/batch/index.js +4 -1
  35. package/dist/batch/index.js.map +1 -1
  36. package/dist/batch/memory.d.ts +1 -1
  37. package/dist/batch/memory.d.ts.map +1 -1
  38. package/dist/batch/memory.js +14 -10
  39. package/dist/batch/memory.js.map +1 -1
  40. package/dist/batch/openai.d.ts +11 -14
  41. package/dist/batch/openai.d.ts.map +1 -1
  42. package/dist/batch/openai.js +52 -156
  43. package/dist/batch/openai.js.map +1 -1
  44. package/dist/batch/provider.d.ts +111 -0
  45. package/dist/batch/provider.d.ts.map +1 -0
  46. package/dist/batch/provider.js +233 -0
  47. package/dist/batch/provider.js.map +1 -0
  48. package/dist/batch-map.d.ts.map +1 -1
  49. package/dist/batch-map.js +23 -17
  50. package/dist/batch-map.js.map +1 -1
  51. package/dist/batch-queue.d.ts +65 -0
  52. package/dist/batch-queue.d.ts.map +1 -1
  53. package/dist/batch-queue.js +169 -14
  54. package/dist/batch-queue.js.map +1 -1
  55. package/dist/budget.d.ts +272 -0
  56. package/dist/budget.d.ts.map +1 -0
  57. package/dist/budget.js +513 -0
  58. package/dist/budget.js.map +1 -0
  59. package/dist/cache.d.ts +295 -0
  60. package/dist/cache.d.ts.map +1 -0
  61. package/dist/cache.js +433 -0
  62. package/dist/cache.js.map +1 -0
  63. package/dist/context.d.ts +42 -8
  64. package/dist/context.d.ts.map +1 -1
  65. package/dist/context.js +64 -62
  66. package/dist/context.js.map +1 -1
  67. package/dist/digital-objects-registry.d.ts +229 -0
  68. package/dist/digital-objects-registry.d.ts.map +1 -0
  69. package/dist/digital-objects-registry.js +617 -0
  70. package/dist/digital-objects-registry.js.map +1 -0
  71. package/dist/embeddings.d.ts +2 -2
  72. package/dist/embeddings.d.ts.map +1 -1
  73. package/dist/errors.d.ts +22 -0
  74. package/dist/errors.d.ts.map +1 -0
  75. package/dist/errors.js +35 -0
  76. package/dist/errors.js.map +1 -0
  77. package/dist/eval/runner.d.ts +10 -1
  78. package/dist/eval/runner.d.ts.map +1 -1
  79. package/dist/eval/runner.js +41 -35
  80. package/dist/eval/runner.js.map +1 -1
  81. package/dist/eval-log/in-memory.d.ts +34 -0
  82. package/dist/eval-log/in-memory.d.ts.map +1 -0
  83. package/dist/eval-log/in-memory.js +84 -0
  84. package/dist/eval-log/in-memory.js.map +1 -0
  85. package/dist/eval-log/index.d.ts +29 -0
  86. package/dist/eval-log/index.d.ts.map +1 -0
  87. package/dist/eval-log/index.js +39 -0
  88. package/dist/eval-log/index.js.map +1 -0
  89. package/dist/eval-log/types.d.ts +101 -0
  90. package/dist/eval-log/types.d.ts.map +1 -0
  91. package/dist/eval-log/types.js +16 -0
  92. package/dist/eval-log/types.js.map +1 -0
  93. package/dist/function-registry.d.ts +116 -0
  94. package/dist/function-registry.d.ts.map +1 -0
  95. package/dist/function-registry.js +546 -0
  96. package/dist/function-registry.js.map +1 -0
  97. package/dist/generate.d.ts +9 -3
  98. package/dist/generate.d.ts.map +1 -1
  99. package/dist/generate.js +18 -22
  100. package/dist/generate.js.map +1 -1
  101. package/dist/index.d.ts +35 -20
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +89 -42
  104. package/dist/index.js.map +1 -1
  105. package/dist/logger.d.ts +118 -0
  106. package/dist/logger.d.ts.map +1 -0
  107. package/dist/logger.js +187 -0
  108. package/dist/logger.js.map +1 -0
  109. package/dist/middleware/budget.d.ts +84 -0
  110. package/dist/middleware/budget.d.ts.map +1 -0
  111. package/dist/middleware/budget.js +110 -0
  112. package/dist/middleware/budget.js.map +1 -0
  113. package/dist/middleware/cache.d.ts +103 -0
  114. package/dist/middleware/cache.d.ts.map +1 -0
  115. package/dist/middleware/cache.js +228 -0
  116. package/dist/middleware/cache.js.map +1 -0
  117. package/dist/middleware/embed-cache.d.ts +99 -0
  118. package/dist/middleware/embed-cache.d.ts.map +1 -0
  119. package/dist/middleware/embed-cache.js +128 -0
  120. package/dist/middleware/embed-cache.js.map +1 -0
  121. package/dist/middleware/index.d.ts +11 -0
  122. package/dist/middleware/index.d.ts.map +1 -0
  123. package/dist/middleware/index.js +11 -0
  124. package/dist/middleware/index.js.map +1 -0
  125. package/dist/middleware/trace.d.ts +103 -0
  126. package/dist/middleware/trace.d.ts.map +1 -0
  127. package/dist/middleware/trace.js +176 -0
  128. package/dist/middleware/trace.js.map +1 -0
  129. package/dist/primitives.d.ts +120 -1
  130. package/dist/primitives.d.ts.map +1 -1
  131. package/dist/primitives.js +398 -26
  132. package/dist/primitives.js.map +1 -1
  133. package/dist/retry.d.ts +368 -0
  134. package/dist/retry.d.ts.map +1 -0
  135. package/dist/retry.js +646 -0
  136. package/dist/retry.js.map +1 -0
  137. package/dist/schema.d.ts.map +1 -1
  138. package/dist/schema.js +2 -10
  139. package/dist/schema.js.map +1 -1
  140. package/dist/telemetry.d.ts +128 -0
  141. package/dist/telemetry.d.ts.map +1 -0
  142. package/dist/telemetry.js +285 -0
  143. package/dist/telemetry.js.map +1 -0
  144. package/dist/template.d.ts.map +1 -1
  145. package/dist/template.js +6 -1
  146. package/dist/template.js.map +1 -1
  147. package/dist/tool-orchestration.d.ts +453 -0
  148. package/dist/tool-orchestration.d.ts.map +1 -0
  149. package/dist/tool-orchestration.js +763 -0
  150. package/dist/tool-orchestration.js.map +1 -0
  151. package/dist/type-guards.d.ts +28 -0
  152. package/dist/type-guards.d.ts.map +1 -0
  153. package/dist/type-guards.js +29 -0
  154. package/dist/type-guards.js.map +1 -0
  155. package/dist/types.d.ts +135 -17
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/types.js +36 -1
  158. package/dist/types.js.map +1 -1
  159. package/dist/wrap-for-v3.d.ts +80 -0
  160. package/dist/wrap-for-v3.d.ts.map +1 -0
  161. package/dist/wrap-for-v3.js +89 -0
  162. package/dist/wrap-for-v3.js.map +1 -0
  163. package/examples/00-quickstart.ts +232 -0
  164. package/examples/01-rag-chatbot.ts +212 -0
  165. package/examples/02-multi-agent-research.ts +290 -0
  166. package/examples/03-email-classification.ts +379 -0
  167. package/examples/04-content-moderation.ts +400 -0
  168. package/examples/05-document-extraction.ts +455 -0
  169. package/examples/06-streaming-chat-nextjs.ts +437 -0
  170. package/examples/07-cloudflare-worker.ts +483 -0
  171. package/examples/08-batch-processing.ts +491 -0
  172. package/examples/09-budget-constrained.ts +527 -0
  173. package/examples/10-tool-orchestration.ts +565 -0
  174. package/examples/11-retry-resilience.ts +403 -0
  175. package/examples/12-caching-strategies.ts +422 -0
  176. package/examples/README.md +145 -0
  177. package/package.json +10 -6
  178. package/src/ai-promise.ts +528 -99
  179. package/src/ai-schemas.ts +122 -0
  180. package/src/ai.ts +69 -1153
  181. package/src/batch/anthropic.ts +96 -161
  182. package/src/batch/bedrock.ts +203 -454
  183. package/src/batch/cloudflare.ts +99 -282
  184. package/src/batch/google.ts +91 -297
  185. package/src/batch/index.ts +4 -1
  186. package/src/batch/memory.ts +15 -10
  187. package/src/batch/openai.ts +65 -193
  188. package/src/batch/provider.ts +336 -0
  189. package/src/batch-map.ts +29 -24
  190. package/src/batch-queue.ts +200 -11
  191. package/src/budget.ts +740 -0
  192. package/src/cache.ts +681 -0
  193. package/src/context.ts +122 -76
  194. package/src/digital-objects-registry.ts +750 -0
  195. package/src/errors.ts +37 -0
  196. package/src/eval/runner.ts +63 -38
  197. package/src/eval-log/in-memory.ts +90 -0
  198. package/src/eval-log/index.ts +46 -0
  199. package/src/eval-log/types.ts +110 -0
  200. package/src/function-registry.ts +671 -0
  201. package/src/generate.ts +33 -33
  202. package/src/index.ts +325 -49
  203. package/src/logger.ts +232 -0
  204. package/src/middleware/budget.ts +171 -0
  205. package/src/middleware/cache.ts +299 -0
  206. package/src/middleware/embed-cache.ts +195 -0
  207. package/src/middleware/index.ts +23 -0
  208. package/src/middleware/trace.ts +248 -0
  209. package/src/primitives.ts +589 -62
  210. package/src/retry.ts +902 -0
  211. package/src/schema.ts +8 -17
  212. package/src/telemetry.ts +403 -0
  213. package/src/template.ts +8 -4
  214. package/src/tool-orchestration.ts +1173 -0
  215. package/src/type-guards.ts +31 -0
  216. package/src/types.ts +164 -25
  217. package/src/wrap-for-v3.ts +105 -0
  218. package/test/ai-promise.test.ts +1080 -0
  219. package/test/ai-proxy.test.ts +1 -1
  220. package/test/backward-compat.test.ts +147 -0
  221. package/test/batch-autosubmit-errors.test.ts +610 -0
  222. package/test/batch-blog-posts.test.ts +87 -129
  223. package/test/budget-tracking.test.ts +800 -0
  224. package/test/cache.test.ts +712 -0
  225. package/test/context-isolation.test.ts +687 -0
  226. package/test/core-functions.test.ts +183 -579
  227. package/test/decide.test.ts +154 -322
  228. package/test/define.test.ts +211 -8
  229. package/test/digital-objects-registry.test.ts +760 -0
  230. package/test/embedding-cache-middleware.test.ts +140 -0
  231. package/test/evals/deterministic.eval.test.ts +376 -0
  232. package/test/generate-core.test.ts +140 -229
  233. package/test/implicit-batch.test.ts +22 -65
  234. package/test/json-parse-error-handling.test.ts +463 -0
  235. package/test/retry-policy-integration.test.ts +117 -0
  236. package/test/retry.test.ts +1016 -0
  237. package/test/schema.test.ts +55 -19
  238. package/test/streaming.test.ts +316 -0
  239. package/test/template.test.ts +1164 -0
  240. package/test/tool-orchestration.test.ts +1040 -0
  241. package/test/wrap-for-v3.test.ts +612 -0
  242. package/vitest.config.js +6 -0
  243. package/vitest.config.ts +20 -0
  244. package/dist/rpc/auth.d.ts +0 -69
  245. package/dist/rpc/auth.d.ts.map +0 -1
  246. package/dist/rpc/auth.js +0 -136
  247. package/dist/rpc/auth.js.map +0 -1
  248. package/dist/rpc/client.d.ts +0 -62
  249. package/dist/rpc/client.d.ts.map +0 -1
  250. package/dist/rpc/client.js +0 -103
  251. package/dist/rpc/client.js.map +0 -1
  252. package/dist/rpc/deferred.d.ts +0 -60
  253. package/dist/rpc/deferred.d.ts.map +0 -1
  254. package/dist/rpc/deferred.js +0 -96
  255. package/dist/rpc/deferred.js.map +0 -1
  256. package/dist/rpc/index.d.ts +0 -22
  257. package/dist/rpc/index.d.ts.map +0 -1
  258. package/dist/rpc/index.js +0 -38
  259. package/dist/rpc/index.js.map +0 -1
  260. package/dist/rpc/local.d.ts +0 -42
  261. package/dist/rpc/local.d.ts.map +0 -1
  262. package/dist/rpc/local.js +0 -50
  263. package/dist/rpc/local.js.map +0 -1
  264. package/dist/rpc/server.d.ts +0 -165
  265. package/dist/rpc/server.d.ts.map +0 -1
  266. package/dist/rpc/server.js +0 -405
  267. package/dist/rpc/server.js.map +0 -1
  268. package/dist/rpc/session.d.ts +0 -32
  269. package/dist/rpc/session.d.ts.map +0 -1
  270. package/dist/rpc/session.js +0 -43
  271. package/dist/rpc/session.js.map +0 -1
  272. package/dist/rpc/transport.d.ts +0 -306
  273. package/dist/rpc/transport.d.ts.map +0 -1
  274. package/dist/rpc/transport.js +0 -731
  275. package/dist/rpc/transport.js.map +0 -1
  276. package/src/batch/anthropic.js +0 -256
  277. package/src/batch/bedrock.js +0 -584
  278. package/src/batch/cloudflare.js +0 -287
  279. package/src/batch/google.js +0 -359
  280. package/src/batch/index.js +0 -30
  281. package/src/batch/memory.js +0 -187
  282. package/src/batch/openai.js +0 -402
  283. package/src/eval/index.js +0 -7
  284. package/src/eval/models.js +0 -119
  285. package/src/eval/runner.js +0 -147
  286. package/test/schema.test.js +0 -96
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Retry and Resilience Patterns Example
3
+ *
4
+ * This example demonstrates building resilient AI applications using ai-functions.
5
+ * It shows how to:
6
+ * - Implement retry logic with exponential backoff
7
+ * - Use circuit breakers for fail-fast behavior
8
+ * - Create fallback chains across models
9
+ * - Handle rate limits and transient errors
10
+ *
11
+ * @example
12
+ * ```bash
13
+ * ANTHROPIC_API_KEY=sk-... npx tsx examples/11-retry-resilience.ts
14
+ * ```
15
+ */
16
+
17
+ import {
18
+ write,
19
+ ai,
20
+ configure,
21
+ withRetry,
22
+ RetryPolicy,
23
+ CircuitBreaker,
24
+ FallbackChain,
25
+ RetryableError,
26
+ RateLimitError,
27
+ classifyError,
28
+ calculateBackoff,
29
+ type RetryOptions,
30
+ type JitterStrategy,
31
+ } from '../src/index.js'
32
+
33
+ // ============================================================================
34
+ // Basic Retry with withRetry
35
+ // ============================================================================
36
+
37
+ async function basicRetryExample(): Promise<void> {
38
+ console.log('\n=== Basic Retry with withRetry() ===\n')
39
+
40
+ // Simple retry wrapper
41
+ const reliableGenerate = async (prompt: string): Promise<string> => {
42
+ return withRetry(async () => write`${prompt}`, {
43
+ maxRetries: 3,
44
+ baseDelay: 1000,
45
+ jitter: 0.2, // Add 20% random jitter
46
+ })
47
+ }
48
+
49
+ console.log('Generating with retry protection...')
50
+ const result = await reliableGenerate('Say hello in one word')
51
+ console.log(`Result: ${result}`)
52
+ }
53
+
54
+ // ============================================================================
55
+ // RetryPolicy - Advanced Configuration
56
+ // ============================================================================
57
+
58
+ async function retryPolicyExample(): Promise<void> {
59
+ console.log('\n=== RetryPolicy - Advanced Configuration ===\n')
60
+
61
+ // Create a reusable retry policy
62
+ const policy = new RetryPolicy({
63
+ maxRetries: 5,
64
+ baseDelay: 1000,
65
+ maxDelay: 30000,
66
+ jitterStrategy: 'decorrelated', // Better than simple jitter for distributed systems
67
+ shouldRetry: (error, attempt) => {
68
+ // Custom retry decision logic
69
+ console.log(` Attempt ${attempt}: ${error.message}`)
70
+
71
+ // Don't retry authentication errors
72
+ if (error.message.includes('auth')) {
73
+ return false
74
+ }
75
+
76
+ // Retry rate limits with longer delay
77
+ if (error.message.includes('rate limit')) {
78
+ return true
79
+ }
80
+
81
+ return attempt < 5
82
+ },
83
+ onRetry: (error, attempt, delay) => {
84
+ console.log(` Retrying in ${delay}ms (attempt ${attempt})...`)
85
+ },
86
+ })
87
+
88
+ // Simulate a function that might fail
89
+ let attempts = 0
90
+ const flakyFunction = async (): Promise<string> => {
91
+ attempts++
92
+ if (attempts < 3) {
93
+ throw new RetryableError('Temporary failure')
94
+ }
95
+ return 'Success!'
96
+ }
97
+
98
+ console.log('Executing with RetryPolicy...')
99
+ try {
100
+ const result = await policy.execute(flakyFunction)
101
+ console.log(`Result: ${result} (after ${attempts} attempts)`)
102
+ } catch (error) {
103
+ console.log(`Failed: ${(error as Error).message}`)
104
+ }
105
+ }
106
+
107
+ // ============================================================================
108
+ // Jitter Strategies
109
+ // ============================================================================
110
+
111
+ async function jitterStrategiesExample(): Promise<void> {
112
+ console.log('\n=== Jitter Strategies ===\n')
113
+
114
+ const strategies: JitterStrategy[] = ['none', 'full', 'equal', 'decorrelated']
115
+
116
+ console.log('Backoff delays with different jitter strategies:')
117
+ console.log('(Base delay: 1000ms, Max delay: 30000ms)\n')
118
+
119
+ for (const strategy of strategies) {
120
+ console.log(`${strategy}:`)
121
+ let prevDelay = 1000
122
+
123
+ for (let attempt = 1; attempt <= 5; attempt++) {
124
+ const delay = calculateBackoff(attempt, {
125
+ baseDelay: 1000,
126
+ maxDelay: 30000,
127
+ jitterStrategy: strategy,
128
+ previousDelay: prevDelay,
129
+ })
130
+ console.log(` Attempt ${attempt}: ${Math.round(delay)}ms`)
131
+ prevDelay = delay
132
+ }
133
+ console.log('')
134
+ }
135
+ }
136
+
137
+ // ============================================================================
138
+ // Circuit Breaker Pattern
139
+ // ============================================================================
140
+
141
+ async function circuitBreakerExample(): Promise<void> {
142
+ console.log('\n=== Circuit Breaker Pattern ===\n')
143
+
144
+ const breaker = new CircuitBreaker({
145
+ failureThreshold: 3, // Open after 3 failures
146
+ resetTimeout: 5000, // Try again after 5 seconds
147
+ halfOpenMaxAttempts: 2, // Allow 2 attempts in half-open
148
+ onStateChange: (from, to) => {
149
+ console.log(` Circuit state: ${from} -> ${to}`)
150
+ },
151
+ })
152
+
153
+ // Simulate failures
154
+ let callCount = 0
155
+ const unreliableService = async (): Promise<string> => {
156
+ callCount++
157
+ if (callCount <= 4) {
158
+ throw new Error('Service unavailable')
159
+ }
160
+ return 'Success!'
161
+ }
162
+
163
+ console.log('Making calls through circuit breaker...\n')
164
+
165
+ for (let i = 1; i <= 8; i++) {
166
+ try {
167
+ const result = await breaker.execute(unreliableService)
168
+ console.log(` Call ${i}: ${result}`)
169
+ } catch (error) {
170
+ console.log(` Call ${i}: ${(error as Error).message}`)
171
+ }
172
+
173
+ // Small delay between calls
174
+ await new Promise((r) => setTimeout(r, 500))
175
+ }
176
+
177
+ // Show circuit metrics
178
+ const metrics = breaker.getMetrics()
179
+ console.log('\nCircuit Breaker Metrics:')
180
+ console.log(` State: ${metrics.state}`)
181
+ console.log(` Failures: ${metrics.failures}`)
182
+ console.log(` Successes: ${metrics.successes}`)
183
+ console.log(` Consecutive Failures: ${metrics.consecutiveFailures}`)
184
+ }
185
+
186
+ // ============================================================================
187
+ // Fallback Chain
188
+ // ============================================================================
189
+
190
+ async function fallbackChainExample(): Promise<void> {
191
+ console.log('\n=== Fallback Chain ===\n')
192
+
193
+ // Simulate different model behaviors
194
+ const claudeCall = async () => {
195
+ console.log(' Trying Claude Sonnet...')
196
+ // Simulate occasional failure
197
+ if (Math.random() < 0.7) {
198
+ throw new Error('Claude temporarily unavailable')
199
+ }
200
+ return 'Response from Claude Sonnet'
201
+ }
202
+
203
+ const gptCall = async () => {
204
+ console.log(' Trying GPT-4o...')
205
+ // Simulate occasional failure
206
+ if (Math.random() < 0.5) {
207
+ throw new Error('GPT-4o rate limited')
208
+ }
209
+ return 'Response from GPT-4o'
210
+ }
211
+
212
+ const haikuCall = async () => {
213
+ console.log(' Trying Claude Haiku...')
214
+ return 'Response from Claude Haiku (fallback)'
215
+ }
216
+
217
+ // Create fallback chain
218
+ const chain = new FallbackChain([
219
+ { name: 'claude-sonnet', execute: claudeCall },
220
+ { name: 'gpt-4o', execute: gptCall },
221
+ { name: 'claude-haiku', execute: haikuCall }, // Always succeeds
222
+ ])
223
+
224
+ console.log('Executing with fallback chain:\n')
225
+
226
+ // Try a few times to see different paths
227
+ for (let i = 1; i <= 3; i++) {
228
+ console.log(`Attempt ${i}:`)
229
+ const result = await chain.execute()
230
+ console.log(` Result: ${result}\n`)
231
+ }
232
+
233
+ // Show metrics
234
+ const metrics = chain.getMetrics()
235
+ console.log('Fallback Chain Metrics:')
236
+ for (const [name, m] of Object.entries(metrics)) {
237
+ console.log(` ${name}: ${m.successes} successes, ${m.failures} failures`)
238
+ }
239
+ }
240
+
241
+ // ============================================================================
242
+ // Error Classification
243
+ // ============================================================================
244
+
245
+ async function errorClassificationExample(): Promise<void> {
246
+ console.log('\n=== Error Classification ===\n')
247
+
248
+ const errors = [
249
+ new Error('Request timeout'),
250
+ new Error('Rate limit exceeded'),
251
+ new Error('Invalid API key'),
252
+ new Error('Connection refused'),
253
+ new Error('Internal server error'),
254
+ new RateLimitError('Too many requests', 60),
255
+ ]
256
+
257
+ console.log('Classifying errors:\n')
258
+
259
+ for (const error of errors) {
260
+ const category = classifyError(error)
261
+ const shouldRetry = category === 'transient' || category === 'rate_limit'
262
+
263
+ console.log(` "${error.message}"`)
264
+ console.log(` Category: ${category}`)
265
+ console.log(` Should retry: ${shouldRetry}`)
266
+
267
+ if (error instanceof RateLimitError) {
268
+ console.log(` Retry after: ${error.retryAfter}s`)
269
+ }
270
+ console.log('')
271
+ }
272
+ }
273
+
274
+ // ============================================================================
275
+ // Combined Resilience Pattern
276
+ // ============================================================================
277
+
278
+ async function combinedResilienceExample(): Promise<void> {
279
+ console.log('\n=== Combined Resilience Pattern ===\n')
280
+
281
+ // Create circuit breaker
282
+ const breaker = new CircuitBreaker({
283
+ failureThreshold: 5,
284
+ resetTimeout: 10000,
285
+ })
286
+
287
+ // Create retry policy
288
+ const retryPolicy = new RetryPolicy({
289
+ maxRetries: 3,
290
+ baseDelay: 1000,
291
+ maxDelay: 5000,
292
+ jitterStrategy: 'decorrelated',
293
+ })
294
+
295
+ // Create fallback chain
296
+ const fallbackChain = new FallbackChain([
297
+ {
298
+ name: 'primary',
299
+ execute: async () => {
300
+ // Wrap in circuit breaker and retry
301
+ return breaker.execute(() =>
302
+ retryPolicy.execute(async () => {
303
+ // Simulate primary service
304
+ return write`Hello world`
305
+ })
306
+ )
307
+ },
308
+ },
309
+ {
310
+ name: 'fallback',
311
+ execute: async () => {
312
+ // Simpler fallback with just retry
313
+ return retryPolicy.execute(async () => {
314
+ return 'Fallback response'
315
+ })
316
+ },
317
+ },
318
+ ])
319
+
320
+ console.log('Combined resilience: Fallback -> Circuit Breaker -> Retry\n')
321
+
322
+ const result = await fallbackChain.execute()
323
+ console.log(`Result: ${result}`)
324
+
325
+ console.log(`
326
+ This pattern provides:
327
+ 1. Automatic retries with exponential backoff
328
+ 2. Circuit breaker to prevent cascading failures
329
+ 3. Fallback to alternative services when primary fails
330
+ `)
331
+ }
332
+
333
+ // ============================================================================
334
+ // Production Recommendations
335
+ // ============================================================================
336
+
337
+ function showProductionRecommendations(): void {
338
+ console.log('\n=== Production Recommendations ===\n')
339
+
340
+ console.log(`
341
+ 1. RETRY CONFIGURATION
342
+ - Start with 3 retries, adjust based on SLAs
343
+ - Use decorrelated jitter for distributed systems
344
+ - Set maxDelay to prevent infinite waits
345
+ - Respect Retry-After headers from providers
346
+
347
+ 2. CIRCUIT BREAKER
348
+ - Set failureThreshold based on error budget
349
+ - resetTimeout should match service recovery time
350
+ - Monitor state changes for alerting
351
+ - Use separate breakers for different services
352
+
353
+ 3. FALLBACK CHAINS
354
+ - Order by quality: best -> acceptable -> minimal
355
+ - Consider cost differences between models
356
+ - Log which model was used for debugging
357
+ - Set timeouts per fallback option
358
+
359
+ 4. ERROR HANDLING
360
+ - Classify errors to determine retry strategy
361
+ - Don't retry authentication errors
362
+ - Rate limit errors: use Retry-After header
363
+ - Log all errors with request IDs
364
+
365
+ 5. MONITORING
366
+ - Track retry rates and success/failure ratios
367
+ - Alert on circuit breaker state changes
368
+ - Monitor fallback usage patterns
369
+ - Set up dashboards for resilience metrics
370
+ `)
371
+ }
372
+
373
+ // ============================================================================
374
+ // Main
375
+ // ============================================================================
376
+
377
+ async function main() {
378
+ console.log('\n=== Retry and Resilience Patterns Example ===')
379
+
380
+ configure({
381
+ model: 'sonnet',
382
+ provider: 'anthropic',
383
+ })
384
+
385
+ await basicRetryExample()
386
+ await retryPolicyExample()
387
+ await jitterStrategiesExample()
388
+ await circuitBreakerExample()
389
+ await fallbackChainExample()
390
+ await errorClassificationExample()
391
+ await combinedResilienceExample()
392
+ showProductionRecommendations()
393
+ }
394
+
395
+ main()
396
+ .then(() => {
397
+ console.log('\n=== Example Complete ===\n')
398
+ process.exit(0)
399
+ })
400
+ .catch((error) => {
401
+ console.error('\nError:', error.message)
402
+ process.exit(1)
403
+ })