ai-functions 2.1.3 → 2.4.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 (284) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +90 -1
  3. package/README.md +38 -0
  4. package/dist/ai-promise.d.ts +3 -3
  5. package/dist/ai-promise.d.ts.map +1 -1
  6. package/dist/ai-promise.js +135 -64
  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 +51 -858
  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.map +1 -1
  56. package/dist/budget.js +27 -14
  57. package/dist/budget.js.map +1 -1
  58. package/dist/cache.d.ts +23 -0
  59. package/dist/cache.d.ts.map +1 -1
  60. package/dist/cache.js +36 -15
  61. package/dist/cache.js.map +1 -1
  62. package/dist/context.d.ts +26 -8
  63. package/dist/context.d.ts.map +1 -1
  64. package/dist/context.js +64 -62
  65. package/dist/context.js.map +1 -1
  66. package/dist/digital-objects-registry.d.ts +229 -0
  67. package/dist/digital-objects-registry.d.ts.map +1 -0
  68. package/dist/digital-objects-registry.js +617 -0
  69. package/dist/digital-objects-registry.js.map +1 -0
  70. package/dist/embeddings.d.ts +2 -2
  71. package/dist/embeddings.d.ts.map +1 -1
  72. package/dist/errors.d.ts +22 -0
  73. package/dist/errors.d.ts.map +1 -0
  74. package/dist/errors.js +35 -0
  75. package/dist/errors.js.map +1 -0
  76. package/dist/eval/runner.d.ts +8 -0
  77. package/dist/eval/runner.d.ts.map +1 -1
  78. package/dist/eval/runner.js +41 -35
  79. package/dist/eval/runner.js.map +1 -1
  80. package/dist/eval-log/in-memory.d.ts +34 -0
  81. package/dist/eval-log/in-memory.d.ts.map +1 -0
  82. package/dist/eval-log/in-memory.js +84 -0
  83. package/dist/eval-log/in-memory.js.map +1 -0
  84. package/dist/eval-log/index.d.ts +29 -0
  85. package/dist/eval-log/index.d.ts.map +1 -0
  86. package/dist/eval-log/index.js +39 -0
  87. package/dist/eval-log/index.js.map +1 -0
  88. package/dist/eval-log/types.d.ts +101 -0
  89. package/dist/eval-log/types.d.ts.map +1 -0
  90. package/dist/eval-log/types.js +16 -0
  91. package/dist/eval-log/types.js.map +1 -0
  92. package/dist/function-registry.d.ts +176 -0
  93. package/dist/function-registry.d.ts.map +1 -0
  94. package/dist/function-registry.js +685 -0
  95. package/dist/function-registry.js.map +1 -0
  96. package/dist/generate.d.ts +9 -3
  97. package/dist/generate.d.ts.map +1 -1
  98. package/dist/generate.js +18 -18
  99. package/dist/generate.js.map +1 -1
  100. package/dist/index.d.ts +18 -11
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +35 -18
  103. package/dist/index.js.map +1 -1
  104. package/dist/logger.d.ts +118 -0
  105. package/dist/logger.d.ts.map +1 -0
  106. package/dist/logger.js +187 -0
  107. package/dist/logger.js.map +1 -0
  108. package/dist/middleware/budget.d.ts +84 -0
  109. package/dist/middleware/budget.d.ts.map +1 -0
  110. package/dist/middleware/budget.js +110 -0
  111. package/dist/middleware/budget.js.map +1 -0
  112. package/dist/middleware/cache.d.ts +103 -0
  113. package/dist/middleware/cache.d.ts.map +1 -0
  114. package/dist/middleware/cache.js +228 -0
  115. package/dist/middleware/cache.js.map +1 -0
  116. package/dist/middleware/embed-cache.d.ts +99 -0
  117. package/dist/middleware/embed-cache.d.ts.map +1 -0
  118. package/dist/middleware/embed-cache.js +128 -0
  119. package/dist/middleware/embed-cache.js.map +1 -0
  120. package/dist/middleware/index.d.ts +11 -0
  121. package/dist/middleware/index.d.ts.map +1 -0
  122. package/dist/middleware/index.js +11 -0
  123. package/dist/middleware/index.js.map +1 -0
  124. package/dist/middleware/trace.d.ts +103 -0
  125. package/dist/middleware/trace.d.ts.map +1 -0
  126. package/dist/middleware/trace.js +176 -0
  127. package/dist/middleware/trace.js.map +1 -0
  128. package/dist/primitives.d.ts +120 -1
  129. package/dist/primitives.d.ts.map +1 -1
  130. package/dist/primitives.js +398 -26
  131. package/dist/primitives.js.map +1 -1
  132. package/dist/retry.d.ts +66 -1
  133. package/dist/retry.d.ts.map +1 -1
  134. package/dist/retry.js +115 -8
  135. package/dist/retry.js.map +1 -1
  136. package/dist/sandbox.d.ts +36 -0
  137. package/dist/sandbox.d.ts.map +1 -0
  138. package/dist/sandbox.js +44 -0
  139. package/dist/sandbox.js.map +1 -0
  140. package/dist/schema.js +2 -2
  141. package/dist/schema.js.map +1 -1
  142. package/dist/telemetry.d.ts +128 -0
  143. package/dist/telemetry.d.ts.map +1 -0
  144. package/dist/telemetry.js +285 -0
  145. package/dist/telemetry.js.map +1 -0
  146. package/dist/template.d.ts.map +1 -1
  147. package/dist/template.js +6 -1
  148. package/dist/template.js.map +1 -1
  149. package/dist/tool-orchestration.d.ts +66 -4
  150. package/dist/tool-orchestration.d.ts.map +1 -1
  151. package/dist/tool-orchestration.js +123 -23
  152. package/dist/tool-orchestration.js.map +1 -1
  153. package/dist/type-guards.d.ts +28 -0
  154. package/dist/type-guards.d.ts.map +1 -0
  155. package/dist/type-guards.js +29 -0
  156. package/dist/type-guards.js.map +1 -0
  157. package/dist/types.d.ts +155 -19
  158. package/dist/types.d.ts.map +1 -1
  159. package/dist/types.js +36 -1
  160. package/dist/types.js.map +1 -1
  161. package/dist/wrap-for-v3.d.ts +80 -0
  162. package/dist/wrap-for-v3.d.ts.map +1 -0
  163. package/dist/wrap-for-v3.js +89 -0
  164. package/dist/wrap-for-v3.js.map +1 -0
  165. package/examples/00-quickstart.ts +232 -0
  166. package/examples/01-rag-chatbot.ts +212 -0
  167. package/examples/02-multi-agent-research.ts +290 -0
  168. package/examples/03-email-classification.ts +379 -0
  169. package/examples/04-content-moderation.ts +400 -0
  170. package/examples/05-document-extraction.ts +455 -0
  171. package/examples/06-streaming-chat-nextjs.ts +437 -0
  172. package/examples/07-cloudflare-worker.ts +483 -0
  173. package/examples/08-batch-processing.ts +491 -0
  174. package/examples/09-budget-constrained.ts +527 -0
  175. package/examples/10-tool-orchestration.ts +565 -0
  176. package/examples/11-retry-resilience.ts +403 -0
  177. package/examples/12-caching-strategies.ts +422 -0
  178. package/examples/README.md +145 -0
  179. package/package.json +29 -25
  180. package/src/ai-promise.ts +226 -140
  181. package/src/ai-schemas.ts +122 -0
  182. package/src/ai.ts +71 -1176
  183. package/src/batch/anthropic.ts +96 -161
  184. package/src/batch/bedrock.ts +203 -454
  185. package/src/batch/cloudflare.ts +99 -282
  186. package/src/batch/google.ts +91 -297
  187. package/src/batch/index.ts +4 -1
  188. package/src/batch/memory.ts +15 -10
  189. package/src/batch/openai.ts +65 -193
  190. package/src/batch/provider.ts +336 -0
  191. package/src/batch-map.ts +29 -24
  192. package/src/batch-queue.ts +200 -11
  193. package/src/budget.ts +31 -18
  194. package/src/cache.ts +45 -17
  195. package/src/context.ts +106 -77
  196. package/src/digital-objects-registry.ts +750 -0
  197. package/src/errors.ts +37 -0
  198. package/src/eval/runner.ts +60 -36
  199. package/src/eval-log/in-memory.ts +90 -0
  200. package/src/eval-log/index.ts +46 -0
  201. package/src/eval-log/types.ts +110 -0
  202. package/src/function-registry.ts +874 -0
  203. package/src/generate.ts +33 -28
  204. package/src/index.ts +122 -21
  205. package/src/logger.ts +232 -0
  206. package/src/middleware/budget.ts +171 -0
  207. package/src/middleware/cache.ts +299 -0
  208. package/src/middleware/embed-cache.ts +195 -0
  209. package/src/middleware/index.ts +23 -0
  210. package/src/middleware/trace.ts +248 -0
  211. package/src/primitives.ts +589 -62
  212. package/src/retry.ts +144 -18
  213. package/src/sandbox.ts +52 -0
  214. package/src/schema.ts +8 -8
  215. package/src/telemetry.ts +403 -0
  216. package/src/template.ts +8 -4
  217. package/src/tool-orchestration.ts +213 -48
  218. package/src/type-guards.ts +31 -0
  219. package/src/types.ts +186 -27
  220. package/src/wrap-for-v3.ts +105 -0
  221. package/test/ai-promise.test.ts +1080 -0
  222. package/test/ai-proxy.test.ts +1 -1
  223. package/test/batch-autosubmit-errors.test.ts +49 -37
  224. package/test/batch-blog-posts.test.ts +87 -129
  225. package/test/core-functions.test.ts +183 -579
  226. package/test/decide.test.ts +154 -322
  227. package/test/define.test.ts +211 -8
  228. package/test/digital-objects-registry.test.ts +760 -0
  229. package/test/embedding-cache-middleware.test.ts +140 -0
  230. package/test/fill-template.test.ts +89 -0
  231. package/test/generate-core.test.ts +140 -229
  232. package/test/implicit-batch.test.ts +22 -65
  233. package/test/retry-policy-integration.test.ts +117 -0
  234. package/test/sandbox-execution.test.ts +155 -0
  235. package/test/schema.test.ts +55 -19
  236. package/test/template.test.ts +1164 -0
  237. package/test/tool-orchestration.test.ts +270 -0
  238. package/test/wrap-for-v3.test.ts +612 -0
  239. package/vitest.config.js +6 -0
  240. package/vitest.config.ts +20 -0
  241. package/LICENSE +0 -21
  242. package/dist/rpc/auth.d.ts +0 -69
  243. package/dist/rpc/auth.d.ts.map +0 -1
  244. package/dist/rpc/auth.js +0 -136
  245. package/dist/rpc/auth.js.map +0 -1
  246. package/dist/rpc/client.d.ts +0 -62
  247. package/dist/rpc/client.d.ts.map +0 -1
  248. package/dist/rpc/client.js +0 -103
  249. package/dist/rpc/client.js.map +0 -1
  250. package/dist/rpc/deferred.d.ts +0 -60
  251. package/dist/rpc/deferred.d.ts.map +0 -1
  252. package/dist/rpc/deferred.js +0 -96
  253. package/dist/rpc/deferred.js.map +0 -1
  254. package/dist/rpc/index.d.ts +0 -22
  255. package/dist/rpc/index.d.ts.map +0 -1
  256. package/dist/rpc/index.js +0 -38
  257. package/dist/rpc/index.js.map +0 -1
  258. package/dist/rpc/local.d.ts +0 -42
  259. package/dist/rpc/local.d.ts.map +0 -1
  260. package/dist/rpc/local.js +0 -50
  261. package/dist/rpc/local.js.map +0 -1
  262. package/dist/rpc/server.d.ts +0 -165
  263. package/dist/rpc/server.d.ts.map +0 -1
  264. package/dist/rpc/server.js +0 -405
  265. package/dist/rpc/server.js.map +0 -1
  266. package/dist/rpc/session.d.ts +0 -32
  267. package/dist/rpc/session.d.ts.map +0 -1
  268. package/dist/rpc/session.js +0 -43
  269. package/dist/rpc/session.js.map +0 -1
  270. package/dist/rpc/transport.d.ts +0 -306
  271. package/dist/rpc/transport.d.ts.map +0 -1
  272. package/dist/rpc/transport.js +0 -731
  273. package/dist/rpc/transport.js.map +0 -1
  274. package/src/batch/anthropic.js +0 -256
  275. package/src/batch/bedrock.js +0 -584
  276. package/src/batch/cloudflare.js +0 -287
  277. package/src/batch/google.js +0 -359
  278. package/src/batch/index.js +0 -30
  279. package/src/batch/memory.js +0 -187
  280. package/src/batch/openai.js +0 -402
  281. package/src/eval/index.js +0 -7
  282. package/src/eval/models.js +0 -119
  283. package/src/eval/runner.js +0 -147
  284. package/test/schema.test.js +0 -96
@@ -0,0 +1,212 @@
1
+ /**
2
+ * RAG Chatbot Example
3
+ *
4
+ * This example demonstrates building a Retrieval-Augmented Generation (RAG) chatbot
5
+ * using ai-functions. It shows how to:
6
+ * - Generate embeddings for documents
7
+ * - Perform semantic search
8
+ * - Generate context-aware responses
9
+ *
10
+ * @example
11
+ * ```bash
12
+ * ANTHROPIC_API_KEY=sk-... npx tsx examples/01-rag-chatbot.ts
13
+ * ```
14
+ */
15
+
16
+ import {
17
+ write,
18
+ list,
19
+ configure,
20
+ EmbeddingCache,
21
+ MemoryCache,
22
+ GenerationCache,
23
+ withRetry,
24
+ } from '../src/index.js'
25
+
26
+ // ============================================================================
27
+ // Document Store (In-memory for this example)
28
+ // ============================================================================
29
+
30
+ interface Document {
31
+ id: string
32
+ content: string
33
+ embedding?: number[]
34
+ }
35
+
36
+ const documents: Document[] = [
37
+ {
38
+ id: 'doc-1',
39
+ content:
40
+ 'ai-functions is a TypeScript library that simplifies AI integration. It provides template literals for natural AI calls like `const poem = await write`a haiku about TypeScript``.',
41
+ },
42
+ {
43
+ id: 'doc-2',
44
+ content:
45
+ 'The library supports batch processing with 50% cost savings through provider batch APIs. Use createBatch() to process large workloads efficiently.',
46
+ },
47
+ {
48
+ id: 'doc-3',
49
+ content:
50
+ 'Built-in retry logic with exponential backoff handles rate limits automatically. Use withRetry() or RetryPolicy for custom retry behavior.',
51
+ },
52
+ {
53
+ id: 'doc-4',
54
+ content:
55
+ 'Budget tracking monitors token usage and costs. BudgetTracker supports alerts at configurable thresholds and enforces spending limits.',
56
+ },
57
+ {
58
+ id: 'doc-5',
59
+ content:
60
+ 'The list primitive generates arrays with automatic batching. Use list`5 ideas`.map() to process each item in parallel.',
61
+ },
62
+ ]
63
+
64
+ // ============================================================================
65
+ // Simple Embedding Simulation (replace with real embeddings in production)
66
+ // ============================================================================
67
+
68
+ function simulateEmbedding(text: string): number[] {
69
+ // Simple word-based embedding simulation
70
+ // In production, use a real embedding model
71
+ const words = text.toLowerCase().split(/\s+/)
72
+ const embedding = new Array(128).fill(0)
73
+
74
+ for (const word of words) {
75
+ const hash = word.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
76
+ embedding[hash % 128] += 1
77
+ }
78
+
79
+ // Normalize
80
+ const magnitude = Math.sqrt(embedding.reduce((acc, val) => acc + val * val, 0))
81
+ return embedding.map((val) => (magnitude > 0 ? val / magnitude : 0))
82
+ }
83
+
84
+ function cosineSimilarity(a: number[], b: number[]): number {
85
+ let dotProduct = 0
86
+ for (let i = 0; i < a.length; i++) {
87
+ dotProduct += a[i] * b[i]
88
+ }
89
+ return dotProduct
90
+ }
91
+
92
+ // ============================================================================
93
+ // RAG Chatbot Implementation
94
+ // ============================================================================
95
+
96
+ class RAGChatbot {
97
+ private documents: Document[]
98
+ private responseCache: GenerationCache
99
+
100
+ constructor(documents: Document[]) {
101
+ this.documents = documents
102
+ this.responseCache = new GenerationCache({
103
+ defaultTTL: 3600000, // 1 hour cache
104
+ })
105
+
106
+ // Generate embeddings for all documents
107
+ for (const doc of this.documents) {
108
+ doc.embedding = simulateEmbedding(doc.content)
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Find the most relevant documents for a query
114
+ */
115
+ private findRelevantDocs(query: string, topK: number = 3): Document[] {
116
+ const queryEmbedding = simulateEmbedding(query)
117
+
118
+ const scored = this.documents.map((doc) => ({
119
+ doc,
120
+ score: cosineSimilarity(queryEmbedding, doc.embedding!),
121
+ }))
122
+
123
+ return scored
124
+ .sort((a, b) => b.score - a.score)
125
+ .slice(0, topK)
126
+ .map(({ doc }) => doc)
127
+ }
128
+
129
+ /**
130
+ * Generate a response using RAG
131
+ */
132
+ async chat(userMessage: string): Promise<string> {
133
+ console.log(`\nUser: ${userMessage}`)
134
+ console.log('---')
135
+
136
+ // Step 1: Retrieve relevant documents
137
+ const relevantDocs = this.findRelevantDocs(userMessage)
138
+ console.log(`Found ${relevantDocs.length} relevant documents`)
139
+
140
+ // Step 2: Build context from retrieved documents
141
+ const context = relevantDocs.map((doc, i) => `[Source ${i + 1}]: ${doc.content}`).join('\n\n')
142
+
143
+ // Step 3: Generate response with context
144
+ const response =
145
+ await write`You are a helpful assistant that answers questions about ai-functions library.
146
+
147
+ Context from documentation:
148
+ ${context}
149
+
150
+ User Question: ${userMessage}
151
+
152
+ Please provide a helpful, accurate response based on the context above. If the context doesn't contain enough information, say so.`
153
+
154
+ console.log(`Assistant: ${response}`)
155
+ return response
156
+ }
157
+
158
+ /**
159
+ * Generate follow-up questions
160
+ */
161
+ async suggestFollowUps(topic: string): Promise<string[]> {
162
+ const suggestions =
163
+ await list`3 follow-up questions someone might ask about ${topic} related to ai-functions library`
164
+ return suggestions
165
+ }
166
+ }
167
+
168
+ // ============================================================================
169
+ // Main Example
170
+ // ============================================================================
171
+
172
+ async function main() {
173
+ console.log('\n=== RAG Chatbot Example ===\n')
174
+
175
+ // Configure the AI provider
176
+ configure({
177
+ model: 'sonnet',
178
+ provider: 'anthropic',
179
+ })
180
+
181
+ // Initialize the chatbot with our documents
182
+ const chatbot = new RAGChatbot(documents)
183
+
184
+ // Example conversation
185
+ const questions = [
186
+ 'How do I generate a list of items?',
187
+ 'What are the cost savings for batch processing?',
188
+ 'How does retry handling work?',
189
+ ]
190
+
191
+ for (const question of questions) {
192
+ await chatbot.chat(question)
193
+ console.log('')
194
+ }
195
+
196
+ // Generate follow-up suggestions
197
+ console.log('\n--- Suggested follow-up questions ---')
198
+ const followUps = await chatbot.suggestFollowUps('batch processing')
199
+ for (const suggestion of followUps) {
200
+ console.log(`- ${suggestion}`)
201
+ }
202
+ }
203
+
204
+ main()
205
+ .then(() => {
206
+ console.log('\n=== Example Complete ===\n')
207
+ process.exit(0)
208
+ })
209
+ .catch((error) => {
210
+ console.error('\nError:', error.message)
211
+ process.exit(1)
212
+ })
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Multi-Agent Research Workflow Example
3
+ *
4
+ * This example demonstrates a multi-agent research workflow where different
5
+ * specialized agents collaborate to research a topic. It shows how to:
6
+ * - Define specialized agents with different roles
7
+ * - Coordinate agent interactions
8
+ * - Aggregate and synthesize results
9
+ * - Use tool orchestration for complex workflows
10
+ *
11
+ * @example
12
+ * ```bash
13
+ * ANTHROPIC_API_KEY=sk-... npx tsx examples/02-multi-agent-research.ts
14
+ * ```
15
+ */
16
+
17
+ import {
18
+ ai,
19
+ write,
20
+ list,
21
+ is,
22
+ configure,
23
+ AgenticLoop,
24
+ createTool,
25
+ createToolset,
26
+ type Tool,
27
+ } from '../src/index.js'
28
+ import { z } from 'zod'
29
+
30
+ // ============================================================================
31
+ // Agent Definitions
32
+ // ============================================================================
33
+
34
+ interface AgentResult {
35
+ agent: string
36
+ findings: string[]
37
+ confidence: number
38
+ }
39
+
40
+ /**
41
+ * Research Planner Agent - Creates a research plan
42
+ */
43
+ async function plannerAgent(topic: string): Promise<string[]> {
44
+ console.log('\n[Planner Agent] Creating research plan...')
45
+
46
+ const questions = await list`5 key research questions to thoroughly investigate: "${topic}"
47
+
48
+ Consider:
49
+ - Background and context
50
+ - Current state and trends
51
+ - Key players and stakeholders
52
+ - Challenges and opportunities
53
+ - Future implications`
54
+
55
+ console.log('[Planner Agent] Research questions:')
56
+ questions.forEach((q, i) => console.log(` ${i + 1}. ${q}`))
57
+
58
+ return questions
59
+ }
60
+
61
+ /**
62
+ * Fact Finder Agent - Gathers factual information
63
+ */
64
+ async function factFinderAgent(question: string): Promise<AgentResult> {
65
+ console.log(`\n[Fact Finder] Researching: ${question.substring(0, 50)}...`)
66
+
67
+ const { facts, sources, confidence } =
68
+ await ai`Research this question and provide factual information:
69
+ "${question}"
70
+
71
+ Provide your response with:
72
+ - facts: array of factual findings (3-5 key facts)
73
+ - sources: where this information typically comes from
74
+ - confidence: your confidence level 0-1 in these facts`
75
+
76
+ const result: AgentResult = {
77
+ agent: 'FactFinder',
78
+ findings: facts as string[],
79
+ confidence: (confidence as number) || 0.7,
80
+ }
81
+
82
+ console.log(
83
+ `[Fact Finder] Found ${result.findings.length} facts (confidence: ${result.confidence})`
84
+ )
85
+ return result
86
+ }
87
+
88
+ /**
89
+ * Critical Analyst Agent - Analyzes and critiques
90
+ */
91
+ async function analystAgent(findings: string[]): Promise<AgentResult> {
92
+ console.log('\n[Analyst Agent] Analyzing findings...')
93
+
94
+ const { analysis, gaps, confidence } = await ai`Critically analyze these research findings:
95
+ ${findings.map((f, i) => `${i + 1}. ${f}`).join('\n')}
96
+
97
+ Provide:
98
+ - analysis: array of analytical insights (3-4 insights)
99
+ - gaps: any gaps or areas needing more research
100
+ - confidence: confidence in the analysis 0-1`
101
+
102
+ const result: AgentResult = {
103
+ agent: 'Analyst',
104
+ findings: analysis as string[],
105
+ confidence: (confidence as number) || 0.6,
106
+ }
107
+
108
+ console.log(`[Analyst Agent] Generated ${result.findings.length} insights`)
109
+ return result
110
+ }
111
+
112
+ /**
113
+ * Synthesizer Agent - Creates final summary
114
+ */
115
+ async function synthesizerAgent(allResults: AgentResult[]): Promise<string> {
116
+ console.log('\n[Synthesizer Agent] Creating final synthesis...')
117
+
118
+ const allFindings = allResults.flatMap((r) => r.findings)
119
+
120
+ const synthesis = await write`Create a comprehensive research summary from these findings:
121
+
122
+ ${allFindings.map((f, i) => `- ${f}`).join('\n')}
123
+
124
+ Structure the summary with:
125
+ 1. Executive Summary (2-3 sentences)
126
+ 2. Key Findings (bullet points)
127
+ 3. Analysis & Insights
128
+ 4. Recommendations
129
+ 5. Areas for Further Research`
130
+
131
+ return synthesis
132
+ }
133
+
134
+ // ============================================================================
135
+ // Coordinator - Orchestrates the Multi-Agent Workflow
136
+ // ============================================================================
137
+
138
+ class ResearchCoordinator {
139
+ private topic: string
140
+ private results: AgentResult[] = []
141
+
142
+ constructor(topic: string) {
143
+ this.topic = topic
144
+ }
145
+
146
+ async run(): Promise<string> {
147
+ console.log(`\n${'='.repeat(60)}`)
148
+ console.log(`Research Topic: ${this.topic}`)
149
+ console.log('='.repeat(60))
150
+
151
+ // Phase 1: Planning
152
+ const questions = await plannerAgent(this.topic)
153
+
154
+ // Phase 2: Parallel Research
155
+ console.log('\n[Coordinator] Starting parallel research phase...')
156
+ const researchPromises = questions.slice(0, 3).map((q) => factFinderAgent(q))
157
+ const researchResults = await Promise.all(researchPromises)
158
+ this.results.push(...researchResults)
159
+
160
+ // Phase 3: Analysis
161
+ const allFacts = researchResults.flatMap((r) => r.findings)
162
+ const analysisResult = await analystAgent(allFacts)
163
+ this.results.push(analysisResult)
164
+
165
+ // Phase 4: Synthesis
166
+ const finalReport = await synthesizerAgent(this.results)
167
+
168
+ // Phase 5: Quality Check
169
+ const isQualityOk =
170
+ await is`This research summary is well-structured and comprehensive: "${finalReport.substring(
171
+ 0,
172
+ 200
173
+ )}..."`
174
+
175
+ if (!isQualityOk) {
176
+ console.log('[Coordinator] Quality check failed, requesting revision...')
177
+ // In production, you might iterate on the summary
178
+ }
179
+
180
+ return finalReport
181
+ }
182
+
183
+ getResults(): AgentResult[] {
184
+ return this.results
185
+ }
186
+ }
187
+
188
+ // ============================================================================
189
+ // Tool-Based Research Agent (Alternative Approach)
190
+ // ============================================================================
191
+
192
+ const searchTool = createTool({
193
+ name: 'search',
194
+ description: 'Search for information on a topic',
195
+ parameters: {
196
+ query: z.string().describe('Search query'),
197
+ },
198
+ execute: async ({ query }) => {
199
+ // Simulate search results
200
+ console.log(` [Tool] Searching: ${query}`)
201
+ return {
202
+ results: [
203
+ `Result 1 for "${query}": Found relevant information...`,
204
+ `Result 2 for "${query}": Additional context...`,
205
+ ],
206
+ }
207
+ },
208
+ })
209
+
210
+ const analyzeTool = createTool({
211
+ name: 'analyze',
212
+ description: 'Analyze and synthesize information',
213
+ parameters: {
214
+ data: z.string().describe('Data to analyze'),
215
+ perspective: z.string().describe('Analysis perspective'),
216
+ },
217
+ execute: async ({ data, perspective }) => {
218
+ console.log(` [Tool] Analyzing from ${perspective} perspective...`)
219
+ return {
220
+ analysis: `Analysis of "${data.substring(
221
+ 0,
222
+ 30
223
+ )}..." from ${perspective} perspective: Key insights identified.`,
224
+ }
225
+ },
226
+ })
227
+
228
+ async function toolBasedResearch(topic: string): Promise<void> {
229
+ console.log('\n--- Tool-Based Research Agent ---')
230
+
231
+ const loop = new AgenticLoop({
232
+ tools: createToolset(searchTool, analyzeTool),
233
+ maxSteps: 5,
234
+ onStep: (step) => {
235
+ console.log(`[Step ${step.stepNumber}] Tool calls: ${step.toolCalls.length}`)
236
+ },
237
+ })
238
+
239
+ // This requires a model that supports tool calling
240
+ // For demonstration, we'll skip the actual execution
241
+ console.log('Tool-based agent configured with:', loop.getToolsForSDK())
242
+ }
243
+
244
+ // ============================================================================
245
+ // Main Example
246
+ // ============================================================================
247
+
248
+ async function main() {
249
+ console.log('\n=== Multi-Agent Research Workflow ===\n')
250
+
251
+ // Configure the AI provider
252
+ configure({
253
+ model: 'sonnet',
254
+ provider: 'anthropic',
255
+ })
256
+
257
+ // Run the research workflow
258
+ const coordinator = new ResearchCoordinator(
259
+ 'The impact of Large Language Models on software development practices'
260
+ )
261
+
262
+ const report = await coordinator.run()
263
+
264
+ console.log('\n' + '='.repeat(60))
265
+ console.log('FINAL RESEARCH REPORT')
266
+ console.log('='.repeat(60))
267
+ console.log(report)
268
+
269
+ // Show agent statistics
270
+ console.log('\n--- Agent Statistics ---')
271
+ const results = coordinator.getResults()
272
+ for (const result of results) {
273
+ console.log(
274
+ `${result.agent}: ${result.findings.length} findings (confidence: ${result.confidence})`
275
+ )
276
+ }
277
+
278
+ // Demonstrate tool-based approach
279
+ await toolBasedResearch('AI in healthcare')
280
+ }
281
+
282
+ main()
283
+ .then(() => {
284
+ console.log('\n=== Example Complete ===\n')
285
+ process.exit(0)
286
+ })
287
+ .catch((error) => {
288
+ console.error('\nError:', error.message)
289
+ process.exit(1)
290
+ })