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
@@ -6,25 +6,32 @@
6
6
  * - 24-hour turnaround
7
7
  * - Up to 10,000 requests per batch
8
8
  *
9
+ * This file is a small adapter on top of the BatchProvider port (`./provider.js`).
10
+ * It owns only the Anthropic-specific request/response shapes and HTTP calls;
11
+ * shared concerns (polling, JSON-Schema conversion, JSON parsing) live in the port.
12
+ *
9
13
  * @see https://docs.anthropic.com/en/docs/build-with-claude/message-batches
10
14
  *
11
15
  * @packageDocumentation
12
16
  */
13
17
 
18
+ import { schema as convertSchema } from '../schema.js'
14
19
  import {
20
+ pollUntilComplete,
15
21
  registerBatchAdapter,
22
+ tryParseJson,
23
+ zodToJsonSchema,
16
24
  type BatchAdapter,
17
25
  type BatchItem,
18
26
  type BatchJob,
19
27
  type BatchQueueOptions,
20
28
  type BatchResult,
21
- type BatchSubmitResult,
22
29
  type BatchStatus,
23
- } from '../batch-queue.js'
24
- import { schema as convertSchema } from '../schema.js'
30
+ type BatchSubmitResult,
31
+ } from './provider.js'
25
32
 
26
33
  // ============================================================================
27
- // Types
34
+ // Provider-specific types
28
35
  // ============================================================================
29
36
 
30
37
  interface AnthropicBatchRequest {
@@ -87,7 +94,7 @@ interface AnthropicBatch {
87
94
  }
88
95
 
89
96
  // ============================================================================
90
- // Anthropic Client
97
+ // Anthropic client
91
98
  // ============================================================================
92
99
 
93
100
  let anthropicApiKey: string | undefined
@@ -95,37 +102,40 @@ let anthropicBaseUrl = 'https://api.anthropic.com/v1'
95
102
  const ANTHROPIC_VERSION = '2023-06-01'
96
103
  const ANTHROPIC_BETA = 'message-batches-2024-09-24'
97
104
 
98
- /**
99
- * Configure the Anthropic client
100
- */
105
+ /** Configure the Anthropic client. */
101
106
  export function configureAnthropic(options: { apiKey?: string; baseUrl?: string }): void {
102
107
  if (options.apiKey) anthropicApiKey = options.apiKey
103
108
  if (options.baseUrl) anthropicBaseUrl = options.baseUrl
104
109
  }
105
110
 
106
111
  function getApiKey(): string {
107
- const key = anthropicApiKey || process.env.ANTHROPIC_API_KEY
112
+ const key = anthropicApiKey || process.env['ANTHROPIC_API_KEY']
108
113
  if (!key) {
109
- throw new Error('Anthropic API key not configured. Set ANTHROPIC_API_KEY or call configureAnthropic()')
114
+ throw new Error(
115
+ 'Anthropic API key not configured. Set ANTHROPIC_API_KEY or call configureAnthropic()'
116
+ )
110
117
  }
111
118
  return key
112
119
  }
113
120
 
121
+ function anthropicHeaders(): Record<string, string> {
122
+ return {
123
+ 'x-api-key': getApiKey(),
124
+ 'anthropic-version': ANTHROPIC_VERSION,
125
+ 'anthropic-beta': ANTHROPIC_BETA,
126
+ 'Content-Type': 'application/json',
127
+ }
128
+ }
129
+
114
130
  async function anthropicRequest<T>(
115
131
  method: 'GET' | 'POST',
116
132
  path: string,
117
133
  body?: unknown
118
134
  ): Promise<T> {
119
- const url = `${anthropicBaseUrl}${path}`
120
- const response = await fetch(url, {
135
+ const response = await fetch(`${anthropicBaseUrl}${path}`, {
121
136
  method,
122
- headers: {
123
- 'x-api-key': getApiKey(),
124
- 'anthropic-version': ANTHROPIC_VERSION,
125
- 'anthropic-beta': ANTHROPIC_BETA,
126
- 'Content-Type': 'application/json',
127
- },
128
- body: body ? JSON.stringify(body) : undefined,
137
+ headers: anthropicHeaders(),
138
+ ...(body !== undefined && { body: JSON.stringify(body) }),
129
139
  })
130
140
 
131
141
  if (!response.ok) {
@@ -136,10 +146,6 @@ async function anthropicRequest<T>(
136
146
  return response.json()
137
147
  }
138
148
 
139
- // ============================================================================
140
- // Status Mapping
141
- // ============================================================================
142
-
143
149
  function mapStatus(batch: AnthropicBatch): BatchStatus {
144
150
  if (batch.cancel_initiated_at) {
145
151
  return batch.processing_status === 'ended' ? 'cancelled' : 'cancelling'
@@ -150,8 +156,30 @@ function mapStatus(batch: AnthropicBatch): BatchStatus {
150
156
  return 'in_progress'
151
157
  }
152
158
 
159
+ function toBatchJob(batch: AnthropicBatch, totalItemsHint?: number): BatchJob {
160
+ const totalFromCounts =
161
+ batch.request_counts.processing +
162
+ batch.request_counts.succeeded +
163
+ batch.request_counts.errored +
164
+ batch.request_counts.canceled +
165
+ batch.request_counts.expired
166
+
167
+ return {
168
+ id: batch.id,
169
+ provider: 'anthropic',
170
+ status: mapStatus(batch),
171
+ totalItems: totalItemsHint ?? totalFromCounts,
172
+ completedItems: batch.request_counts.succeeded,
173
+ failedItems:
174
+ batch.request_counts.errored + batch.request_counts.expired + batch.request_counts.canceled,
175
+ createdAt: new Date(batch.created_at),
176
+ ...(batch.ended_at && { completedAt: new Date(batch.ended_at) }),
177
+ expiresAt: new Date(batch.expires_at),
178
+ }
179
+ }
180
+
153
181
  // ============================================================================
154
- // Anthropic Batch Adapter
182
+ // Anthropic adapter (BatchProvider port)
155
183
  // ============================================================================
156
184
 
157
185
  const anthropicAdapter: BatchAdapter = {
@@ -159,7 +187,6 @@ const anthropicAdapter: BatchAdapter = {
159
187
  const model = options.model || 'claude-sonnet-4-20250514'
160
188
  const maxTokens = 4096
161
189
 
162
- // Build batch requests
163
190
  const requests: AnthropicBatchRequest[] = items.map((item) => {
164
191
  const request: AnthropicBatchRequest = {
165
192
  custom_id: item.id,
@@ -167,21 +194,20 @@ const anthropicAdapter: BatchAdapter = {
167
194
  model,
168
195
  max_tokens: item.options?.maxTokens || maxTokens,
169
196
  messages: [{ role: 'user', content: item.prompt }],
170
- system: item.options?.system,
171
- temperature: item.options?.temperature,
197
+ ...(item.options?.system !== undefined && { system: item.options.system }),
198
+ ...(item.options?.temperature !== undefined && {
199
+ temperature: item.options.temperature,
200
+ }),
172
201
  },
173
202
  }
174
203
 
175
- // Add JSON schema as a tool if provided
176
204
  if (item.schema) {
177
205
  const zodSchema = convertSchema(item.schema)
178
- const jsonSchema = zodToJsonSchema(zodSchema)
179
-
180
206
  request.params.tools = [
181
207
  {
182
208
  name: 'structured_response',
183
209
  description: 'Generate a structured response matching the schema',
184
- input_schema: jsonSchema,
210
+ input_schema: zodToJsonSchema(zodSchema),
185
211
  },
186
212
  ]
187
213
  request.params.tool_choice = { type: 'tool', name: 'structured_response' }
@@ -190,48 +216,22 @@ const anthropicAdapter: BatchAdapter = {
190
216
  return request
191
217
  })
192
218
 
193
- // Create the batch
194
219
  const batch = await anthropicRequest<AnthropicBatch>('POST', '/messages/batches', {
195
220
  requests,
196
221
  })
197
222
 
198
- const job: BatchJob = {
199
- id: batch.id,
200
- provider: 'anthropic',
201
- status: mapStatus(batch),
202
- totalItems: items.length,
203
- completedItems: batch.request_counts.succeeded,
204
- failedItems: batch.request_counts.errored + batch.request_counts.expired + batch.request_counts.canceled,
205
- createdAt: new Date(batch.created_at),
206
- expiresAt: new Date(batch.expires_at),
207
- webhookUrl: options.webhookUrl,
223
+ const job = toBatchJob(batch, items.length)
224
+ if (options.webhookUrl !== undefined) {
225
+ job.webhookUrl = options.webhookUrl
208
226
  }
209
227
 
210
- // Create completion promise
211
228
  const completion = this.waitForCompletion(batch.id)
212
-
213
229
  return { job, completion }
214
230
  },
215
231
 
216
232
  async getStatus(batchId: string): Promise<BatchJob> {
217
233
  const batch = await anthropicRequest<AnthropicBatch>('GET', `/messages/batches/${batchId}`)
218
-
219
- return {
220
- id: batch.id,
221
- provider: 'anthropic',
222
- status: mapStatus(batch),
223
- totalItems:
224
- batch.request_counts.processing +
225
- batch.request_counts.succeeded +
226
- batch.request_counts.errored +
227
- batch.request_counts.canceled +
228
- batch.request_counts.expired,
229
- completedItems: batch.request_counts.succeeded,
230
- failedItems: batch.request_counts.errored + batch.request_counts.expired + batch.request_counts.canceled,
231
- createdAt: new Date(batch.created_at),
232
- completedAt: batch.ended_at ? new Date(batch.ended_at) : undefined,
233
- expiresAt: new Date(batch.expires_at),
234
- }
234
+ return toBatchJob(batch)
235
235
  },
236
236
 
237
237
  async cancel(batchId: string): Promise<void> {
@@ -245,129 +245,64 @@ const anthropicAdapter: BatchAdapter = {
245
245
  throw new Error(`Batch not complete. Status: ${status.status}`)
246
246
  }
247
247
 
248
- // Fetch results (Anthropic returns them directly via the API)
248
+ // Anthropic returns results via a signed URL on the batch object.
249
249
  const batch = await anthropicRequest<AnthropicBatch>('GET', `/messages/batches/${batchId}`)
250
-
251
250
  if (!batch.results_url) {
252
251
  throw new Error('No results URL available')
253
252
  }
254
253
 
255
- // Download results from the URL
256
- const response = await fetch(batch.results_url, {
257
- headers: {
258
- 'x-api-key': getApiKey(),
259
- 'anthropic-version': ANTHROPIC_VERSION,
260
- 'anthropic-beta': ANTHROPIC_BETA,
261
- },
262
- })
263
-
254
+ const response = await fetch(batch.results_url, { headers: anthropicHeaders() })
264
255
  if (!response.ok) {
265
256
  throw new Error(`Failed to fetch results: ${response.status}`)
266
257
  }
267
258
 
268
- const content = await response.text()
269
- const lines = content.trim().split('\n')
270
- const results: BatchResult[] = []
271
-
272
- for (const line of lines) {
273
- const result: AnthropicBatchResult = JSON.parse(line)
274
-
275
- if (result.result.type === 'succeeded' && result.result.message) {
276
- const message = result.result.message
277
- let extractedResult: unknown
278
-
279
- // Extract from tool use or text
280
- const toolUse = message.content.find((c) => c.type === 'tool_use')
281
- const textContent = message.content.find((c) => c.type === 'text')
282
-
283
- if (toolUse?.input) {
284
- extractedResult = toolUse.input
285
- } else if (textContent?.text) {
286
- // Try to parse as JSON
287
- try {
288
- extractedResult = JSON.parse(textContent.text)
289
- } catch {
290
- extractedResult = textContent.text
291
- }
292
- }
293
-
294
- results.push({
295
- id: result.custom_id,
296
- customId: result.custom_id,
297
- status: 'completed',
298
- result: extractedResult,
299
- usage: {
300
- promptTokens: message.usage.input_tokens,
301
- completionTokens: message.usage.output_tokens,
302
- totalTokens: message.usage.input_tokens + message.usage.output_tokens,
303
- },
304
- })
305
- } else {
306
- results.push({
307
- id: result.custom_id,
308
- customId: result.custom_id,
309
- status: 'failed',
310
- error: result.result.error?.message || `Request ${result.result.type}`,
311
- })
312
- }
313
- }
314
-
315
- return results
259
+ const lines = (await response.text()).trim().split('\n')
260
+ return lines.map(parseAnthropicResult)
316
261
  },
317
262
 
318
263
  async waitForCompletion(batchId: string, pollInterval = 5000): Promise<BatchResult[]> {
319
- while (true) {
320
- const status = await this.getStatus(batchId)
321
-
322
- if (status.status === 'completed' || status.status === 'cancelled') {
323
- return this.getResults(batchId)
324
- }
325
-
326
- await new Promise((resolve) => setTimeout(resolve, pollInterval))
327
- }
264
+ return pollUntilComplete(this, batchId, { pollInterval })
328
265
  },
329
266
  }
330
267
 
331
- // ============================================================================
332
- // Helpers
333
- // ============================================================================
268
+ function parseAnthropicResult(line: string): BatchResult {
269
+ const result: AnthropicBatchResult = JSON.parse(line)
334
270
 
335
- /**
336
- * Simple Zod to JSON Schema converter
337
- */
338
- function zodToJsonSchema(zodSchema: unknown): Record<string, unknown> {
339
- const schema = zodSchema as { _def?: { typeName?: string; shape?: unknown } }
271
+ if (result.result.type === 'succeeded' && result.result.message) {
272
+ const message = result.result.message
273
+ const toolUse = message.content.find((c) => c.type === 'tool_use')
274
+ const textContent = message.content.find((c) => c.type === 'text')
340
275
 
341
- if (!schema._def) {
342
- return { type: 'object' }
343
- }
276
+ let extractedResult: unknown
277
+ if (toolUse?.input) {
278
+ extractedResult = toolUse.input
279
+ } else if (textContent?.text) {
280
+ extractedResult = tryParseJson(textContent.text)
281
+ }
344
282
 
345
- const typeName = schema._def.typeName
346
-
347
- switch (typeName) {
348
- case 'ZodString':
349
- return { type: 'string' }
350
- case 'ZodNumber':
351
- return { type: 'number' }
352
- case 'ZodBoolean':
353
- return { type: 'boolean' }
354
- case 'ZodArray':
355
- return { type: 'array', items: zodToJsonSchema((schema._def as any).type) }
356
- case 'ZodObject': {
357
- const shape = (schema._def as any).shape()
358
- const properties: Record<string, unknown> = {}
359
- for (const [key, value] of Object.entries(shape)) {
360
- properties[key] = zodToJsonSchema(value)
361
- }
362
- return { type: 'object', properties, required: Object.keys(properties) }
283
+ return {
284
+ id: result.custom_id,
285
+ customId: result.custom_id,
286
+ status: 'completed',
287
+ result: extractedResult,
288
+ usage: {
289
+ promptTokens: message.usage.input_tokens,
290
+ completionTokens: message.usage.output_tokens,
291
+ totalTokens: message.usage.input_tokens + message.usage.output_tokens,
292
+ },
363
293
  }
364
- default:
365
- return { type: 'object' }
294
+ }
295
+
296
+ return {
297
+ id: result.custom_id,
298
+ customId: result.custom_id,
299
+ status: 'failed',
300
+ error: result.result.error?.message || `Request ${result.result.type}`,
366
301
  }
367
302
  }
368
303
 
369
304
  // ============================================================================
370
- // Register Adapter
305
+ // Register adapter
371
306
  // ============================================================================
372
307
 
373
308
  registerBatchAdapter('anthropic', anthropicAdapter)