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,422 @@
1
+ /**
2
+ * Caching Strategies Example
3
+ *
4
+ * This example demonstrates intelligent caching for AI operations using ai-functions.
5
+ * It shows how to:
6
+ * - Use MemoryCache for general caching
7
+ * - Cache generation results with GenerationCache
8
+ * - Cache embeddings with EmbeddingCache
9
+ * - Wrap functions with automatic caching
10
+ *
11
+ * @example
12
+ * ```bash
13
+ * ANTHROPIC_API_KEY=sk-... npx tsx examples/12-caching-strategies.ts
14
+ * ```
15
+ */
16
+
17
+ import {
18
+ write,
19
+ ai,
20
+ list,
21
+ configure,
22
+ MemoryCache,
23
+ GenerationCache,
24
+ EmbeddingCache,
25
+ withCache,
26
+ hashKey,
27
+ createCacheKey,
28
+ type CacheEntry,
29
+ type CacheStats,
30
+ } from '../src/index.js'
31
+
32
+ // ============================================================================
33
+ // Basic MemoryCache
34
+ // ============================================================================
35
+
36
+ async function memoryCacheExample(): Promise<void> {
37
+ console.log('\n=== MemoryCache - Basic Usage ===\n')
38
+
39
+ const cache = new MemoryCache({
40
+ maxSize: 100, // Max 100 entries
41
+ defaultTTL: 60000, // 1 minute TTL
42
+ })
43
+
44
+ // Store and retrieve values
45
+ await cache.set('greeting', 'Hello, World!')
46
+ await cache.set('number', 42, { ttl: 5000 }) // 5 second TTL
47
+ await cache.set('user', { name: 'Alice', email: 'alice@example.com' }, { ttl: 30000 })
48
+
49
+ console.log('Stored values:')
50
+ console.log(` greeting: ${await cache.get('greeting')}`)
51
+ console.log(` number: ${await cache.get('number')}`)
52
+ console.log(` user: ${JSON.stringify(await cache.get('user'))}`)
53
+
54
+ // Check if key exists
55
+ console.log(`\n Has 'greeting': ${await cache.has('greeting')}`)
56
+ console.log(` Has 'missing': ${await cache.has('missing')}`)
57
+
58
+ // Get stats
59
+ const stats = cache.getStats()
60
+ console.log('\nCache Stats:')
61
+ console.log(` Size: ${stats.size}`)
62
+ console.log(` Hits: ${stats.hits}`)
63
+ console.log(` Misses: ${stats.misses}`)
64
+ console.log(` Hit Rate: ${((stats.hitRate || 0) * 100).toFixed(1)}%`)
65
+
66
+ // Clear specific key
67
+ await cache.delete('number')
68
+ console.log(`\n After delete, has 'number': ${await cache.has('number')}`)
69
+
70
+ // Clear all
71
+ await cache.clear()
72
+ console.log(` After clear, size: ${cache.getStats().size}`)
73
+ }
74
+
75
+ // ============================================================================
76
+ // GenerationCache
77
+ // ============================================================================
78
+
79
+ async function generationCacheExample(): Promise<void> {
80
+ console.log('\n=== GenerationCache - AI Response Caching ===\n')
81
+
82
+ const cache = new GenerationCache({
83
+ defaultTTL: 3600000, // 1 hour
84
+ maxSize: 1000,
85
+ })
86
+
87
+ // Cache key is based on prompt and model
88
+ const cacheKey1 = { prompt: 'What is TypeScript?', model: 'sonnet' }
89
+ const cacheKey2 = { prompt: 'What is TypeScript?', model: 'gpt-4o' }
90
+
91
+ // Check cache before generating
92
+ let result = await cache.get(cacheKey1)
93
+
94
+ if (!result) {
95
+ console.log('Cache miss - generating response...')
96
+ result = await write`What is TypeScript? Answer in one sentence.`
97
+
98
+ // Store in cache
99
+ await cache.set(cacheKey1, result)
100
+ console.log(`Cached response: "${result.substring(0, 50)}..."`)
101
+ } else {
102
+ console.log(`Cache hit: "${result.substring(0, 50)}..."`)
103
+ }
104
+
105
+ // Same prompt again - should hit cache
106
+ console.log('\nSecond request with same prompt...')
107
+ const cached = await cache.get(cacheKey1)
108
+ console.log(cached ? 'Cache HIT' : 'Cache MISS')
109
+
110
+ // Different model - different cache entry
111
+ console.log('\nSame prompt, different model...')
112
+ const differentModel = await cache.get(cacheKey2)
113
+ console.log(differentModel ? 'Cache HIT' : 'Cache MISS (different model)')
114
+
115
+ // Get usage metrics
116
+ console.log('\nGeneration Cache Metrics:')
117
+ const stats = cache.getStats()
118
+ console.log(` Entries: ${stats.size}`)
119
+ console.log(` Hits: ${stats.hits}`)
120
+ console.log(` Misses: ${stats.misses}`)
121
+ }
122
+
123
+ // ============================================================================
124
+ // EmbeddingCache with Batch Support
125
+ // ============================================================================
126
+
127
+ async function embeddingCacheExample(): Promise<void> {
128
+ console.log('\n=== EmbeddingCache - Embedding Storage ===\n')
129
+
130
+ const cache = new EmbeddingCache({
131
+ defaultTTL: 86400000, // 24 hours - embeddings change less frequently
132
+ maxSize: 10000, // Store up to 10k embeddings
133
+ })
134
+
135
+ // Simulate embedding generation
136
+ const generateEmbedding = (text: string): number[] => {
137
+ // Simplified embedding simulation
138
+ const hash = text.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
139
+ return Array(128)
140
+ .fill(0)
141
+ .map((_, i) => Math.sin(hash + i) / 2)
142
+ }
143
+
144
+ // Batch embedding with cache
145
+ const texts = [
146
+ 'The quick brown fox',
147
+ 'Jumps over the lazy dog',
148
+ 'Hello world',
149
+ 'The quick brown fox', // Duplicate
150
+ ]
151
+
152
+ console.log('Batch embedding with cache...\n')
153
+
154
+ // First, check which are already cached
155
+ const cacheResults = await cache.getMany(texts, { model: 'text-embedding-3-small' })
156
+ console.log(` Hits: ${cacheResults.hits.length}`)
157
+ console.log(` Misses: ${cacheResults.misses.length}`)
158
+
159
+ // Generate embeddings for misses
160
+ const newEmbeddings: Record<string, number[]> = {}
161
+ for (const text of cacheResults.misses) {
162
+ console.log(` Generating embedding for: "${text.substring(0, 30)}..."`)
163
+ newEmbeddings[text] = generateEmbedding(text)
164
+ }
165
+
166
+ // Store new embeddings
167
+ await cache.setMany(newEmbeddings, { model: 'text-embedding-3-small' })
168
+ console.log(`\n Cached ${Object.keys(newEmbeddings).length} new embeddings`)
169
+
170
+ // Second batch request - should hit more
171
+ console.log('\nSecond batch request...')
172
+ const secondResults = await cache.getMany(texts, { model: 'text-embedding-3-small' })
173
+ console.log(` Hits: ${secondResults.hits.length}`)
174
+ console.log(` Misses: ${secondResults.misses.length}`)
175
+
176
+ // Calculate savings
177
+ const savingsPercent = (secondResults.hits.length / texts.length) * 100
178
+ console.log(
179
+ `\n Cache efficiency: ${savingsPercent.toFixed(0)}% (${secondResults.hits.length}/${
180
+ texts.length
181
+ } from cache)`
182
+ )
183
+ }
184
+
185
+ // ============================================================================
186
+ // withCache Function Wrapper
187
+ // ============================================================================
188
+
189
+ async function withCacheExample(): Promise<void> {
190
+ console.log('\n=== withCache - Automatic Function Caching ===\n')
191
+
192
+ const cache = new MemoryCache({ maxSize: 100 })
193
+
194
+ // Create a cached version of any function
195
+ const generateSummary = async (text: string): Promise<string> => {
196
+ console.log(' [Generating summary...]')
197
+ // Simulate AI call
198
+ return `Summary of: ${text.substring(0, 30)}...`
199
+ }
200
+
201
+ // Wrap with caching
202
+ const cachedSummary = withCache(cache, generateSummary, {
203
+ keyFn: (text: string) => `summary:${hashKey(text)}`,
204
+ ttl: 60000,
205
+ })
206
+
207
+ // First call - generates
208
+ console.log('First call:')
209
+ const result1 = await cachedSummary('This is a long article about AI and machine learning...')
210
+ console.log(` Result: ${result1}`)
211
+
212
+ // Second call with same input - from cache
213
+ console.log('\nSecond call (same input):')
214
+ const result2 = await cachedSummary('This is a long article about AI and machine learning...')
215
+ console.log(` Result: ${result2}`)
216
+
217
+ // Different input - generates
218
+ console.log('\nThird call (different input):')
219
+ const result3 = await cachedSummary('A completely different article about web development...')
220
+ console.log(` Result: ${result3}`)
221
+
222
+ console.log('\nCache stats:', cache.getStats())
223
+ }
224
+
225
+ // ============================================================================
226
+ // Cache Key Strategies
227
+ // ============================================================================
228
+
229
+ async function cacheKeyStrategiesExample(): Promise<void> {
230
+ console.log('\n=== Cache Key Strategies ===\n')
231
+
232
+ // Strategy 1: Simple string hash
233
+ const prompt1 = 'What is TypeScript?'
234
+ const key1 = hashKey(prompt1)
235
+ console.log(`Simple hash:`)
236
+ console.log(` Input: "${prompt1}"`)
237
+ console.log(` Key: ${key1}`)
238
+
239
+ // Strategy 2: Composite key with model
240
+ const key2 = createCacheKey({
241
+ prompt: prompt1,
242
+ model: 'sonnet',
243
+ temperature: 0.7,
244
+ })
245
+ console.log(`\nComposite key:`)
246
+ console.log(` Input: { prompt, model, temperature }`)
247
+ console.log(` Key: ${key2}`)
248
+
249
+ // Strategy 3: Normalized prompt (ignore whitespace differences)
250
+ const normalizePrompt = (p: string): string => p.trim().replace(/\s+/g, ' ').toLowerCase()
251
+ const prompt2 = ' What is TypeScript? '
252
+ console.log(`\nNormalized prompt:`)
253
+ console.log(` Original: "${prompt2}"`)
254
+ console.log(` Normalized: "${normalizePrompt(prompt2)}"`)
255
+ console.log(
256
+ ` Same key as prompt1: ${
257
+ hashKey(normalizePrompt(prompt2)) === hashKey(normalizePrompt(prompt1))
258
+ }`
259
+ )
260
+
261
+ // Strategy 4: Semantic caching key (for similar prompts)
262
+ // This would use embeddings to find similar cached entries
263
+ console.log(`\nSemantic caching (conceptual):`)
264
+ console.log(` "What is TS?" would match "What is TypeScript?"`)
265
+ console.log(` Requires embedding-based similarity lookup`)
266
+ }
267
+
268
+ // ============================================================================
269
+ // Cache Invalidation Patterns
270
+ // ============================================================================
271
+
272
+ async function cacheInvalidationExample(): Promise<void> {
273
+ console.log('\n=== Cache Invalidation Patterns ===\n')
274
+
275
+ const cache = new MemoryCache({ maxSize: 100 })
276
+
277
+ // Pattern 1: TTL-based expiration
278
+ console.log('1. TTL-based expiration:')
279
+ await cache.set('short-lived', 'data', { ttl: 1000 }) // 1 second
280
+ console.log(` Set with 1s TTL: ${await cache.get('short-lived')}`)
281
+
282
+ await new Promise((r) => setTimeout(r, 1100))
283
+ console.log(` After 1.1s: ${await cache.get('short-lived')} (expired)`)
284
+
285
+ // Pattern 2: Manual invalidation
286
+ console.log('\n2. Manual invalidation:')
287
+ await cache.set('user:123', { name: 'Alice' })
288
+ console.log(` Before invalidation: ${JSON.stringify(await cache.get('user:123'))}`)
289
+
290
+ await cache.delete('user:123')
291
+ console.log(` After invalidation: ${await cache.get('user:123')}`)
292
+
293
+ // Pattern 3: Pattern-based invalidation
294
+ console.log('\n3. Pattern-based invalidation (conceptual):')
295
+ console.log(` cache.deletePattern('user:*') // Delete all user entries`)
296
+ console.log(` Useful when a user's data changes globally`)
297
+
298
+ // Pattern 4: Version-based keys
299
+ console.log('\n4. Version-based keys:')
300
+ const version = 'v2'
301
+ const versionedKey = `${version}:prompt:${hashKey('What is TypeScript?')}`
302
+ console.log(` Key includes version: ${versionedKey}`)
303
+ console.log(` Incrementing version invalidates all old entries`)
304
+ }
305
+
306
+ // ============================================================================
307
+ // Cost Savings Calculation
308
+ // ============================================================================
309
+
310
+ async function costSavingsExample(): Promise<void> {
311
+ console.log('\n=== Cost Savings from Caching ===\n')
312
+
313
+ // Simulate request patterns
314
+ const totalRequests = 1000
315
+ const uniquePrompts = 100
316
+ const hitRate = 0.7 // 70% of requests are repeats
317
+
318
+ // Pricing assumptions (per 1M tokens)
319
+ const inputCost = 3.0 // $3 per 1M input tokens
320
+ const outputCost = 15.0 // $15 per 1M output tokens
321
+ const avgInputTokens = 100
322
+ const avgOutputTokens = 200
323
+
324
+ // Calculate without caching
325
+ const costPerRequest = (avgInputTokens * inputCost + avgOutputTokens * outputCost) / 1000000
326
+ const totalCostNoCache = totalRequests * costPerRequest
327
+
328
+ // Calculate with caching (only pay for unique prompts)
329
+ const cachedRequests = totalRequests * hitRate
330
+ const uncachedRequests = totalRequests - cachedRequests
331
+ const totalCostWithCache = uncachedRequests * costPerRequest
332
+
333
+ const savings = totalCostNoCache - totalCostWithCache
334
+ const savingsPercent = (savings / totalCostNoCache) * 100
335
+
336
+ console.log('Scenario:')
337
+ console.log(` Total requests: ${totalRequests}`)
338
+ console.log(` Unique prompts: ${uniquePrompts}`)
339
+ console.log(` Cache hit rate: ${(hitRate * 100).toFixed(0)}%`)
340
+ console.log(`\nCost Analysis:`)
341
+ console.log(` Without caching: $${totalCostNoCache.toFixed(4)}`)
342
+ console.log(` With caching: $${totalCostWithCache.toFixed(4)}`)
343
+ console.log(` Savings: $${savings.toFixed(4)} (${savingsPercent.toFixed(0)}%)`)
344
+
345
+ console.log(`\nRecommendation:`)
346
+ console.log(` For ${totalRequests} requests/day at ${(hitRate * 100).toFixed(0)}% hit rate:`)
347
+ console.log(` Monthly savings: ~$${(savings * 30).toFixed(2)}`)
348
+ }
349
+
350
+ // ============================================================================
351
+ // Production Recommendations
352
+ // ============================================================================
353
+
354
+ function showProductionRecommendations(): void {
355
+ console.log('\n=== Production Caching Recommendations ===\n')
356
+
357
+ console.log(`
358
+ 1. CACHE STORAGE SELECTION
359
+ - Development: MemoryCache (simple, no setup)
360
+ - Production: Redis/Memcached (persistent, distributed)
361
+ - Edge: Cloudflare KV, Durable Objects
362
+
363
+ 2. TTL STRATEGIES
364
+ - Embeddings: 24-48 hours (stable, expensive)
365
+ - Generations: 1-4 hours (may need freshness)
366
+ - Lists/Classifications: 15-60 minutes (volatile)
367
+ - User-specific: 5-15 minutes (personalized)
368
+
369
+ 3. KEY DESIGN
370
+ - Include: prompt hash, model, temperature
371
+ - Normalize: whitespace, case (for similar queries)
372
+ - Version: include cache version for easy invalidation
373
+
374
+ 4. SIZE MANAGEMENT
375
+ - Set maxSize based on memory budget
376
+ - Monitor hit rates to optimize size
377
+ - Use LRU eviction for unpredictable access patterns
378
+
379
+ 5. INVALIDATION
380
+ - TTL for automatic expiration
381
+ - Manual invalidation for data changes
382
+ - Version bumps for schema changes
383
+
384
+ 6. MONITORING
385
+ - Track hit/miss rates
386
+ - Monitor cache size over time
387
+ - Alert on low hit rates
388
+ - Log cache key patterns for optimization
389
+ `)
390
+ }
391
+
392
+ // ============================================================================
393
+ // Main
394
+ // ============================================================================
395
+
396
+ async function main() {
397
+ console.log('\n=== Caching Strategies Example ===')
398
+
399
+ configure({
400
+ model: 'sonnet',
401
+ provider: 'anthropic',
402
+ })
403
+
404
+ await memoryCacheExample()
405
+ await generationCacheExample()
406
+ await embeddingCacheExample()
407
+ await withCacheExample()
408
+ await cacheKeyStrategiesExample()
409
+ await cacheInvalidationExample()
410
+ await costSavingsExample()
411
+ showProductionRecommendations()
412
+ }
413
+
414
+ main()
415
+ .then(() => {
416
+ console.log('\n=== Example Complete ===\n')
417
+ process.exit(0)
418
+ })
419
+ .catch((error) => {
420
+ console.error('\nError:', error.message)
421
+ process.exit(1)
422
+ })
@@ -0,0 +1,145 @@
1
+ # ai-functions Examples
2
+
3
+ This directory contains runnable examples demonstrating various use cases for the `ai-functions` library.
4
+
5
+ ## Running Examples
6
+
7
+ Make sure you have an API key configured:
8
+
9
+ ```bash
10
+ export ANTHROPIC_API_KEY=sk-ant-...
11
+ # or
12
+ export OPENAI_API_KEY=sk-...
13
+ ```
14
+
15
+ Then run any example with:
16
+
17
+ ```bash
18
+ npx tsx examples/<example-name>.ts
19
+ ```
20
+
21
+ ## Examples Overview
22
+
23
+ ### 1. RAG Chatbot (`01-rag-chatbot.ts`)
24
+ Build a Retrieval-Augmented Generation chatbot that:
25
+ - Generates embeddings for documents
26
+ - Performs semantic search
27
+ - Generates context-aware responses
28
+
29
+ ### 2. Multi-Agent Research Workflow (`02-multi-agent-research.ts`)
30
+ Coordinate multiple specialized agents:
31
+ - Planner agent creates research plans
32
+ - Fact finder agent gathers information
33
+ - Analyst agent critiques findings
34
+ - Synthesizer agent creates final reports
35
+
36
+ ### 3. Email Classification & Routing (`03-email-classification.ts`)
37
+ Intelligent email processing:
38
+ - Classify emails by category, priority, sentiment
39
+ - Extract key information and action items
40
+ - Route to appropriate handlers
41
+ - Generate auto-responses
42
+
43
+ ### 4. Content Moderation Pipeline (`04-content-moderation.ts`)
44
+ Multi-stage moderation system:
45
+ - Quick safety checks
46
+ - Detailed category analysis
47
+ - Severity assessment
48
+ - Routing decisions
49
+
50
+ ### 5. Document Data Extraction (`05-document-extraction.ts`)
51
+ Extract structured data from:
52
+ - Invoices (line items, totals, dates)
53
+ - Resumes (experience, skills, education)
54
+ - Contracts (parties, terms, financials)
55
+ - General entity extraction
56
+
57
+ ### 6. Streaming Chat UI (`06-streaming-chat-nextjs.ts`)
58
+ Build streaming interfaces:
59
+ - Real-time text streaming
60
+ - Partial object streaming
61
+ - React/Next.js integration patterns
62
+ - Conversation state management
63
+
64
+ ### 7. Cloudflare Worker Deployment (`07-cloudflare-worker.ts`)
65
+ Edge function patterns:
66
+ - Worker request handling
67
+ - Rate limiting
68
+ - Response caching
69
+ - Streaming responses
70
+
71
+ ### 8. Batch Processing (1000+ items) (`08-batch-processing.ts`)
72
+ Process large volumes efficiently:
73
+ - Concurrent processing with limits
74
+ - Provider batch API (50% cost savings)
75
+ - Progress tracking
76
+ - Error recovery
77
+
78
+ ### 9. Budget-Constrained Generation (`09-budget-constrained.ts`)
79
+ Control costs and usage:
80
+ - Budget limits and alerts
81
+ - Cost tracking by model
82
+ - Per-user/tenant budgets
83
+ - Optimization strategies
84
+
85
+ ### 10. Tool Orchestration (`10-tool-orchestration.ts`)
86
+ Build agentic applications:
87
+ - Define tools with Zod schemas
88
+ - AgenticLoop for multi-turn conversations
89
+ - Tool composition patterns
90
+ - Streaming events
91
+
92
+ ### 11. Retry and Resilience Patterns (`11-retry-resilience.ts`)
93
+ Build fault-tolerant applications:
94
+ - Retry with exponential backoff
95
+ - Circuit breaker pattern
96
+ - Fallback chains
97
+ - Error classification
98
+
99
+ ### 12. Caching Strategies (`12-caching-strategies.ts`)
100
+ Optimize costs with intelligent caching:
101
+ - MemoryCache for general use
102
+ - GenerationCache for AI responses
103
+ - EmbeddingCache for vectors
104
+ - Function wrappers
105
+
106
+ ### Quickstart (`00-quickstart.ts`)
107
+ Get started quickly with:
108
+ - Basic primitives overview
109
+ - Simple examples of each feature
110
+ - Configuration patterns
111
+
112
+ ### Batch Blog Posts (`batch-blog-posts.ts`)
113
+ Original example showing implicit batching:
114
+ - Global configuration
115
+ - Automatic batch detection
116
+ - list.map() patterns
117
+
118
+ ## Quick Reference
119
+
120
+ | Example | Key Features | Use Case |
121
+ |---------|--------------|----------|
122
+ | RAG Chatbot | Embeddings, search, context | Knowledge bases, support bots |
123
+ | Multi-Agent | Agent coordination, synthesis | Research, analysis |
124
+ | Email Classification | Classification, extraction, routing | Email automation |
125
+ | Content Moderation | Policy checks, severity scoring | UGC platforms |
126
+ | Document Extraction | Schema inference, validation | Data entry automation |
127
+ | Streaming Chat | Real-time updates, partial objects | Chat applications |
128
+ | Cloudflare Worker | Edge runtime, caching | API endpoints |
129
+ | Batch Processing | Concurrency, progress tracking | Bulk operations |
130
+ | Budget Constrained | Cost control, alerts | Production systems |
131
+ | Tool Orchestration | Agentic loops, tool calling | AI assistants |
132
+ | Retry Resilience | Retries, circuit breakers, fallbacks | Production systems |
133
+ | Caching Strategies | Cache generation, embeddings | Cost optimization |
134
+
135
+ ## Prerequisites
136
+
137
+ - Node.js 18+
138
+ - TypeScript 5+
139
+ - API key for Anthropic or OpenAI
140
+
141
+ ## Getting Help
142
+
143
+ - See the main [README.md](../README.md) for API documentation
144
+ - Check [test/](../test/) for more usage patterns
145
+ - File issues at the repository
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-functions",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "description": "Core AI primitives for building intelligent applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,7 +26,7 @@
26
26
  "scripts": {
27
27
  "build": "tsc -p tsconfig.json",
28
28
  "dev": "tsc -p tsconfig.json --watch",
29
- "test": "vitest",
29
+ "test": "vitest run",
30
30
  "test:unit": "vitest run --exclude 'test/evals/**' --exclude 'test/e2e-*'",
31
31
  "test:evals": "vitest run test/evals/",
32
32
  "test:evals:primitives": "vitest run test/evals/primitives.eval.test.ts",
@@ -44,11 +44,15 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@ai-sdk/amazon-bedrock": "^3.0.0",
47
- "ai": "^5.0.0",
48
- "ai-providers": "^2.1.1",
49
- "language-models": "2.1.1",
47
+ "@ai-sdk/provider": "^3.0.7",
48
+ "@org.ai/types": "2.3.0",
49
+ "ai": "^6.0.0",
50
+ "ai-providers": "^2.3.0",
51
+ "digital-objects": "^1.1.0",
52
+ "language-models": "2.3.0",
50
53
  "yaml": "^2.8.0",
51
- "zod": "^3.23.0"
54
+ "zod": "^3.23.0",
55
+ "zod-to-json-schema": "^3.25.1"
52
56
  },
53
57
  "optionalDependencies": {
54
58
  "oauth.do": "^0.2.1"