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,143 @@
1
+ /**
2
+ * Structured Output Eval
3
+ *
4
+ * Tests model ability to generate valid structured JSON output
5
+ * matching specified schemas across all providers.
6
+ */
7
+
8
+ import { evalite } from 'evalite'
9
+ import { generateObject } from '../src/generate.js'
10
+ import { schema } from '../src/schema.js'
11
+ import { createModelVariants, getModelPricing, type EvalModel } from '../src/eval/models.js'
12
+
13
+ // Test cases for structured output
14
+ const TEST_CASES = [
15
+ {
16
+ name: 'Simple object',
17
+ prompt: 'Generate a greeting in French',
18
+ schema: {
19
+ greeting: 'A friendly greeting',
20
+ language: 'The language of the greeting',
21
+ },
22
+ expectedTypes: { greeting: 'string', language: 'string' },
23
+ },
24
+ {
25
+ name: 'With numbers',
26
+ prompt: 'Generate info about Tokyo',
27
+ schema: {
28
+ name: 'City name',
29
+ population: 'Population in millions (number)',
30
+ area: 'Area in square kilometers (number)',
31
+ },
32
+ expectedTypes: { name: 'string', population: 'number', area: 'number' },
33
+ },
34
+ {
35
+ name: 'With arrays',
36
+ prompt: 'Generate a simple pasta recipe',
37
+ schema: {
38
+ title: 'Recipe title',
39
+ ingredients: ['List of ingredients'],
40
+ steps: ['Cooking steps'],
41
+ },
42
+ expectedTypes: { title: 'string', ingredients: 'array', steps: 'array' },
43
+ },
44
+ {
45
+ name: 'With enum',
46
+ prompt: 'Analyze sentiment: "I love this product!"',
47
+ schema: {
48
+ sentiment: 'positive | negative | neutral',
49
+ confidence: 'Confidence score 0-1 (number)',
50
+ },
51
+ expectedTypes: { sentiment: 'string', confidence: 'number' },
52
+ },
53
+ {
54
+ name: 'Nested object',
55
+ prompt: 'Generate a fictional person living in Japan',
56
+ schema: {
57
+ person: { name: 'Full name', age: 'Age (number)' },
58
+ address: { city: 'City name', country: 'Country name' },
59
+ },
60
+ expectedTypes: { person: 'object', address: 'object' },
61
+ },
62
+ ]
63
+
64
+ // Test across models - start with fast tier for quick iteration
65
+ const modelVariants = createModelVariants({ tiers: ['fast'] })
66
+
67
+ evalite.each(modelVariants)('Structured Output', {
68
+ data: TEST_CASES.map(tc => ({ input: tc })),
69
+
70
+ task: async (input, variant) => {
71
+ const model = variant as EvalModel
72
+ const startTime = Date.now()
73
+
74
+ const { object, usage } = await generateObject({
75
+ model: model.id,
76
+ schema: schema(input.schema),
77
+ prompt: input.prompt,
78
+ })
79
+
80
+ const latencyMs = Date.now() - startTime
81
+
82
+ // Calculate cost from language-models pricing
83
+ const pricing = getModelPricing(model.id)
84
+ const cost = pricing
85
+ ? ((usage?.promptTokens ?? 0) * pricing.prompt + (usage?.completionTokens ?? 0) * pricing.completion) / 1_000_000
86
+ : 0
87
+
88
+ return {
89
+ object,
90
+ expectedTypes: input.expectedTypes,
91
+ testName: input.name,
92
+ modelId: model.id,
93
+ modelName: model.name,
94
+ provider: model.provider,
95
+ latencyMs,
96
+ cost,
97
+ usage,
98
+ }
99
+ },
100
+
101
+ scorers: [
102
+ // Type accuracy
103
+ {
104
+ name: 'Type Accuracy',
105
+ description: 'Whether output fields have correct types',
106
+ scorer: ({ output }) => {
107
+ const obj = output.object as Record<string, unknown>
108
+ const expected = output.expectedTypes as Record<string, string>
109
+ const fields = Object.keys(expected)
110
+
111
+ let correct = 0
112
+ for (const field of fields) {
113
+ const val = obj[field]
114
+ const expectedType = expected[field]
115
+ const actualType = Array.isArray(val) ? 'array' : typeof val
116
+
117
+ if (actualType === expectedType) correct++
118
+ }
119
+
120
+ return { score: correct / fields.length }
121
+ },
122
+ },
123
+
124
+ // Latency
125
+ {
126
+ name: 'Latency',
127
+ description: 'Response time (target < 3s)',
128
+ scorer: ({ output }) => {
129
+ const ms = output.latencyMs as number
130
+ if (ms < 2000) return { score: 1 }
131
+ if (ms > 10000) return { score: 0 }
132
+ return { score: 1 - (ms - 2000) / 8000 }
133
+ },
134
+ },
135
+ ],
136
+
137
+ columns: ({ output, scores }) => [
138
+ { label: 'Model', value: output.modelName },
139
+ { label: 'Test', value: output.testName },
140
+ { label: 'Latency', value: `${output.latencyMs}ms` },
141
+ { label: 'Cost', value: `$${(output.cost as number).toFixed(6)}` },
142
+ ],
143
+ })
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Writing Quality Eval (LLM-as-Judge)
3
+ *
4
+ * Tests model writing capabilities using LLM-as-judge scoring.
5
+ * Uses a strong model (sonnet) to judge output quality.
6
+ */
7
+
8
+ import { evalite } from 'evalite'
9
+ import { generateText, generateObject } from '../src/generate.js'
10
+ import { schema } from '../src/schema.js'
11
+ import { createModelVariants, type EvalModel } from '../src/eval/models.js'
12
+
13
+ // Use sonnet as the judge model
14
+ const JUDGE_MODEL = 'sonnet'
15
+
16
+ // Writing test cases
17
+ const TEST_CASES = [
18
+ {
19
+ name: 'Professional email',
20
+ prompt: 'Write a professional email declining a meeting invitation politely.',
21
+ criteria: ['Polite tone', 'Clear explanation', 'Proper email format'],
22
+ },
23
+ {
24
+ name: 'Product description',
25
+ prompt: 'Write a product description for wireless earbuds targeting tech-savvy consumers.',
26
+ criteria: ['Highlights features', 'Compelling language', 'Clear value proposition'],
27
+ },
28
+ {
29
+ name: 'Explanation',
30
+ prompt: 'Explain how photosynthesis works in simple terms for a high school student.',
31
+ criteria: ['Accurate content', 'Clear language', 'Logical flow'],
32
+ },
33
+ ]
34
+
35
+ const modelVariants = createModelVariants({ tiers: ['fast'] })
36
+
37
+ evalite.each(modelVariants)('Writing Quality', {
38
+ data: TEST_CASES.map(tc => ({ input: tc })),
39
+
40
+ task: async (input, variant) => {
41
+ const model = variant as EvalModel
42
+ const startTime = Date.now()
43
+
44
+ // Generate the writing
45
+ const { text, usage } = await generateText({
46
+ model: model.id,
47
+ prompt: input.prompt,
48
+ })
49
+
50
+ const latencyMs = Date.now() - startTime
51
+
52
+ return {
53
+ text,
54
+ testName: input.name,
55
+ criteria: input.criteria,
56
+ modelId: model.id,
57
+ modelName: model.name,
58
+ provider: model.provider,
59
+ latencyMs,
60
+ usage,
61
+ }
62
+ },
63
+
64
+ scorers: [
65
+ // LLM-as-judge for quality
66
+ {
67
+ name: 'Writing Quality',
68
+ description: 'LLM judge evaluation of writing quality',
69
+ scorer: async ({ input, output }) => {
70
+ const { object } = await generateObject({
71
+ model: JUDGE_MODEL,
72
+ schema: schema({
73
+ clarity: 'How clear is the writing? (number 0-1)',
74
+ engagement: 'How engaging is the content? (number 0-1)',
75
+ accuracy: 'How well does it meet the criteria? (number 0-1)',
76
+ reasoning: 'Brief explanation',
77
+ }),
78
+ prompt: `Evaluate this writing on a scale of 0-1.
79
+
80
+ Criteria: ${(input.criteria as string[]).join(', ')}
81
+
82
+ Writing:
83
+ """
84
+ ${output.text}
85
+ """`,
86
+ })
87
+
88
+ const avg = ((object.clarity as number) + (object.engagement as number) + (object.accuracy as number)) / 3
89
+ return {
90
+ score: avg,
91
+ metadata: object,
92
+ }
93
+ },
94
+ },
95
+
96
+ // Word count check
97
+ {
98
+ name: 'Appropriate Length',
99
+ description: 'Whether output has reasonable length',
100
+ scorer: ({ output }) => {
101
+ const words = (output.text as string).split(/\s+/).length
102
+ if (words < 20) return { score: 0.3, metadata: { words } }
103
+ if (words > 500) return { score: 0.7, metadata: { words } }
104
+ return { score: 1, metadata: { words } }
105
+ },
106
+ },
107
+ ],
108
+
109
+ columns: ({ output }) => [
110
+ { label: 'Model', value: output.modelName },
111
+ { label: 'Test', value: output.testName },
112
+ { label: 'Words', value: (output.text as string).split(/\s+/).length },
113
+ { label: 'Latency', value: `${output.latencyMs}ms` },
114
+ ],
115
+
116
+ trialCount: 2, // Run twice for variance
117
+ })
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Batch Blog Post Generation Example
3
+ *
4
+ * This example demonstrates the new IMPLICIT batch processing:
5
+ *
6
+ * ```ts
7
+ * // Configure once (or use environment variables)
8
+ * configure({ provider: 'openai', model: 'gpt-4o', batchMode: 'auto' })
9
+ *
10
+ * // Use naturally - batching is automatic!
11
+ * const titles = await list`10 blog post titles about startups`
12
+ * const posts = titles.map(title => write`blog post: # ${title}`)
13
+ * console.log(await posts) // Batched automatically!
14
+ * ```
15
+ *
16
+ * Environment variables:
17
+ * - AI_PROVIDER: openai | anthropic | cloudflare | bedrock
18
+ * - AI_MODEL: model name (e.g., gpt-4o, claude-sonnet-4-20250514)
19
+ * - AI_BATCH_MODE: auto | immediate | deferred
20
+ * - AI_BATCH_THRESHOLD: minimum items for auto batch (default: 5)
21
+ *
22
+ * @example
23
+ * ```bash
24
+ * # Using environment variables
25
+ * AI_PROVIDER=openai AI_MODEL=gpt-4o npx tsx examples/batch-blog-posts.ts
26
+ *
27
+ * # Or with API keys
28
+ * OPENAI_API_KEY=sk-... npx tsx examples/batch-blog-posts.ts
29
+ * ```
30
+ */
31
+
32
+ import {
33
+ list,
34
+ write,
35
+ configure,
36
+ withContext,
37
+ type BatchProvider,
38
+ } from '../src/index.js'
39
+
40
+ // Import the batch adapter for your provider
41
+ // import '../src/batch/openai.js'
42
+ // import '../src/batch/anthropic.js'
43
+ // import '../src/batch/cloudflare.js'
44
+ // import '../src/batch/bedrock.js'
45
+
46
+ // For testing, use the memory adapter
47
+ import '../src/batch/memory.js'
48
+
49
+ async function main() {
50
+ console.log('\n🚀 Implicit Batch Blog Post Generation\n')
51
+
52
+ // ============================================================================
53
+ // Option 1: Global Configuration (recommended)
54
+ // ============================================================================
55
+
56
+ configure({
57
+ provider: 'openai',
58
+ model: 'gpt-4o',
59
+ batchMode: 'auto', // 'auto' | 'immediate' | 'deferred'
60
+ batchThreshold: 5, // Use batch API when >= 5 items
61
+ })
62
+
63
+ console.log('📝 Step 1: Generate titles (executes immediately)...')
64
+ const titles = await list`10 blog post titles about building startups in 2026`
65
+
66
+ console.log(`\nGenerated ${(titles as any).length || 10} titles`)
67
+
68
+ // ============================================================================
69
+ // Option 2: The Clean API (what you asked for!)
70
+ // ============================================================================
71
+
72
+ console.log('\n⚡ Step 2: Map titles to blog posts (automatic batching)...')
73
+ console.log(' Code: titles.map(title => write`blog post: # ${title}`)')
74
+
75
+ // This is the API you wanted!
76
+ // - No explicit batch creation
77
+ // - No provider/model in the code
78
+ // - Automatic batch detection based on context
79
+ const posts = (titles as string[]).map(title =>
80
+ write`Write a comprehensive blog post for startup founders:
81
+
82
+ # ${title}
83
+
84
+ Include:
85
+ - Attention-grabbing introduction
86
+ - 3-5 key sections with actionable insights
87
+ - Real-world examples
88
+ - Compelling conclusion with call-to-action`
89
+ )
90
+
91
+ console.log(` Created ${posts.length} deferred operations`)
92
+
93
+ // When you await, it resolves via batch API if beneficial
94
+ console.log('\n⏳ Step 3: Await results (batched automatically)...')
95
+ // Note: Each item is an AIPromise, we'd await them all
96
+ // const results = await Promise.all(posts)
97
+
98
+ console.log('\n✅ Done!')
99
+
100
+ // ============================================================================
101
+ // Option 3: Scoped Context (for different providers in same code)
102
+ // ============================================================================
103
+
104
+ console.log('\n🔄 Bonus: Using withContext for scoped configuration...')
105
+
106
+ await withContext(
107
+ { provider: 'anthropic', model: 'claude-sonnet-4-20250514', batchMode: 'deferred' },
108
+ async () => {
109
+ console.log(' Inside context: Using Anthropic with deferred batching')
110
+ // All operations here use Anthropic
111
+ // const summaries = titles.map(title => write`summarize: ${title}`)
112
+ }
113
+ )
114
+
115
+ console.log(' Outside context: Back to OpenAI')
116
+ }
117
+
118
+ // ============================================================================
119
+ // Summary of the API
120
+ // ============================================================================
121
+
122
+ /*
123
+ The new API is clean and implicit:
124
+
125
+ 1. Configure once (globally or via environment):
126
+ ```ts
127
+ configure({ provider: 'openai', model: 'gpt-4o', batchMode: 'auto' })
128
+ ```
129
+
130
+ 2. Use naturally:
131
+ ```ts
132
+ const titles = await list`10 blog post titles`
133
+ const posts = titles.map(title => write`blog post: # ${title}`)
134
+ ```
135
+
136
+ 3. Batching happens automatically when:
137
+ - batchMode is 'auto' and items >= batchThreshold
138
+ - batchMode is 'deferred' (always batch)
139
+
140
+ 4. No batching when:
141
+ - batchMode is 'immediate'
142
+ - batchMode is 'auto' and items < batchThreshold
143
+
144
+ 5. Provider batch APIs supported:
145
+ - OpenAI: 50% discount, 24hr turnaround
146
+ - Anthropic: 50% discount, 24hr turnaround
147
+ - Cloudflare: Via AI Gateway
148
+ - AWS Bedrock: Native batch inference
149
+ */
150
+
151
+ // Run the example
152
+ main()
153
+ .then(() => {
154
+ console.log('\n✨ Example complete!\n')
155
+ process.exit(0)
156
+ })
157
+ .catch((error) => {
158
+ console.error('\n❌ Error:', error.message)
159
+ process.exit(1)
160
+ })
package/package.json CHANGED
@@ -1,72 +1,72 @@
1
1
  {
2
2
  "name": "ai-functions",
3
- "version": "0.3.0",
4
- "description": "A powerful TypeScript library for building AI-powered applications with template literals and structured outputs",
3
+ "version": "0.4.0",
4
+ "description": "Core AI primitives for building intelligent applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
- "module": "dist/index.js",
8
7
  "types": "dist/index.d.ts",
9
- "bin": {
10
- "ai-functions": "bin/cli.js"
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./embeddings": {
14
+ "import": "./dist/embeddings.js",
15
+ "types": "./dist/embeddings.d.ts"
16
+ },
17
+ "./providers": {
18
+ "import": "./dist/providers/index.js",
19
+ "types": "./dist/providers/index.d.ts"
20
+ },
21
+ "./providers/cloudflare": {
22
+ "import": "./dist/providers/cloudflare.js",
23
+ "types": "./dist/providers/cloudflare.d.ts"
24
+ }
11
25
  },
12
- "files": [
13
- "dist",
14
- "bin"
15
- ],
16
26
  "scripts": {
17
- "build": "tsc",
18
- "test": "vitest run",
19
- "test:watch": "vitest",
20
- "lint": "eslint src",
21
- "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\" \"*.{md,mdx}\"",
22
- "prepublishOnly": "pnpm run build",
23
- "semantic-release": "semantic-release"
27
+ "build": "tsc -p tsconfig.json",
28
+ "dev": "tsc -p tsconfig.json --watch",
29
+ "test": "vitest",
30
+ "test:unit": "vitest run --exclude 'test/evals/**' --exclude 'test/e2e-*'",
31
+ "test:evals": "vitest run test/evals/",
32
+ "test:evals:primitives": "vitest run test/evals/primitives.eval.test.ts",
33
+ "test:evals:define": "vitest run test/evals/define-function.eval.test.ts",
34
+ "eval": "tsx evals/run-evals.ts",
35
+ "eval:fast": "tsx evals/run-evals.ts",
36
+ "eval:all": "tsx evals/run-evals.ts --all",
37
+ "eval:math": "tsx evals/run-evals.ts --math",
38
+ "eval:class": "tsx evals/run-evals.ts --class",
39
+ "eval:marketing": "tsx evals/marketing.eval.ts",
40
+ "eval:marketing:all": "tsx evals/marketing.eval.ts --all",
41
+ "typecheck": "tsc --noEmit",
42
+ "lint": "eslint .",
43
+ "clean": "rm -rf dist"
44
+ },
45
+ "dependencies": {
46
+ "@ai-sdk/amazon-bedrock": "^3.0.0",
47
+ "ai": "^5.0.0",
48
+ "ai-providers": "workspace:^",
49
+ "language-models": "workspace:*",
50
+ "rpc.do": "^0.1.0",
51
+ "yaml": "^2.8.0",
52
+ "zod": "^3.23.0"
53
+ },
54
+ "optionalDependencies": {
55
+ "oauth.do": "^0.0.1"
24
56
  },
25
57
  "keywords": [
26
58
  "ai",
27
- "openai",
28
- "template-literals",
29
- "typescript",
30
- "structured-output",
31
- "cli"
59
+ "functions",
60
+ "embeddings",
61
+ "cloudflare",
62
+ "oauth",
63
+ "primitives"
32
64
  ],
33
- "author": "AI Primitives",
34
65
  "license": "MIT",
35
- "homepage": "https://github.com/ai-primitives/ai-functions#readme",
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://github.com/ai-primitives/ai-functions.git"
39
- },
40
- "bugs": {
41
- "url": "https://github.com/ai-primitives/ai-functions/issues"
42
- },
43
66
  "devDependencies": {
44
- "@ai-sdk/provider": "^1.0.2",
45
- "@ai-sdk/provider-utils": "^2.0.4",
46
- "@ai-sdk/ui-utils": "^1.0.5",
47
- "@eslint/js": "^9.17.0",
48
- "@opentelemetry/api": "^1.9.0",
49
- "@semantic-release/commit-analyzer": "^13.0.0",
50
- "@semantic-release/github": "^11.0.1",
51
- "@semantic-release/npm": "^12.0.1",
52
- "@semantic-release/release-notes-generator": "^14.0.1",
53
- "@types/node": "^22.10.2",
54
- "@typescript-eslint/eslint-plugin": "^8.18.0",
55
- "@typescript-eslint/parser": "^8.18.0",
56
- "dotenv": "^16.4.7",
57
- "eslint": "^9.17.0",
58
- "prettier": "^3.4.2",
59
- "semantic-release": "^24.2.0",
60
- "typescript": "^5.7.2",
61
- "undici": "^7.2.0",
62
- "vitest": "^2.1.8",
63
- "web-streams-polyfill": "^4.0.0"
64
- },
65
- "dependencies": {
66
- "@ai-sdk/openai": "^1.0.10",
67
- "@ai-sdk/openai-compatible": "^0.0.9",
68
- "ai": "^4.0.20",
69
- "p-queue": "^8.0.1",
70
- "zod": "^3.24.1"
67
+ "dotenv": "^17.2.3",
68
+ "evalite": "^0.19.0",
69
+ "tsx": "^4.0.0",
70
+ "vitest": "^2.1.0"
71
71
  }
72
72
  }