ai-functions 2.1.1 → 2.3.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 (286) hide show
  1. package/.turbo/turbo-build.log +1 -4
  2. package/CHANGELOG.md +68 -1
  3. package/README.md +397 -157
  4. package/dist/ai-promise.d.ts +50 -3
  5. package/dist/ai-promise.d.ts.map +1 -1
  6. package/dist/ai-promise.js +410 -51
  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 +54 -837
  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 +272 -0
  56. package/dist/budget.d.ts.map +1 -0
  57. package/dist/budget.js +513 -0
  58. package/dist/budget.js.map +1 -0
  59. package/dist/cache.d.ts +295 -0
  60. package/dist/cache.d.ts.map +1 -0
  61. package/dist/cache.js +433 -0
  62. package/dist/cache.js.map +1 -0
  63. package/dist/context.d.ts +42 -8
  64. package/dist/context.d.ts.map +1 -1
  65. package/dist/context.js +64 -62
  66. package/dist/context.js.map +1 -1
  67. package/dist/digital-objects-registry.d.ts +229 -0
  68. package/dist/digital-objects-registry.d.ts.map +1 -0
  69. package/dist/digital-objects-registry.js +617 -0
  70. package/dist/digital-objects-registry.js.map +1 -0
  71. package/dist/embeddings.d.ts +2 -2
  72. package/dist/embeddings.d.ts.map +1 -1
  73. package/dist/errors.d.ts +22 -0
  74. package/dist/errors.d.ts.map +1 -0
  75. package/dist/errors.js +35 -0
  76. package/dist/errors.js.map +1 -0
  77. package/dist/eval/runner.d.ts +10 -1
  78. package/dist/eval/runner.d.ts.map +1 -1
  79. package/dist/eval/runner.js +41 -35
  80. package/dist/eval/runner.js.map +1 -1
  81. package/dist/eval-log/in-memory.d.ts +34 -0
  82. package/dist/eval-log/in-memory.d.ts.map +1 -0
  83. package/dist/eval-log/in-memory.js +84 -0
  84. package/dist/eval-log/in-memory.js.map +1 -0
  85. package/dist/eval-log/index.d.ts +29 -0
  86. package/dist/eval-log/index.d.ts.map +1 -0
  87. package/dist/eval-log/index.js +39 -0
  88. package/dist/eval-log/index.js.map +1 -0
  89. package/dist/eval-log/types.d.ts +101 -0
  90. package/dist/eval-log/types.d.ts.map +1 -0
  91. package/dist/eval-log/types.js +16 -0
  92. package/dist/eval-log/types.js.map +1 -0
  93. package/dist/function-registry.d.ts +116 -0
  94. package/dist/function-registry.d.ts.map +1 -0
  95. package/dist/function-registry.js +546 -0
  96. package/dist/function-registry.js.map +1 -0
  97. package/dist/generate.d.ts +9 -3
  98. package/dist/generate.d.ts.map +1 -1
  99. package/dist/generate.js +18 -22
  100. package/dist/generate.js.map +1 -1
  101. package/dist/index.d.ts +35 -20
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +89 -42
  104. package/dist/index.js.map +1 -1
  105. package/dist/logger.d.ts +118 -0
  106. package/dist/logger.d.ts.map +1 -0
  107. package/dist/logger.js +187 -0
  108. package/dist/logger.js.map +1 -0
  109. package/dist/middleware/budget.d.ts +84 -0
  110. package/dist/middleware/budget.d.ts.map +1 -0
  111. package/dist/middleware/budget.js +110 -0
  112. package/dist/middleware/budget.js.map +1 -0
  113. package/dist/middleware/cache.d.ts +103 -0
  114. package/dist/middleware/cache.d.ts.map +1 -0
  115. package/dist/middleware/cache.js +228 -0
  116. package/dist/middleware/cache.js.map +1 -0
  117. package/dist/middleware/embed-cache.d.ts +99 -0
  118. package/dist/middleware/embed-cache.d.ts.map +1 -0
  119. package/dist/middleware/embed-cache.js +128 -0
  120. package/dist/middleware/embed-cache.js.map +1 -0
  121. package/dist/middleware/index.d.ts +11 -0
  122. package/dist/middleware/index.d.ts.map +1 -0
  123. package/dist/middleware/index.js +11 -0
  124. package/dist/middleware/index.js.map +1 -0
  125. package/dist/middleware/trace.d.ts +103 -0
  126. package/dist/middleware/trace.d.ts.map +1 -0
  127. package/dist/middleware/trace.js +176 -0
  128. package/dist/middleware/trace.js.map +1 -0
  129. package/dist/primitives.d.ts +120 -1
  130. package/dist/primitives.d.ts.map +1 -1
  131. package/dist/primitives.js +398 -26
  132. package/dist/primitives.js.map +1 -1
  133. package/dist/retry.d.ts +368 -0
  134. package/dist/retry.d.ts.map +1 -0
  135. package/dist/retry.js +646 -0
  136. package/dist/retry.js.map +1 -0
  137. package/dist/schema.d.ts.map +1 -1
  138. package/dist/schema.js +2 -10
  139. package/dist/schema.js.map +1 -1
  140. package/dist/telemetry.d.ts +128 -0
  141. package/dist/telemetry.d.ts.map +1 -0
  142. package/dist/telemetry.js +285 -0
  143. package/dist/telemetry.js.map +1 -0
  144. package/dist/template.d.ts.map +1 -1
  145. package/dist/template.js +6 -1
  146. package/dist/template.js.map +1 -1
  147. package/dist/tool-orchestration.d.ts +453 -0
  148. package/dist/tool-orchestration.d.ts.map +1 -0
  149. package/dist/tool-orchestration.js +763 -0
  150. package/dist/tool-orchestration.js.map +1 -0
  151. package/dist/type-guards.d.ts +28 -0
  152. package/dist/type-guards.d.ts.map +1 -0
  153. package/dist/type-guards.js +29 -0
  154. package/dist/type-guards.js.map +1 -0
  155. package/dist/types.d.ts +135 -17
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/types.js +36 -1
  158. package/dist/types.js.map +1 -1
  159. package/dist/wrap-for-v3.d.ts +80 -0
  160. package/dist/wrap-for-v3.d.ts.map +1 -0
  161. package/dist/wrap-for-v3.js +89 -0
  162. package/dist/wrap-for-v3.js.map +1 -0
  163. package/examples/00-quickstart.ts +232 -0
  164. package/examples/01-rag-chatbot.ts +212 -0
  165. package/examples/02-multi-agent-research.ts +290 -0
  166. package/examples/03-email-classification.ts +379 -0
  167. package/examples/04-content-moderation.ts +400 -0
  168. package/examples/05-document-extraction.ts +455 -0
  169. package/examples/06-streaming-chat-nextjs.ts +437 -0
  170. package/examples/07-cloudflare-worker.ts +483 -0
  171. package/examples/08-batch-processing.ts +491 -0
  172. package/examples/09-budget-constrained.ts +527 -0
  173. package/examples/10-tool-orchestration.ts +565 -0
  174. package/examples/11-retry-resilience.ts +403 -0
  175. package/examples/12-caching-strategies.ts +422 -0
  176. package/examples/README.md +145 -0
  177. package/package.json +10 -6
  178. package/src/ai-promise.ts +528 -99
  179. package/src/ai-schemas.ts +122 -0
  180. package/src/ai.ts +69 -1153
  181. package/src/batch/anthropic.ts +96 -161
  182. package/src/batch/bedrock.ts +203 -454
  183. package/src/batch/cloudflare.ts +99 -282
  184. package/src/batch/google.ts +91 -297
  185. package/src/batch/index.ts +4 -1
  186. package/src/batch/memory.ts +15 -10
  187. package/src/batch/openai.ts +65 -193
  188. package/src/batch/provider.ts +336 -0
  189. package/src/batch-map.ts +29 -24
  190. package/src/batch-queue.ts +200 -11
  191. package/src/budget.ts +740 -0
  192. package/src/cache.ts +681 -0
  193. package/src/context.ts +122 -76
  194. package/src/digital-objects-registry.ts +750 -0
  195. package/src/errors.ts +37 -0
  196. package/src/eval/runner.ts +63 -38
  197. package/src/eval-log/in-memory.ts +90 -0
  198. package/src/eval-log/index.ts +46 -0
  199. package/src/eval-log/types.ts +110 -0
  200. package/src/function-registry.ts +671 -0
  201. package/src/generate.ts +33 -33
  202. package/src/index.ts +325 -49
  203. package/src/logger.ts +232 -0
  204. package/src/middleware/budget.ts +171 -0
  205. package/src/middleware/cache.ts +299 -0
  206. package/src/middleware/embed-cache.ts +195 -0
  207. package/src/middleware/index.ts +23 -0
  208. package/src/middleware/trace.ts +248 -0
  209. package/src/primitives.ts +589 -62
  210. package/src/retry.ts +902 -0
  211. package/src/schema.ts +8 -17
  212. package/src/telemetry.ts +403 -0
  213. package/src/template.ts +8 -4
  214. package/src/tool-orchestration.ts +1173 -0
  215. package/src/type-guards.ts +31 -0
  216. package/src/types.ts +164 -25
  217. package/src/wrap-for-v3.ts +105 -0
  218. package/test/ai-promise.test.ts +1080 -0
  219. package/test/ai-proxy.test.ts +1 -1
  220. package/test/backward-compat.test.ts +147 -0
  221. package/test/batch-autosubmit-errors.test.ts +610 -0
  222. package/test/batch-blog-posts.test.ts +87 -129
  223. package/test/budget-tracking.test.ts +800 -0
  224. package/test/cache.test.ts +712 -0
  225. package/test/context-isolation.test.ts +687 -0
  226. package/test/core-functions.test.ts +183 -579
  227. package/test/decide.test.ts +154 -322
  228. package/test/define.test.ts +211 -8
  229. package/test/digital-objects-registry.test.ts +760 -0
  230. package/test/embedding-cache-middleware.test.ts +140 -0
  231. package/test/evals/deterministic.eval.test.ts +376 -0
  232. package/test/generate-core.test.ts +140 -229
  233. package/test/implicit-batch.test.ts +22 -65
  234. package/test/json-parse-error-handling.test.ts +463 -0
  235. package/test/retry-policy-integration.test.ts +117 -0
  236. package/test/retry.test.ts +1016 -0
  237. package/test/schema.test.ts +55 -19
  238. package/test/streaming.test.ts +316 -0
  239. package/test/template.test.ts +1164 -0
  240. package/test/tool-orchestration.test.ts +1040 -0
  241. package/test/wrap-for-v3.test.ts +612 -0
  242. package/vitest.config.js +6 -0
  243. package/vitest.config.ts +20 -0
  244. package/dist/rpc/auth.d.ts +0 -69
  245. package/dist/rpc/auth.d.ts.map +0 -1
  246. package/dist/rpc/auth.js +0 -136
  247. package/dist/rpc/auth.js.map +0 -1
  248. package/dist/rpc/client.d.ts +0 -62
  249. package/dist/rpc/client.d.ts.map +0 -1
  250. package/dist/rpc/client.js +0 -103
  251. package/dist/rpc/client.js.map +0 -1
  252. package/dist/rpc/deferred.d.ts +0 -60
  253. package/dist/rpc/deferred.d.ts.map +0 -1
  254. package/dist/rpc/deferred.js +0 -96
  255. package/dist/rpc/deferred.js.map +0 -1
  256. package/dist/rpc/index.d.ts +0 -22
  257. package/dist/rpc/index.d.ts.map +0 -1
  258. package/dist/rpc/index.js +0 -38
  259. package/dist/rpc/index.js.map +0 -1
  260. package/dist/rpc/local.d.ts +0 -42
  261. package/dist/rpc/local.d.ts.map +0 -1
  262. package/dist/rpc/local.js +0 -50
  263. package/dist/rpc/local.js.map +0 -1
  264. package/dist/rpc/server.d.ts +0 -165
  265. package/dist/rpc/server.d.ts.map +0 -1
  266. package/dist/rpc/server.js +0 -405
  267. package/dist/rpc/server.js.map +0 -1
  268. package/dist/rpc/session.d.ts +0 -32
  269. package/dist/rpc/session.d.ts.map +0 -1
  270. package/dist/rpc/session.js +0 -43
  271. package/dist/rpc/session.js.map +0 -1
  272. package/dist/rpc/transport.d.ts +0 -306
  273. package/dist/rpc/transport.d.ts.map +0 -1
  274. package/dist/rpc/transport.js +0 -731
  275. package/dist/rpc/transport.js.map +0 -1
  276. package/src/batch/anthropic.js +0 -256
  277. package/src/batch/bedrock.js +0 -584
  278. package/src/batch/cloudflare.js +0 -287
  279. package/src/batch/google.js +0 -359
  280. package/src/batch/index.js +0 -30
  281. package/src/batch/memory.js +0 -187
  282. package/src/batch/openai.js +0 -402
  283. package/src/eval/index.js +0 -7
  284. package/src/eval/models.js +0 -119
  285. package/src/eval/runner.js +0 -147
  286. package/test/schema.test.js +0 -96
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Type Guards for AI Functions
3
+ *
4
+ * Shared type guard utilities used across AI packages.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import type { ZodTypeAny } from 'zod'
10
+
11
+ /**
12
+ * Check if value is a Zod schema
13
+ *
14
+ * Uses duck-typing to detect Zod schemas by checking for the
15
+ * `_def` property (internal Zod schema definition) and `parse` method.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { isZodSchema } from 'ai-functions'
20
+ * import { z } from 'zod'
21
+ *
22
+ * const schema = z.object({ name: z.string() })
23
+ * if (isZodSchema(schema)) {
24
+ * // TypeScript knows schema is ZodTypeAny
25
+ * schema.parse({ name: 'test' })
26
+ * }
27
+ * ```
28
+ */
29
+ export function isZodSchema(value: unknown): value is ZodTypeAny {
30
+ return value !== null && typeof value === 'object' && '_def' in value && 'parse' in value
31
+ }
package/src/types.ts CHANGED
@@ -2,16 +2,106 @@
2
2
  * Core types for AI functions
3
3
  */
4
4
 
5
+ // ============================================================================
6
+ // Human Function Pending Types
7
+ // ============================================================================
8
+
9
+ /**
10
+ * Symbol used to identify pending human function results
11
+ */
12
+ export const PENDING_HUMAN_RESULT_SYMBOL = Symbol.for('HumanFunctionPending')
13
+
14
+ /**
15
+ * Human interaction channels
16
+ *
17
+ * - chat: Real-time messaging (WebSocket, in-app)
18
+ * - email: Async email communication
19
+ * - phone: Voice calls
20
+ * - sms: SMS text messages
21
+ * - workspace: Team collaboration platforms (Slack, Teams, Discord)
22
+ * - web: Web-based interface (browser, web app)
23
+ */
24
+ export type HumanChannel = 'chat' | 'email' | 'phone' | 'sms' | 'workspace' | 'web'
25
+
26
+ /**
27
+ * Pending human function result returned when human input is not yet available.
28
+ *
29
+ * This is returned by human functions that need actual human input but are running
30
+ * in a placeholder mode (e.g., during testing or when channel integrations are not configured).
31
+ *
32
+ * Use `isPendingHumanResult()` to check if a result is pending before using it.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const result = await approveRefund({ amount: 500, reason: 'Duplicate charge' })
37
+ *
38
+ * if (isPendingHumanResult(result)) {
39
+ * console.log('Waiting for human approval via:', result.channel)
40
+ * // Handle pending state - queue for later, show UI, etc.
41
+ * } else {
42
+ * // result is the actual TOutput type
43
+ * console.log('Approved:', result.approved)
44
+ * }
45
+ * ```
46
+ */
47
+ export interface HumanFunctionPending<TExpected = unknown> {
48
+ /** Symbol marker for type identification */
49
+ readonly [PENDING_HUMAN_RESULT_SYMBOL]: true
50
+ /** Indicates this is a pending placeholder, not actual human response */
51
+ readonly _pending: true
52
+ /** The channel where human input was requested */
53
+ readonly channel: HumanChannel
54
+ /** Generated UI/content artifacts for the channel */
55
+ readonly artifacts: unknown
56
+ /** The expected response type schema */
57
+ readonly expectedResponseType: TExpected
58
+ }
59
+
60
+ /**
61
+ * Type guard to check if a result is a pending human function result.
62
+ *
63
+ * Use this to safely handle cases where human input is not yet available.
64
+ *
65
+ * @param value - The value to check
66
+ * @returns True if the value is a HumanFunctionPending object
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const result = await reviewDocument({ docId: '123' })
71
+ *
72
+ * if (isPendingHumanResult(result)) {
73
+ * // result is HumanFunctionPending - human input needed
74
+ * console.warn('Human review pending:', result.channel)
75
+ * return { status: 'pending', channel: result.channel }
76
+ * }
77
+ *
78
+ * // result is ReviewResult - actual human response
79
+ * return { status: 'reviewed', approved: result.approved }
80
+ * ```
81
+ */
82
+ export function isPendingHumanResult<T>(
83
+ value: T | HumanFunctionPending
84
+ ): value is HumanFunctionPending {
85
+ return (
86
+ value !== null &&
87
+ typeof value === 'object' &&
88
+ '_pending' in value &&
89
+ value._pending === true &&
90
+ PENDING_HUMAN_RESULT_SYMBOL in value
91
+ )
92
+ }
93
+
94
+ // ============================================================================
95
+ // AI Function Types
96
+ // ============================================================================
97
+
5
98
  /**
6
99
  * A function definition that can be called by AI
7
100
  *
8
101
  * @typeParam TOutput - The return type of the function handler
9
102
  * @typeParam TInput - The input type accepted by the function handler
10
103
  */
11
- export interface AIFunctionDefinition<
12
- TOutput = unknown,
13
- TInput = unknown
14
- > {
104
+ export interface AIFunctionDefinition<TOutput = unknown, TInput = unknown> {
15
105
  /** Unique name for the function */
16
106
  name: string
17
107
  /** Human-readable description for the AI */
@@ -162,9 +252,11 @@ export interface WriteOptions {
162
252
  /**
163
253
  * Type for functions that support both regular calls and tagged template literals
164
254
  */
165
- export type TemplateFunction<TArgs extends unknown[], TReturn> =
166
- & ((prompt: string, ...args: TArgs) => TReturn)
167
- & ((strings: TemplateStringsArray, ...values: unknown[]) => TReturn)
255
+ export type TemplateFunction<TArgs extends unknown[], TReturn> = ((
256
+ prompt: string,
257
+ ...args: TArgs
258
+ ) => TReturn) &
259
+ ((strings: TemplateStringsArray, ...values: unknown[]) => TReturn)
168
260
 
169
261
  /**
170
262
  * A single item in a list
@@ -210,18 +302,6 @@ export type CodeLanguage = 'typescript' | 'javascript' | 'python' | 'go' | 'rust
210
302
  */
211
303
  export type GenerativeOutputType = 'string' | 'object' | 'image' | 'video'
212
304
 
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
305
  /**
226
306
  * Legacy channel type for backwards compatibility
227
307
  * @deprecated Use HumanChannel instead
@@ -273,12 +353,24 @@ export interface BaseFunctionDefinition<TOutput = unknown, TInput = unknown> {
273
353
  }
274
354
 
275
355
  /**
276
- * Code function - generates actual executable code
356
+ * Code function - a **deterministic** handler.
357
+ *
358
+ * `Code` is the deterministic kind: a fetch/transform/rule handler that runs
359
+ * the **same logic every time** with no model in the execution path. When
360
+ * called, it invokes the supplied {@link CodeFunctionDefinition.handler}
361
+ * (or evaluates the inline {@link CodeFunctionDefinition.code} body) and
362
+ * returns the result directly — no LLM is consulted at call time.
363
+ *
364
+ * This is the contract consumers bind to (e.g. ADR-0033's
365
+ * "Code = deterministic"). If you want a model to *author* code, that is a
366
+ * generation task: use {@link generateCode} / the `generate('code', …)`
367
+ * primitive, or define a `Generative` function whose output is source text.
368
+ * See the migration note in the package README.
277
369
  *
278
- * When called, this generates:
279
- * - Implementation code with JSDoc comments
280
- * - Vitest test cases
281
- * - Example usage scripts
370
+ * Exactly one of `handler` or `code` should be supplied. `handler` is the
371
+ * canonical form (a native function reference); `code` is an inline source
372
+ * body, deterministically compiled by the consumer's runtime — never sent to
373
+ * a model.
282
374
  *
283
375
  * @example
284
376
  * ```ts
@@ -290,7 +382,7 @@ export interface BaseFunctionDefinition<TOutput = unknown, TInput = unknown> {
290
382
  * rate: 'Tax rate as decimal (number)',
291
383
  * },
292
384
  * returnType: 'The calculated tax amount (number)',
293
- * language: 'typescript',
385
+ * handler: ({ amount, rate }) => amount * rate,
294
386
  * })
295
387
  * ```
296
388
  *
@@ -300,6 +392,51 @@ export interface BaseFunctionDefinition<TOutput = unknown, TInput = unknown> {
300
392
  export interface CodeFunctionDefinition<TOutput = unknown, TInput = unknown>
301
393
  extends BaseFunctionDefinition<TOutput, TInput> {
302
394
  type: 'code'
395
+ /**
396
+ * The deterministic handler invoked on every call. Receives the parsed
397
+ * `args` and returns (or resolves to) the result. No LLM is involved.
398
+ *
399
+ * Either `handler` or {@link CodeFunctionDefinition.code} must be provided;
400
+ * `handler` takes precedence when both are present.
401
+ */
402
+ handler?: (input: TInput) => TOutput | Promise<TOutput>
403
+ /**
404
+ * Inline source body for the handler, as a string. Deterministically
405
+ * compiled by the consumer's runtime (it is **not** generated by a model).
406
+ * Used when a handler cannot be passed by reference (e.g. a definition
407
+ * loaded from storage). The body receives the `args` in scope and should
408
+ * `return` the result.
409
+ *
410
+ * Either `code` or {@link CodeFunctionDefinition.handler} must be provided.
411
+ */
412
+ code?: string
413
+ /** Target programming language of `code` (default: `'typescript'`). Metadata only. */
414
+ language?: CodeLanguage
415
+ /** Optional human-readable note about what the handler does. Metadata only. */
416
+ instructions?: string
417
+ }
418
+
419
+ /**
420
+ * Definition for a code-**authoring** request — the explicit, opt-in path for
421
+ * having a model *write* code. This is the behavior `type: 'code'` used to
422
+ * have implicitly; it has been split out so that `Code` can mean
423
+ * "deterministic handler" without a silent change of meaning.
424
+ *
425
+ * This is **not** part of the {@link FunctionDefinition} union and never
426
+ * executes deterministically — calling it consults a model. Drive it via
427
+ * {@link generateCode}.
428
+ *
429
+ * @typeParam TInput - The arguments schema describing the code to author
430
+ */
431
+ export interface CodeGenerationDefinition<TInput = unknown> {
432
+ /** Name of the function/query to author */
433
+ name: string
434
+ /** Human-readable description of what the code should do */
435
+ description?: string
436
+ /** Arguments/spec schema describing the code to generate */
437
+ args: TInput
438
+ /** Return type schema the authored code should produce (optional) */
439
+ returnType?: unknown
303
440
  /** Target programming language */
304
441
  language?: CodeLanguage
305
442
  /** Additional context or requirements for code generation */
@@ -308,6 +445,8 @@ export interface CodeFunctionDefinition<TOutput = unknown, TInput = unknown>
308
445
  includeTests?: boolean
309
446
  /** Whether to include example usage (default: true) */
310
447
  includeExamples?: boolean
448
+ /** Model to use for authoring (defaults to 'sonnet') */
449
+ model?: string
311
450
  }
312
451
 
313
452
  /**
@@ -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
+ }