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
package/src/types.ts CHANGED
@@ -2,16 +2,117 @@
2
2
  * Core types for AI functions
3
3
  */
4
4
 
5
+ import type { SandboxEnv } from 'ai-evaluate'
6
+
7
+ /**
8
+ * Host Workers environment for the ai-evaluate sandbox.
9
+ *
10
+ * Re-exported from ai-evaluate so consumers can type the optional `env`
11
+ * argument threaded through `DefinedFunction.call` / `generateAndRunCode`
12
+ * without importing ai-evaluate directly.
13
+ */
14
+ export type { SandboxEnv } from 'ai-evaluate'
15
+
16
+ // ============================================================================
17
+ // Human Function Pending Types
18
+ // ============================================================================
19
+
20
+ /**
21
+ * Symbol used to identify pending human function results
22
+ */
23
+ export const PENDING_HUMAN_RESULT_SYMBOL = Symbol.for('HumanFunctionPending')
24
+
25
+ /**
26
+ * Human interaction channels
27
+ *
28
+ * - chat: Real-time messaging (WebSocket, in-app)
29
+ * - email: Async email communication
30
+ * - phone: Voice calls
31
+ * - sms: SMS text messages
32
+ * - workspace: Team collaboration platforms (Slack, Teams, Discord)
33
+ * - web: Web-based interface (browser, web app)
34
+ */
35
+ export type HumanChannel = 'chat' | 'email' | 'phone' | 'sms' | 'workspace' | 'web'
36
+
37
+ /**
38
+ * Pending human function result returned when human input is not yet available.
39
+ *
40
+ * This is returned by human functions that need actual human input but are running
41
+ * in a placeholder mode (e.g., during testing or when channel integrations are not configured).
42
+ *
43
+ * Use `isPendingHumanResult()` to check if a result is pending before using it.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const result = await approveRefund({ amount: 500, reason: 'Duplicate charge' })
48
+ *
49
+ * if (isPendingHumanResult(result)) {
50
+ * console.log('Waiting for human approval via:', result.channel)
51
+ * // Handle pending state - queue for later, show UI, etc.
52
+ * } else {
53
+ * // result is the actual TOutput type
54
+ * console.log('Approved:', result.approved)
55
+ * }
56
+ * ```
57
+ */
58
+ export interface HumanFunctionPending<TExpected = unknown> {
59
+ /** Symbol marker for type identification */
60
+ readonly [PENDING_HUMAN_RESULT_SYMBOL]: true
61
+ /** Indicates this is a pending placeholder, not actual human response */
62
+ readonly _pending: true
63
+ /** The channel where human input was requested */
64
+ readonly channel: HumanChannel
65
+ /** Generated UI/content artifacts for the channel */
66
+ readonly artifacts: unknown
67
+ /** The expected response type schema */
68
+ readonly expectedResponseType: TExpected
69
+ }
70
+
71
+ /**
72
+ * Type guard to check if a result is a pending human function result.
73
+ *
74
+ * Use this to safely handle cases where human input is not yet available.
75
+ *
76
+ * @param value - The value to check
77
+ * @returns True if the value is a HumanFunctionPending object
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const result = await reviewDocument({ docId: '123' })
82
+ *
83
+ * if (isPendingHumanResult(result)) {
84
+ * // result is HumanFunctionPending - human input needed
85
+ * console.warn('Human review pending:', result.channel)
86
+ * return { status: 'pending', channel: result.channel }
87
+ * }
88
+ *
89
+ * // result is ReviewResult - actual human response
90
+ * return { status: 'reviewed', approved: result.approved }
91
+ * ```
92
+ */
93
+ export function isPendingHumanResult<T>(
94
+ value: T | HumanFunctionPending
95
+ ): value is HumanFunctionPending {
96
+ return (
97
+ value !== null &&
98
+ typeof value === 'object' &&
99
+ '_pending' in value &&
100
+ value._pending === true &&
101
+ PENDING_HUMAN_RESULT_SYMBOL in value
102
+ )
103
+ }
104
+
105
+ // ============================================================================
106
+ // AI Function Types
107
+ // ============================================================================
108
+
5
109
  /**
6
110
  * A function definition that can be called by AI
7
111
  *
8
112
  * @typeParam TOutput - The return type of the function handler
9
113
  * @typeParam TInput - The input type accepted by the function handler
10
114
  */
11
- export interface AIFunctionDefinition<
12
- TOutput = unknown,
13
- TInput = unknown
14
- > {
115
+ export interface AIFunctionDefinition<TOutput = unknown, TInput = unknown> {
15
116
  /** Unique name for the function */
16
117
  name: string
17
118
  /** Human-readable description for the AI */
@@ -162,9 +263,11 @@ export interface WriteOptions {
162
263
  /**
163
264
  * Type for functions that support both regular calls and tagged template literals
164
265
  */
165
- export type TemplateFunction<TArgs extends unknown[], TReturn> =
166
- & ((prompt: string, ...args: TArgs) => TReturn)
167
- & ((strings: TemplateStringsArray, ...values: unknown[]) => TReturn)
266
+ export type TemplateFunction<TArgs extends unknown[], TReturn> = ((
267
+ prompt: string,
268
+ ...args: TArgs
269
+ ) => TReturn) &
270
+ ((strings: TemplateStringsArray, ...values: unknown[]) => TReturn)
168
271
 
169
272
  /**
170
273
  * A single item in a list
@@ -210,18 +313,6 @@ export type CodeLanguage = 'typescript' | 'javascript' | 'python' | 'go' | 'rust
210
313
  */
211
314
  export type GenerativeOutputType = 'string' | 'object' | 'image' | 'video'
212
315
 
213
- /**
214
- * Human interaction channels
215
- *
216
- * - chat: Real-time messaging (WebSocket, in-app)
217
- * - email: Async email communication
218
- * - phone: Voice calls
219
- * - sms: SMS text messages
220
- * - workspace: Team collaboration platforms (Slack, Teams, Discord)
221
- * - web: Web-based interface (browser, web app)
222
- */
223
- export type HumanChannel = 'chat' | 'email' | 'phone' | 'sms' | 'workspace' | 'web'
224
-
225
316
  /**
226
317
  * Legacy channel type for backwards compatibility
227
318
  * @deprecated Use HumanChannel instead
@@ -273,12 +364,24 @@ export interface BaseFunctionDefinition<TOutput = unknown, TInput = unknown> {
273
364
  }
274
365
 
275
366
  /**
276
- * Code function - generates actual executable code
367
+ * Code function - a **deterministic** handler.
368
+ *
369
+ * `Code` is the deterministic kind: a fetch/transform/rule handler that runs
370
+ * the **same logic every time** with no model in the execution path. When
371
+ * called, it invokes the supplied {@link CodeFunctionDefinition.handler}
372
+ * (or evaluates the inline {@link CodeFunctionDefinition.code} body) and
373
+ * returns the result directly — no LLM is consulted at call time.
277
374
  *
278
- * When called, this generates:
279
- * - Implementation code with JSDoc comments
280
- * - Vitest test cases
281
- * - Example usage scripts
375
+ * This is the contract consumers bind to (e.g. ADR-0033's
376
+ * "Code = deterministic"). If you want a model to *author* code, that is a
377
+ * generation task: use {@link generateCode} / the `generate('code', …)`
378
+ * primitive, or define a `Generative` function whose output is source text.
379
+ * See the migration note in the package README.
380
+ *
381
+ * Exactly one of `handler` or `code` should be supplied. `handler` is the
382
+ * canonical form (a native function reference); `code` is an inline source
383
+ * body, deterministically compiled by the consumer's runtime — never sent to
384
+ * a model.
282
385
  *
283
386
  * @example
284
387
  * ```ts
@@ -290,7 +393,7 @@ export interface BaseFunctionDefinition<TOutput = unknown, TInput = unknown> {
290
393
  * rate: 'Tax rate as decimal (number)',
291
394
  * },
292
395
  * returnType: 'The calculated tax amount (number)',
293
- * language: 'typescript',
396
+ * handler: ({ amount, rate }) => amount * rate,
294
397
  * })
295
398
  * ```
296
399
  *
@@ -300,6 +403,51 @@ export interface BaseFunctionDefinition<TOutput = unknown, TInput = unknown> {
300
403
  export interface CodeFunctionDefinition<TOutput = unknown, TInput = unknown>
301
404
  extends BaseFunctionDefinition<TOutput, TInput> {
302
405
  type: 'code'
406
+ /**
407
+ * The deterministic handler invoked on every call. Receives the parsed
408
+ * `args` and returns (or resolves to) the result. No LLM is involved.
409
+ *
410
+ * Either `handler` or {@link CodeFunctionDefinition.code} must be provided;
411
+ * `handler` takes precedence when both are present.
412
+ */
413
+ handler?: (input: TInput) => TOutput | Promise<TOutput>
414
+ /**
415
+ * Inline source body for the handler, as a string. Deterministically
416
+ * compiled by the consumer's runtime (it is **not** generated by a model).
417
+ * Used when a handler cannot be passed by reference (e.g. a definition
418
+ * loaded from storage). The body receives the `args` in scope and should
419
+ * `return` the result.
420
+ *
421
+ * Either `code` or {@link CodeFunctionDefinition.handler} must be provided.
422
+ */
423
+ code?: string
424
+ /** Target programming language of `code` (default: `'typescript'`). Metadata only. */
425
+ language?: CodeLanguage
426
+ /** Optional human-readable note about what the handler does. Metadata only. */
427
+ instructions?: string
428
+ }
429
+
430
+ /**
431
+ * Definition for a code-**authoring** request — the explicit, opt-in path for
432
+ * having a model *write* code. This is the behavior `type: 'code'` used to
433
+ * have implicitly; it has been split out so that `Code` can mean
434
+ * "deterministic handler" without a silent change of meaning.
435
+ *
436
+ * This is **not** part of the {@link FunctionDefinition} union and never
437
+ * executes deterministically — calling it consults a model. Drive it via
438
+ * {@link generateCode}.
439
+ *
440
+ * @typeParam TInput - The arguments schema describing the code to author
441
+ */
442
+ export interface CodeGenerationDefinition<TInput = unknown> {
443
+ /** Name of the function/query to author */
444
+ name: string
445
+ /** Human-readable description of what the code should do */
446
+ description?: string
447
+ /** Arguments/spec schema describing the code to generate */
448
+ args: TInput
449
+ /** Return type schema the authored code should produce (optional) */
450
+ returnType?: unknown
303
451
  /** Target programming language */
304
452
  language?: CodeLanguage
305
453
  /** Additional context or requirements for code generation */
@@ -308,6 +456,8 @@ export interface CodeFunctionDefinition<TOutput = unknown, TInput = unknown>
308
456
  includeTests?: boolean
309
457
  /** Whether to include example usage (default: true) */
310
458
  includeExamples?: boolean
459
+ /** Model to use for authoring (defaults to 'sonnet') */
460
+ model?: string
311
461
  }
312
462
 
313
463
  /**
@@ -519,8 +669,17 @@ export type FunctionDefinition<TOutput = unknown, TInput = unknown> =
519
669
  export interface DefinedFunction<TOutput = unknown, TInput = unknown> {
520
670
  /** The original definition */
521
671
  definition: FunctionDefinition<TOutput, TInput>
522
- /** Call the function */
523
- call: (args: TInput) => Promise<TOutput>
672
+ /**
673
+ * Call the function.
674
+ *
675
+ * @param args - The function arguments.
676
+ * @param env - Optional host Workers env (carrying a `LOADER` worker-loader
677
+ * binding, and `TEST` for the test path) used by `type: 'code'` functions
678
+ * to run inline `code` bodies in ai-evaluate's sandbox. When omitted, the
679
+ * inline-code path falls back to the Miniflare-backed Node runtime. Has no
680
+ * effect on `handler`-based code functions or other function types.
681
+ */
682
+ call: (args: TInput, env?: SandboxEnv) => Promise<TOutput>
524
683
  /** Get the function as a tool definition for AI */
525
684
  asTool: () => AIFunctionDefinition<TOutput, TInput>
526
685
  }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * wrapForV3 — convenience composer for the v3 cascade-walker / evaluator-panel
3
+ * use case.
4
+ *
5
+ * Composes `cacheMiddleware`, `budgetMiddleware`, and `traceMiddleware` in a
6
+ * single `wrapLanguageModel` call so callers in services-as-software (round
7
+ * 15+ swap) can replace their existing post-hoc duck-typing in
8
+ * `cost-estimate.ts` with a single wrap call:
9
+ *
10
+ * ```ts
11
+ * import { wrapForV3, BudgetTracker, getEvalLogStore } from 'ai-functions'
12
+ *
13
+ * const tracker = new BudgetTracker({ maxCost: 1.0 })
14
+ * const store = getEvalLogStore()
15
+ *
16
+ * const wrapped = wrapForV3(openai('gpt-4o'), {
17
+ * cache: { store: 'disk', ttlMs: 86_400_000 },
18
+ * budget: { tracker },
19
+ * trace: { emit: (e) => store.record({ ...e, costUsd: e.costUsd ?? 0 }) },
20
+ * })
21
+ * ```
22
+ *
23
+ * **Composition order:**
24
+ * 1. **cache** — first so cache hits skip budget+trace network cost. The
25
+ * cached payload's usage still flows downstream so budget records the
26
+ * cost on hits AND misses.
27
+ * 2. **budget** — second so it sees the wrapped result regardless of
28
+ * cache hit/miss; tracker.recordUsage fires either way.
29
+ * 3. **trace** — last so the event sees the final outcome (post-cache,
30
+ * post-budget). Errors from `emit` are swallowed.
31
+ *
32
+ * AI SDK 6 ordering semantics (per the wrapLanguageModel JSDoc): "the first
33
+ * middleware will transform the input first, and the last middleware will
34
+ * be wrapped directly around the model." So when we hand the array
35
+ * `[cache, budget, trace]`, the runtime call order is
36
+ * `cache → budget → trace → model` on the way in, and the reverse on the
37
+ * way out. Cache sees the call first; if it has a hit, downstream layers
38
+ * never run their `wrapGenerate` body for that call. Budget and trace each
39
+ * get their own post-completion hook on the result the layer below them
40
+ * returned — so on a cache hit, neither budget nor trace runs (because
41
+ * cache short-circuits via `return cached`). To get budget + trace on
42
+ * cache hits, the budgetMiddleware/traceMiddleware would need to wrap the
43
+ * cache middleware (i.e. install AFTER it in the chain). Per the spec
44
+ * above, "later in the array = closer to the model" → install order
45
+ * matters: callers who want cache-hit cost recording should pass
46
+ * `[budget, trace, cache]`. We use `[cache, budget, trace]` as the default
47
+ * because the eval-fixture use case wants the 5x verify-time win and is
48
+ * happy to skip the cost record on the hit path (the original miss already
49
+ * recorded it).
50
+ *
51
+ * @packageDocumentation
52
+ */
53
+
54
+ import { wrapLanguageModel, type LanguageModel } from 'ai'
55
+ import type { LanguageModelV3, LanguageModelV3Middleware } from '@ai-sdk/provider'
56
+ import { cacheMiddleware, type CacheMiddlewareOptions } from './middleware/cache.js'
57
+ import { budgetMiddleware, type BudgetMiddlewareOptions } from './middleware/budget.js'
58
+ import { traceMiddleware, type TraceMiddlewareOptions } from './middleware/trace.js'
59
+
60
+ // ============================================================================
61
+ // Types
62
+ // ============================================================================
63
+
64
+ /**
65
+ * Options for {@link wrapForV3}. All three middleware sections are
66
+ * optional — pass only what you need.
67
+ */
68
+ export interface WrapForV3Options {
69
+ /** Cache config (see {@link CacheMiddlewareOptions}). */
70
+ cache?: CacheMiddlewareOptions
71
+ /** Budget tracking config (see {@link BudgetMiddlewareOptions}). */
72
+ budget?: BudgetMiddlewareOptions
73
+ /** Trace emission config (see {@link TraceMiddlewareOptions}). */
74
+ trace?: TraceMiddlewareOptions
75
+ }
76
+
77
+ // ============================================================================
78
+ // Composer
79
+ // ============================================================================
80
+
81
+ /**
82
+ * Wrap a {@link LanguageModel} with the v3-cascade middleware stack
83
+ * (cache → budget → trace, in install order).
84
+ *
85
+ * Returns the wrapped model with the same shape as the input; downstream
86
+ * `generateText` / `generateObject` / `streamText` calls treat it as a
87
+ * regular model.
88
+ *
89
+ * @see WrapForV3Options for partial-config behaviour
90
+ */
91
+ export function wrapForV3(model: LanguageModel, opts: WrapForV3Options = {}): LanguageModel {
92
+ const middleware: LanguageModelV3Middleware[] = []
93
+ if (opts.cache) middleware.push(cacheMiddleware(opts.cache))
94
+ if (opts.budget) middleware.push(budgetMiddleware(opts.budget))
95
+ if (opts.trace) middleware.push(traceMiddleware(opts.trace))
96
+ if (middleware.length === 0) return model
97
+ // wrapLanguageModel currently accepts LanguageModelV3 — at the AI SDK 6
98
+ // surface, `LanguageModel` is the wider union. The runtime is V3
99
+ // everywhere in the published providers; the cast is the same one the
100
+ // wrapLanguageModel cookbook uses.
101
+ return wrapLanguageModel({
102
+ model: model as LanguageModelV3,
103
+ middleware,
104
+ }) as LanguageModel
105
+ }