ai-functions 0.3.0 → 0.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 (400) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-test.log +105 -0
  3. package/README.md +190 -86
  4. package/TODO.md +138 -0
  5. package/dist/ai-promise.d.ts +219 -0
  6. package/dist/ai-promise.d.ts.map +1 -0
  7. package/dist/ai-promise.js +610 -0
  8. package/dist/ai-promise.js.map +1 -0
  9. package/dist/ai.d.ts +285 -0
  10. package/dist/ai.d.ts.map +1 -0
  11. package/dist/ai.js +842 -0
  12. package/dist/ai.js.map +1 -0
  13. package/dist/batch/anthropic.d.ts +23 -0
  14. package/dist/batch/anthropic.d.ts.map +1 -0
  15. package/dist/batch/anthropic.js +257 -0
  16. package/dist/batch/anthropic.js.map +1 -0
  17. package/dist/batch/bedrock.d.ts +64 -0
  18. package/dist/batch/bedrock.d.ts.map +1 -0
  19. package/dist/batch/bedrock.js +586 -0
  20. package/dist/batch/bedrock.js.map +1 -0
  21. package/dist/batch/cloudflare.d.ts +37 -0
  22. package/dist/batch/cloudflare.d.ts.map +1 -0
  23. package/dist/batch/cloudflare.js +289 -0
  24. package/dist/batch/cloudflare.js.map +1 -0
  25. package/dist/batch/google.d.ts +41 -0
  26. package/dist/batch/google.d.ts.map +1 -0
  27. package/dist/batch/google.js +360 -0
  28. package/dist/batch/google.js.map +1 -0
  29. package/dist/batch/index.d.ts +31 -0
  30. package/dist/batch/index.d.ts.map +1 -0
  31. package/dist/batch/index.js +31 -0
  32. package/dist/batch/index.js.map +1 -0
  33. package/dist/batch/memory.d.ts +44 -0
  34. package/dist/batch/memory.d.ts.map +1 -0
  35. package/dist/batch/memory.js +188 -0
  36. package/dist/batch/memory.js.map +1 -0
  37. package/dist/batch/openai.d.ts +37 -0
  38. package/dist/batch/openai.d.ts.map +1 -0
  39. package/dist/batch/openai.js +403 -0
  40. package/dist/batch/openai.js.map +1 -0
  41. package/dist/batch-map.d.ts +125 -0
  42. package/dist/batch-map.d.ts.map +1 -0
  43. package/dist/batch-map.js +406 -0
  44. package/dist/batch-map.js.map +1 -0
  45. package/dist/batch-queue.d.ts +273 -0
  46. package/dist/batch-queue.d.ts.map +1 -0
  47. package/dist/batch-queue.js +271 -0
  48. package/dist/batch-queue.js.map +1 -0
  49. package/dist/context.d.ts +133 -0
  50. package/dist/context.d.ts.map +1 -0
  51. package/dist/context.js +267 -0
  52. package/dist/context.js.map +1 -0
  53. package/dist/embeddings.d.ts +123 -0
  54. package/dist/embeddings.d.ts.map +1 -0
  55. package/dist/embeddings.js +170 -0
  56. package/dist/embeddings.js.map +1 -0
  57. package/dist/eval/index.d.ts +8 -0
  58. package/dist/eval/index.d.ts.map +1 -0
  59. package/dist/eval/index.js +8 -0
  60. package/dist/eval/index.js.map +1 -0
  61. package/dist/eval/models.d.ts +66 -0
  62. package/dist/eval/models.d.ts.map +1 -0
  63. package/dist/eval/models.js +120 -0
  64. package/dist/eval/models.js.map +1 -0
  65. package/dist/eval/runner.d.ts +64 -0
  66. package/dist/eval/runner.d.ts.map +1 -0
  67. package/dist/eval/runner.js +148 -0
  68. package/dist/eval/runner.js.map +1 -0
  69. package/dist/generate.d.ts +168 -0
  70. package/dist/generate.d.ts.map +1 -0
  71. package/dist/generate.js +174 -0
  72. package/dist/generate.js.map +1 -0
  73. package/dist/index.d.ts +29 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +53 -52
  76. package/dist/index.js.map +1 -1
  77. package/dist/primitives.d.ts +292 -0
  78. package/dist/primitives.d.ts.map +1 -0
  79. package/dist/primitives.js +471 -0
  80. package/dist/primitives.js.map +1 -0
  81. package/dist/providers/cloudflare.d.ts +9 -0
  82. package/dist/providers/cloudflare.d.ts.map +1 -0
  83. package/dist/providers/cloudflare.js +9 -0
  84. package/dist/providers/cloudflare.js.map +1 -0
  85. package/dist/providers/index.d.ts +9 -0
  86. package/dist/providers/index.d.ts.map +1 -0
  87. package/dist/providers/index.js +9 -0
  88. package/dist/providers/index.js.map +1 -0
  89. package/dist/schema.d.ts +54 -0
  90. package/dist/schema.d.ts.map +1 -0
  91. package/dist/schema.js +109 -0
  92. package/dist/schema.js.map +1 -0
  93. package/dist/template.d.ts +73 -0
  94. package/dist/template.d.ts.map +1 -0
  95. package/dist/template.js +129 -0
  96. package/dist/template.js.map +1 -0
  97. package/dist/types.d.ts +474 -106
  98. package/dist/types.d.ts.map +1 -1
  99. package/dist/types.js +4 -8
  100. package/dist/types.js.map +1 -1
  101. package/evalite.config.ts +19 -0
  102. package/evals/README.md +212 -0
  103. package/evals/classification.eval.ts +108 -0
  104. package/evals/marketing.eval.ts +370 -0
  105. package/evals/math.eval.ts +94 -0
  106. package/evals/run-evals.ts +166 -0
  107. package/evals/structured-output.eval.ts +143 -0
  108. package/evals/writing.eval.ts +117 -0
  109. package/examples/batch-blog-posts.ts +160 -0
  110. package/package.json +57 -57
  111. package/src/ai-promise.ts +784 -0
  112. package/src/ai.ts +1183 -0
  113. package/src/batch/anthropic.ts +375 -0
  114. package/src/batch/bedrock.ts +801 -0
  115. package/src/batch/cloudflare.ts +421 -0
  116. package/src/batch/google.ts +491 -0
  117. package/src/batch/index.ts +31 -0
  118. package/src/batch/memory.ts +253 -0
  119. package/src/batch/openai.ts +557 -0
  120. package/src/batch-map.ts +534 -0
  121. package/src/batch-queue.ts +493 -0
  122. package/src/context.ts +332 -0
  123. package/src/embeddings.ts +244 -0
  124. package/src/eval/index.ts +8 -0
  125. package/src/eval/models.ts +158 -0
  126. package/src/eval/runner.ts +217 -0
  127. package/src/generate.ts +245 -0
  128. package/src/index.ts +154 -0
  129. package/src/primitives.ts +612 -0
  130. package/src/providers/cloudflare.ts +15 -0
  131. package/src/providers/index.ts +14 -0
  132. package/src/schema.ts +147 -0
  133. package/src/template.ts +209 -0
  134. package/src/types.ts +540 -0
  135. package/test/README.md +105 -0
  136. package/test/ai-proxy.test.ts +192 -0
  137. package/test/async-iterators.test.ts +327 -0
  138. package/test/batch-background.test.ts +482 -0
  139. package/test/batch-blog-posts.test.ts +387 -0
  140. package/test/blog-generation.test.ts +510 -0
  141. package/test/browse-read.test.ts +611 -0
  142. package/test/core-functions.test.ts +694 -0
  143. package/test/decide.test.ts +393 -0
  144. package/test/define.test.ts +274 -0
  145. package/test/e2e-bedrock-manual.ts +163 -0
  146. package/test/e2e-bedrock.test.ts +191 -0
  147. package/test/e2e-flex-gateway.ts +157 -0
  148. package/test/e2e-flex-manual.ts +183 -0
  149. package/test/e2e-flex.test.ts +209 -0
  150. package/test/e2e-google-manual.ts +178 -0
  151. package/test/e2e-google.test.ts +216 -0
  152. package/test/embeddings.test.ts +284 -0
  153. package/test/evals/define-function.eval.test.ts +379 -0
  154. package/test/evals/primitives.eval.test.ts +384 -0
  155. package/test/function-types.test.ts +492 -0
  156. package/test/generate-core.test.ts +319 -0
  157. package/test/generate.test.ts +163 -0
  158. package/test/implicit-batch.test.ts +422 -0
  159. package/test/schema.test.ts +109 -0
  160. package/test/tagged-templates.test.ts +302 -0
  161. package/tsconfig.json +10 -0
  162. package/vitest.config.ts +42 -0
  163. package/LICENSE +0 -21
  164. package/bin/cli.js +0 -5
  165. package/dist/cli/index.d.ts +0 -10
  166. package/dist/cli/index.d.ts.map +0 -1
  167. package/dist/cli/index.js +0 -38
  168. package/dist/cli/index.js.map +0 -1
  169. package/dist/cli/index.test.d.ts +0 -2
  170. package/dist/cli/index.test.d.ts.map +0 -1
  171. package/dist/cli/index.test.js +0 -35
  172. package/dist/cli/index.test.js.map +0 -1
  173. package/dist/constants/models.d.ts +0 -10
  174. package/dist/constants/models.d.ts.map +0 -1
  175. package/dist/constants/models.js +0 -12
  176. package/dist/constants/models.js.map +0 -1
  177. package/dist/converters/index.d.ts +0 -3
  178. package/dist/converters/index.d.ts.map +0 -1
  179. package/dist/converters/index.js +0 -3
  180. package/dist/converters/index.js.map +0 -1
  181. package/dist/converters/model.d.ts +0 -4
  182. package/dist/converters/model.d.ts.map +0 -1
  183. package/dist/converters/model.js +0 -19
  184. package/dist/converters/model.js.map +0 -1
  185. package/dist/converters/schema.d.ts +0 -4
  186. package/dist/converters/schema.d.ts.map +0 -1
  187. package/dist/converters/schema.js +0 -25
  188. package/dist/converters/schema.js.map +0 -1
  189. package/dist/core/responses.d.ts +0 -5
  190. package/dist/core/responses.d.ts.map +0 -1
  191. package/dist/core/responses.js +0 -16
  192. package/dist/core/responses.js.map +0 -1
  193. package/dist/core/responses.test.d.ts +0 -2
  194. package/dist/core/responses.test.d.ts.map +0 -1
  195. package/dist/core/responses.test.js +0 -31
  196. package/dist/core/responses.test.js.map +0 -1
  197. package/dist/errors.d.ts +0 -6
  198. package/dist/errors.d.ts.map +0 -1
  199. package/dist/errors.js +0 -9
  200. package/dist/errors.js.map +0 -1
  201. package/dist/examples/streaming.test.d.ts +0 -2
  202. package/dist/examples/streaming.test.d.ts.map +0 -1
  203. package/dist/examples/streaming.test.js +0 -176
  204. package/dist/examples/streaming.test.js.map +0 -1
  205. package/dist/factory/__tests__/index.test.d.ts +0 -2
  206. package/dist/factory/__tests__/index.test.d.ts.map +0 -1
  207. package/dist/factory/__tests__/index.test.js +0 -430
  208. package/dist/factory/__tests__/index.test.js.map +0 -1
  209. package/dist/factory/__tests__/list.test.d.ts +0 -2
  210. package/dist/factory/__tests__/list.test.d.ts.map +0 -1
  211. package/dist/factory/__tests__/list.test.js +0 -92
  212. package/dist/factory/__tests__/list.test.js.map +0 -1
  213. package/dist/factory/index.d.ts +0 -20
  214. package/dist/factory/index.d.ts.map +0 -1
  215. package/dist/factory/index.js +0 -287
  216. package/dist/factory/index.js.map +0 -1
  217. package/dist/factory/index.test.d.ts +0 -2
  218. package/dist/factory/index.test.d.ts.map +0 -1
  219. package/dist/factory/index.test.js +0 -287
  220. package/dist/factory/index.test.js.map +0 -1
  221. package/dist/factory/list.d.ts +0 -3
  222. package/dist/factory/list.d.ts.map +0 -1
  223. package/dist/factory/list.js +0 -221
  224. package/dist/factory/list.js.map +0 -1
  225. package/dist/factory/list.test.d.ts +0 -2
  226. package/dist/factory/list.test.d.ts.map +0 -1
  227. package/dist/factory/list.test.js +0 -84
  228. package/dist/factory/list.test.js.map +0 -1
  229. package/dist/generate/index.d.ts +0 -5
  230. package/dist/generate/index.d.ts.map +0 -1
  231. package/dist/generate/index.js +0 -17
  232. package/dist/generate/index.js.map +0 -1
  233. package/dist/index.test.d.ts +0 -2
  234. package/dist/index.test.d.ts.map +0 -1
  235. package/dist/index.test.js +0 -59
  236. package/dist/index.test.js.map +0 -1
  237. package/dist/list/await.d.ts +0 -3
  238. package/dist/list/await.d.ts.map +0 -1
  239. package/dist/list/await.js +0 -28
  240. package/dist/list/await.js.map +0 -1
  241. package/dist/list/constants.d.ts +0 -4
  242. package/dist/list/constants.d.ts.map +0 -1
  243. package/dist/list/constants.js +0 -5
  244. package/dist/list/constants.js.map +0 -1
  245. package/dist/list/create-function.d.ts +0 -3
  246. package/dist/list/create-function.d.ts.map +0 -1
  247. package/dist/list/create-function.js +0 -11
  248. package/dist/list/create-function.js.map +0 -1
  249. package/dist/list/index.d.ts +0 -4
  250. package/dist/list/index.d.ts.map +0 -1
  251. package/dist/list/index.js +0 -5
  252. package/dist/list/index.js.map +0 -1
  253. package/dist/list/prompt.d.ts +0 -3
  254. package/dist/list/prompt.d.ts.map +0 -1
  255. package/dist/list/prompt.js +0 -6
  256. package/dist/list/prompt.js.map +0 -1
  257. package/dist/list/schemas.d.ts +0 -4
  258. package/dist/list/schemas.d.ts.map +0 -1
  259. package/dist/list/schemas.js +0 -8
  260. package/dist/list/schemas.js.map +0 -1
  261. package/dist/list/stream.d.ts +0 -3
  262. package/dist/list/stream.d.ts.map +0 -1
  263. package/dist/list/stream.js +0 -33
  264. package/dist/list/stream.js.map +0 -1
  265. package/dist/list/types.d.ts +0 -11
  266. package/dist/list/types.d.ts.map +0 -1
  267. package/dist/list/types.js +0 -2
  268. package/dist/list/types.js.map +0 -1
  269. package/dist/list/validation.d.ts +0 -3
  270. package/dist/list/validation.d.ts.map +0 -1
  271. package/dist/list/validation.js +0 -12
  272. package/dist/list/validation.js.map +0 -1
  273. package/dist/providers/config.d.ts +0 -4
  274. package/dist/providers/config.d.ts.map +0 -1
  275. package/dist/providers/config.js +0 -21
  276. package/dist/providers/config.js.map +0 -1
  277. package/dist/providers/config.test.d.ts +0 -2
  278. package/dist/providers/config.test.d.ts.map +0 -1
  279. package/dist/providers/config.test.js +0 -37
  280. package/dist/providers/config.test.js.map +0 -1
  281. package/dist/proxy/constants.d.ts +0 -4
  282. package/dist/proxy/constants.d.ts.map +0 -1
  283. package/dist/proxy/constants.js +0 -5
  284. package/dist/proxy/constants.js.map +0 -1
  285. package/dist/proxy/create-function.d.ts +0 -4
  286. package/dist/proxy/create-function.d.ts.map +0 -1
  287. package/dist/proxy/create-function.js +0 -24
  288. package/dist/proxy/create-function.js.map +0 -1
  289. package/dist/proxy/create-proxy.d.ts +0 -2
  290. package/dist/proxy/create-proxy.d.ts.map +0 -1
  291. package/dist/proxy/create-proxy.js +0 -11
  292. package/dist/proxy/create-proxy.js.map +0 -1
  293. package/dist/proxy/function-generator.d.ts +0 -9
  294. package/dist/proxy/function-generator.d.ts.map +0 -1
  295. package/dist/proxy/function-generator.js +0 -29
  296. package/dist/proxy/function-generator.js.map +0 -1
  297. package/dist/proxy/index.d.ts +0 -4
  298. package/dist/proxy/index.d.ts.map +0 -1
  299. package/dist/proxy/index.js +0 -4
  300. package/dist/proxy/index.js.map +0 -1
  301. package/dist/proxy/prompt.d.ts +0 -2
  302. package/dist/proxy/prompt.d.ts.map +0 -1
  303. package/dist/proxy/prompt.js +0 -6
  304. package/dist/proxy/prompt.js.map +0 -1
  305. package/dist/proxy/types.d.ts +0 -7
  306. package/dist/proxy/types.d.ts.map +0 -1
  307. package/dist/proxy/types.js +0 -2
  308. package/dist/proxy/types.js.map +0 -1
  309. package/dist/queue/manager.d.ts +0 -5
  310. package/dist/queue/manager.d.ts.map +0 -1
  311. package/dist/queue/manager.js +0 -37
  312. package/dist/queue/manager.js.map +0 -1
  313. package/dist/queue/manager.test.d.ts +0 -2
  314. package/dist/queue/manager.test.d.ts.map +0 -1
  315. package/dist/queue/manager.test.js +0 -52
  316. package/dist/queue/manager.test.js.map +0 -1
  317. package/dist/schema-converter.d.ts +0 -4
  318. package/dist/schema-converter.d.ts.map +0 -1
  319. package/dist/schema-converter.js +0 -30
  320. package/dist/schema-converter.js.map +0 -1
  321. package/dist/stream/index.d.ts +0 -7
  322. package/dist/stream/index.d.ts.map +0 -1
  323. package/dist/stream/index.js +0 -23
  324. package/dist/stream/index.js.map +0 -1
  325. package/dist/streaming/utils.d.ts +0 -4
  326. package/dist/streaming/utils.d.ts.map +0 -1
  327. package/dist/streaming/utils.js +0 -131
  328. package/dist/streaming/utils.js.map +0 -1
  329. package/dist/streaming/utils.test.d.ts +0 -2
  330. package/dist/streaming/utils.test.d.ts.map +0 -1
  331. package/dist/streaming/utils.test.js +0 -84
  332. package/dist/streaming/utils.test.js.map +0 -1
  333. package/dist/templates/result.d.ts +0 -7
  334. package/dist/templates/result.d.ts.map +0 -1
  335. package/dist/templates/result.js +0 -40
  336. package/dist/templates/result.js.map +0 -1
  337. package/dist/templates/result.test.d.ts +0 -2
  338. package/dist/templates/result.test.d.ts.map +0 -1
  339. package/dist/templates/result.test.js +0 -75
  340. package/dist/templates/result.test.js.map +0 -1
  341. package/dist/test/setup.d.ts +0 -2
  342. package/dist/test/setup.d.ts.map +0 -1
  343. package/dist/test/setup.js +0 -21
  344. package/dist/test/setup.js.map +0 -1
  345. package/dist/test-types.d.ts +0 -13
  346. package/dist/test-types.d.ts.map +0 -1
  347. package/dist/test-types.js +0 -55
  348. package/dist/test-types.js.map +0 -1
  349. package/dist/types/index.d.ts +0 -4
  350. package/dist/types/index.d.ts.map +0 -1
  351. package/dist/types/index.js +0 -4
  352. package/dist/types/index.js.map +0 -1
  353. package/dist/types/list.d.ts +0 -10
  354. package/dist/types/list.d.ts.map +0 -1
  355. package/dist/types/list.js +0 -2
  356. package/dist/types/list.js.map +0 -1
  357. package/dist/types/model.d.ts +0 -7
  358. package/dist/types/model.d.ts.map +0 -1
  359. package/dist/types/model.js +0 -2
  360. package/dist/types/model.js.map +0 -1
  361. package/dist/types/options.d.ts +0 -25
  362. package/dist/types/options.d.ts.map +0 -1
  363. package/dist/types/options.js +0 -2
  364. package/dist/types/options.js.map +0 -1
  365. package/dist/types/schema.d.ts +0 -5
  366. package/dist/types/schema.d.ts.map +0 -1
  367. package/dist/types/schema.js +0 -2
  368. package/dist/types/schema.js.map +0 -1
  369. package/dist/utils/__tests__/request-handler.test.d.ts +0 -2
  370. package/dist/utils/__tests__/request-handler.test.d.ts.map +0 -1
  371. package/dist/utils/__tests__/request-handler.test.js +0 -134
  372. package/dist/utils/__tests__/request-handler.test.js.map +0 -1
  373. package/dist/utils/__tests__/schema.test.d.ts +0 -2
  374. package/dist/utils/__tests__/schema.test.d.ts.map +0 -1
  375. package/dist/utils/__tests__/schema.test.js +0 -49
  376. package/dist/utils/__tests__/schema.test.js.map +0 -1
  377. package/dist/utils/__tests__/stream-progress.test.d.ts +0 -2
  378. package/dist/utils/__tests__/stream-progress.test.d.ts.map +0 -1
  379. package/dist/utils/__tests__/stream-progress.test.js +0 -85
  380. package/dist/utils/__tests__/stream-progress.test.js.map +0 -1
  381. package/dist/utils/index.d.ts +0 -2
  382. package/dist/utils/index.d.ts.map +0 -1
  383. package/dist/utils/index.js +0 -2
  384. package/dist/utils/index.js.map +0 -1
  385. package/dist/utils/request-handler.d.ts +0 -17
  386. package/dist/utils/request-handler.d.ts.map +0 -1
  387. package/dist/utils/request-handler.js +0 -105
  388. package/dist/utils/request-handler.js.map +0 -1
  389. package/dist/utils/schema.d.ts +0 -11
  390. package/dist/utils/schema.d.ts.map +0 -1
  391. package/dist/utils/schema.js +0 -51
  392. package/dist/utils/schema.js.map +0 -1
  393. package/dist/utils/stream-progress.d.ts +0 -17
  394. package/dist/utils/stream-progress.d.ts.map +0 -1
  395. package/dist/utils/stream-progress.js +0 -86
  396. package/dist/utils/stream-progress.js.map +0 -1
  397. package/dist/utils/validation.d.ts +0 -3
  398. package/dist/utils/validation.d.ts.map +0 -1
  399. package/dist/utils/validation.js +0 -30
  400. package/dist/utils/validation.js.map +0 -1
@@ -0,0 +1,421 @@
1
+ /**
2
+ * Cloudflare AI Gateway Batch Adapter
3
+ *
4
+ * Implements batch processing using Cloudflare AI Gateway's batch endpoint.
5
+ * Cloudflare's batch API is newer but integrates well with Workers.
6
+ *
7
+ * Note: Cloudflare's batch API is evolving. This adapter implements
8
+ * the current batch capabilities and can be extended as new features land.
9
+ *
10
+ * @see https://developers.cloudflare.com/ai-gateway/
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+
15
+ import {
16
+ registerBatchAdapter,
17
+ type BatchAdapter,
18
+ type BatchItem,
19
+ type BatchJob,
20
+ type BatchQueueOptions,
21
+ type BatchResult,
22
+ type BatchSubmitResult,
23
+ type BatchStatus,
24
+ } from '../batch-queue.js'
25
+ import { schema as convertSchema } from '../schema.js'
26
+
27
+ // ============================================================================
28
+ // Types
29
+ // ============================================================================
30
+
31
+ interface CloudflareBatchRequest {
32
+ id: string
33
+ provider: string
34
+ endpoint: string
35
+ headers: Record<string, string>
36
+ query: {
37
+ model: string
38
+ messages: Array<{ role: string; content: string }>
39
+ response_format?: { type: 'json_object' }
40
+ max_tokens?: number
41
+ temperature?: number
42
+ }
43
+ }
44
+
45
+ interface CloudflareBatchResponse {
46
+ id: string
47
+ success: boolean
48
+ result?: {
49
+ response: string
50
+ usage?: {
51
+ prompt_tokens: number
52
+ completion_tokens: number
53
+ total_tokens: number
54
+ }
55
+ }
56
+ error?: {
57
+ message: string
58
+ code?: string
59
+ }
60
+ }
61
+
62
+ interface CloudflareBatchJob {
63
+ id: string
64
+ status: 'pending' | 'processing' | 'completed' | 'failed'
65
+ created_at: string
66
+ completed_at?: string
67
+ request_count: number
68
+ completed_count: number
69
+ failed_count: number
70
+ results_url?: string
71
+ }
72
+
73
+ // ============================================================================
74
+ // Cloudflare Client Configuration
75
+ // ============================================================================
76
+
77
+ let accountId: string | undefined
78
+ let gatewayId: string | undefined
79
+ let apiToken: string | undefined
80
+ let baseUrl = 'https://api.cloudflare.com/client/v4'
81
+
82
+ /**
83
+ * Configure the Cloudflare client
84
+ */
85
+ export function configureCloudflare(options: {
86
+ accountId?: string
87
+ gatewayId?: string
88
+ apiToken?: string
89
+ baseUrl?: string
90
+ }): void {
91
+ if (options.accountId) accountId = options.accountId
92
+ if (options.gatewayId) gatewayId = options.gatewayId
93
+ if (options.apiToken) apiToken = options.apiToken
94
+ if (options.baseUrl) baseUrl = options.baseUrl
95
+ }
96
+
97
+ function getConfig(): { accountId: string; gatewayId: string; apiToken: string } {
98
+ const accId = accountId || process.env.CLOUDFLARE_ACCOUNT_ID
99
+ const gwId = gatewayId || process.env.CLOUDFLARE_AI_GATEWAY_ID || process.env.AI_GATEWAY_ID
100
+ const token = apiToken || process.env.CLOUDFLARE_API_TOKEN
101
+
102
+ if (!accId) {
103
+ throw new Error('Cloudflare account ID not configured. Set CLOUDFLARE_ACCOUNT_ID or call configureCloudflare()')
104
+ }
105
+ if (!gwId) {
106
+ throw new Error('Cloudflare AI Gateway ID not configured. Set CLOUDFLARE_AI_GATEWAY_ID or call configureCloudflare()')
107
+ }
108
+ if (!token) {
109
+ throw new Error('Cloudflare API token not configured. Set CLOUDFLARE_API_TOKEN or call configureCloudflare()')
110
+ }
111
+
112
+ return { accountId: accId, gatewayId: gwId, apiToken: token }
113
+ }
114
+
115
+ async function cloudflareRequest<T>(
116
+ method: 'GET' | 'POST',
117
+ path: string,
118
+ body?: unknown
119
+ ): Promise<T> {
120
+ const config = getConfig()
121
+ const url = `${baseUrl}${path}`
122
+
123
+ const response = await fetch(url, {
124
+ method,
125
+ headers: {
126
+ Authorization: `Bearer ${config.apiToken}`,
127
+ 'Content-Type': 'application/json',
128
+ },
129
+ body: body ? JSON.stringify(body) : undefined,
130
+ })
131
+
132
+ if (!response.ok) {
133
+ const error = await response.text()
134
+ throw new Error(`Cloudflare API error: ${response.status} ${error}`)
135
+ }
136
+
137
+ const data = await response.json() as { success: boolean; result: T; errors?: unknown[] }
138
+ if (!data.success) {
139
+ throw new Error(`Cloudflare API error: ${JSON.stringify(data.errors)}`)
140
+ }
141
+
142
+ return data.result
143
+ }
144
+
145
+ // ============================================================================
146
+ // In-memory job storage (for polling)
147
+ // ============================================================================
148
+
149
+ const pendingJobs = new Map<string, {
150
+ items: BatchItem[]
151
+ options: BatchQueueOptions
152
+ results: BatchResult[]
153
+ status: BatchStatus
154
+ createdAt: Date
155
+ completedAt?: Date
156
+ }>()
157
+
158
+ let jobCounter = 0
159
+
160
+ // ============================================================================
161
+ // Cloudflare Batch Adapter
162
+ // ============================================================================
163
+
164
+ /**
165
+ * Cloudflare batch adapter
166
+ *
167
+ * Note: Cloudflare's AI Gateway doesn't have a native batch API like OpenAI/Anthropic.
168
+ * This adapter implements batch processing by:
169
+ * 1. Sending requests concurrently through the gateway
170
+ * 2. Utilizing Cloudflare's caching and rate limiting
171
+ * 3. Tracking job state locally (or in D1/KV for production)
172
+ *
173
+ * For true async batch processing, consider using Cloudflare Queues + Workers.
174
+ */
175
+ const cloudflareAdapter: BatchAdapter = {
176
+ async submit(items: BatchItem[], options: BatchQueueOptions): Promise<BatchSubmitResult> {
177
+ const config = getConfig()
178
+ const jobId = `cf_batch_${++jobCounter}_${Date.now()}`
179
+ const model = options.model || 'mistral/mistral-7b-instruct-v0.1'
180
+
181
+ // Store job state
182
+ pendingJobs.set(jobId, {
183
+ items,
184
+ options,
185
+ results: [],
186
+ status: 'pending',
187
+ createdAt: new Date(),
188
+ })
189
+
190
+ // Process requests concurrently (Cloudflare handles rate limiting)
191
+ const completion = processCloudflareRequests(jobId, items, config, model, options)
192
+
193
+ const job: BatchJob = {
194
+ id: jobId,
195
+ provider: 'cloudflare',
196
+ status: 'pending',
197
+ totalItems: items.length,
198
+ completedItems: 0,
199
+ failedItems: 0,
200
+ createdAt: new Date(),
201
+ webhookUrl: options.webhookUrl,
202
+ }
203
+
204
+ return { job, completion }
205
+ },
206
+
207
+ async getStatus(batchId: string): Promise<BatchJob> {
208
+ const job = pendingJobs.get(batchId)
209
+ if (!job) {
210
+ throw new Error(`Batch not found: ${batchId}`)
211
+ }
212
+
213
+ const completedItems = job.results.filter((r) => r.status === 'completed').length
214
+ const failedItems = job.results.filter((r) => r.status === 'failed').length
215
+
216
+ return {
217
+ id: batchId,
218
+ provider: 'cloudflare',
219
+ status: job.status,
220
+ totalItems: job.items.length,
221
+ completedItems,
222
+ failedItems,
223
+ createdAt: job.createdAt,
224
+ completedAt: job.completedAt,
225
+ }
226
+ },
227
+
228
+ async cancel(batchId: string): Promise<void> {
229
+ const job = pendingJobs.get(batchId)
230
+ if (job) {
231
+ job.status = 'cancelled'
232
+ }
233
+ },
234
+
235
+ async getResults(batchId: string): Promise<BatchResult[]> {
236
+ const job = pendingJobs.get(batchId)
237
+ if (!job) {
238
+ throw new Error(`Batch not found: ${batchId}`)
239
+ }
240
+ return job.results
241
+ },
242
+
243
+ async waitForCompletion(batchId: string, pollInterval = 1000): Promise<BatchResult[]> {
244
+ const job = pendingJobs.get(batchId)
245
+ if (!job) {
246
+ throw new Error(`Batch not found: ${batchId}`)
247
+ }
248
+
249
+ while (job.status !== 'completed' && job.status !== 'failed' && job.status !== 'cancelled') {
250
+ await new Promise((resolve) => setTimeout(resolve, pollInterval))
251
+ }
252
+
253
+ return job.results
254
+ },
255
+ }
256
+
257
+ // ============================================================================
258
+ // Processing
259
+ // ============================================================================
260
+
261
+ async function processCloudflareRequests(
262
+ jobId: string,
263
+ items: BatchItem[],
264
+ config: { accountId: string; gatewayId: string; apiToken: string },
265
+ model: string,
266
+ options: BatchQueueOptions
267
+ ): Promise<BatchResult[]> {
268
+ const job = pendingJobs.get(jobId)
269
+ if (!job) {
270
+ throw new Error(`Job not found: ${jobId}`)
271
+ }
272
+
273
+ job.status = 'in_progress'
274
+
275
+ // Process all requests concurrently with concurrency limit
276
+ const CONCURRENCY = 10
277
+ const results: BatchResult[] = []
278
+
279
+ for (let i = 0; i < items.length; i += CONCURRENCY) {
280
+ const batch = items.slice(i, i + CONCURRENCY)
281
+
282
+ const batchResults = await Promise.all(
283
+ batch.map(async (item) => {
284
+ try {
285
+ const result = await processCloudflareItem(item, config, model)
286
+ return result
287
+ } catch (error) {
288
+ return {
289
+ id: item.id,
290
+ customId: item.id,
291
+ status: 'failed' as const,
292
+ error: error instanceof Error ? error.message : 'Unknown error',
293
+ }
294
+ }
295
+ })
296
+ )
297
+
298
+ results.push(...batchResults)
299
+ job.results = results
300
+ }
301
+
302
+ job.status = results.every((r) => r.status === 'completed') ? 'completed' : 'failed'
303
+ job.completedAt = new Date()
304
+
305
+ return results
306
+ }
307
+
308
+ async function processCloudflareItem(
309
+ item: BatchItem,
310
+ config: { accountId: string; gatewayId: string; apiToken: string },
311
+ model: string
312
+ ): Promise<BatchResult> {
313
+ // Route through AI Gateway
314
+ const gatewayUrl = `https://gateway.ai.cloudflare.com/v1/${config.accountId}/${config.gatewayId}`
315
+
316
+ // Determine provider from model
317
+ let provider = 'workers-ai'
318
+ let endpoint = ''
319
+
320
+ if (model.startsWith('openai/') || model.startsWith('gpt-')) {
321
+ provider = 'openai'
322
+ endpoint = '/chat/completions'
323
+ } else if (model.startsWith('anthropic/') || model.startsWith('claude-')) {
324
+ provider = 'anthropic'
325
+ endpoint = '/messages'
326
+ } else if (model.startsWith('@cf/') || model.startsWith('workers-ai/')) {
327
+ provider = 'workers-ai'
328
+ endpoint = `/ai/run/${model.replace('workers-ai/', '').replace('@cf/', '')}`
329
+ } else {
330
+ // Default to OpenAI-compatible
331
+ provider = 'openai'
332
+ endpoint = '/chat/completions'
333
+ }
334
+
335
+ const url = `${gatewayUrl}/${provider}${endpoint}`
336
+
337
+ const messages = [
338
+ ...(item.options?.system ? [{ role: 'system', content: item.options.system }] : []),
339
+ { role: 'user', content: item.prompt },
340
+ ]
341
+
342
+ const body: Record<string, unknown> = {
343
+ model: model.replace(`${provider}/`, ''),
344
+ messages,
345
+ max_tokens: item.options?.maxTokens || 4096,
346
+ temperature: item.options?.temperature,
347
+ }
348
+
349
+ // Add JSON mode if schema is provided
350
+ if (item.schema) {
351
+ body.response_format = { type: 'json_object' }
352
+ }
353
+
354
+ const response = await fetch(url, {
355
+ method: 'POST',
356
+ headers: {
357
+ 'cf-aig-authorization': `Bearer ${config.apiToken}`,
358
+ 'Content-Type': 'application/json',
359
+ },
360
+ body: JSON.stringify(body),
361
+ })
362
+
363
+ if (!response.ok) {
364
+ const error = await response.text()
365
+ throw new Error(`Cloudflare Gateway error: ${response.status} ${error}`)
366
+ }
367
+
368
+ const data = await response.json() as {
369
+ choices?: Array<{ message: { content: string } }>
370
+ content?: Array<{ text: string }>
371
+ response?: string
372
+ usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number }
373
+ }
374
+
375
+ // Extract content based on response format
376
+ let content: string | undefined
377
+
378
+ if (data.choices?.[0]?.message?.content) {
379
+ // OpenAI format
380
+ content = data.choices[0].message.content
381
+ } else if (data.content?.[0]?.text) {
382
+ // Anthropic format
383
+ content = data.content[0].text
384
+ } else if (data.response) {
385
+ // Workers AI format
386
+ content = data.response
387
+ }
388
+
389
+ let result: unknown = content
390
+
391
+ // Try to parse JSON if schema was provided
392
+ if (item.schema && content) {
393
+ try {
394
+ result = JSON.parse(content)
395
+ } catch {
396
+ // Keep as string
397
+ }
398
+ }
399
+
400
+ return {
401
+ id: item.id,
402
+ customId: item.id,
403
+ status: 'completed',
404
+ result,
405
+ usage: data.usage
406
+ ? {
407
+ promptTokens: data.usage.prompt_tokens,
408
+ completionTokens: data.usage.completion_tokens,
409
+ totalTokens: data.usage.total_tokens,
410
+ }
411
+ : undefined,
412
+ }
413
+ }
414
+
415
+ // ============================================================================
416
+ // Register Adapter
417
+ // ============================================================================
418
+
419
+ registerBatchAdapter('cloudflare', cloudflareAdapter)
420
+
421
+ export { cloudflareAdapter }