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
package/dist/ai.js CHANGED
@@ -1,447 +1,30 @@
1
1
  /**
2
2
  * AI() and ai() - Core AI function constructors
3
3
  *
4
- * These provide the main entry points for AI-powered functions,
5
- * with full RPC promise pipelining support via rpc.do.
6
- */
7
- // TODO: Re-enable RPC imports when rpc.do is published
8
- // import { RPC, http, ws, type RPCProxy, type RPCPromise as RpcPromiseType } from 'rpc.do'
9
- /**
10
- * Base class for RPC service targets
11
- * This is a placeholder for services that want to expose methods over RPC
12
- */
13
- export class RpcTarget {
14
- }
15
- import { generateObject } from './generate.js';
16
- import { schema as convertSchema } from './schema.js';
17
- export function AI(schemasOrOptions, defaultOptions) {
18
- // Check if this is RPC client mode
19
- if (isAIClientOptions(schemasOrOptions)) {
20
- // TODO: Re-enable RPC client when rpc.do is published
21
- // const { model, temperature, maxTokens, functions, wsUrl, httpUrl, token } = schemasOrOptions
22
- //
23
- // // Create transport based on provided URLs
24
- // let transport
25
- // if (wsUrl) {
26
- // transport = ws(wsUrl, token ? () => token : undefined)
27
- // } else if (httpUrl) {
28
- // transport = http(httpUrl, token ? () => token : undefined)
29
- // } else {
30
- // throw new Error('AI client requires either wsUrl or httpUrl')
31
- // }
32
- //
33
- // // Create RPC client
34
- // const rpcClient = RPC<AIClient>(transport)
35
- //
36
- // // Create a proxy that handles both defined methods and dynamic function calls
37
- // return new Proxy(rpcClient, {
38
- // get(target, prop: string) {
39
- // // Return existing methods
40
- // if (prop in target) {
41
- // return (target as unknown as Record<string, unknown>)[prop]
42
- // }
43
- //
44
- // // Handle dynamic function calls (ai.functionName())
45
- // return (...args: unknown[]) => {
46
- // const client = target as unknown as AIClient
47
- // return client.do(prop, args.length === 1 ? args[0] : args)
48
- // }
49
- // }
50
- // }) as AIClient & Record<string, (...args: unknown[]) => Promise<unknown>>
51
- throw new Error('RPC client mode requires rpc.do package (not yet published). Use schema-based mode instead.');
52
- }
53
- // Schema functions mode - create a function for each schema
54
- return createSchemaFunctions(schemasOrOptions, defaultOptions);
55
- }
56
- /**
57
- * Check if options are AI client options vs schemas
58
- */
59
- function isAIClientOptions(value) {
60
- if (typeof value !== 'object' || value === null)
61
- return false;
62
- const obj = value;
63
- return 'wsUrl' in obj || 'httpUrl' in obj || 'functions' in obj;
64
- }
65
- /**
66
- * Create schema-based functions from a map of schemas
67
- */
68
- function createSchemaFunctions(schemas, defaultOptions = {}) {
69
- const functions = {};
70
- for (const [name, schema] of Object.entries(schemas)) {
71
- functions[name] = async (prompt, options) => {
72
- const mergedOptions = { ...defaultOptions, ...options };
73
- const { model = 'sonnet', system, ...rest } = mergedOptions;
74
- // Build prompt from schema descriptions if none provided
75
- const schemaPrompt = prompt || buildPromptFromSchema(schema);
76
- const result = await generateObject({
77
- model,
78
- schema,
79
- prompt: schemaPrompt,
80
- system,
81
- ...rest,
82
- });
83
- return result.object;
84
- };
85
- }
86
- return functions;
87
- }
88
- /**
89
- * Build a prompt by extracting descriptions from the schema
90
- */
91
- function buildPromptFromSchema(schema, path = '') {
92
- if (typeof schema === 'string') {
93
- return schema;
94
- }
95
- if (Array.isArray(schema)) {
96
- return schema[0] || 'Generate items';
97
- }
98
- if (typeof schema === 'object' && schema !== null) {
99
- const descriptions = [];
100
- for (const [key, value] of Object.entries(schema)) {
101
- const subPrompt = buildPromptFromSchema(value, path ? `${path}.${key}` : key);
102
- if (subPrompt) {
103
- descriptions.push(`${key}: ${subPrompt}`);
104
- }
105
- }
106
- return descriptions.length > 0 ? `Generate the following:\n${descriptions.join('\n')}` : '';
107
- }
108
- return '';
109
- }
110
- /**
111
- * Create a defined function from a function definition
112
- */
113
- function createDefinedFunction(definition) {
114
- const call = async (args) => {
115
- switch (definition.type) {
116
- case 'code':
117
- return executeCodeFunction(definition, args);
118
- case 'generative':
119
- return executeGenerativeFunction(definition, args);
120
- case 'agentic':
121
- return executeAgenticFunction(definition, args);
122
- case 'human':
123
- return executeHumanFunction(definition, args);
124
- default:
125
- throw new Error(`Unknown function type: ${definition.type}`);
126
- }
127
- };
128
- const asTool = () => {
129
- return {
130
- name: definition.name,
131
- description: definition.description || `Execute ${definition.name}`,
132
- parameters: convertArgsToJSONSchema(definition.args),
133
- handler: call,
134
- };
135
- };
136
- return { definition, call, asTool };
137
- }
138
- /**
139
- * Convert args schema to JSON Schema
140
- */
141
- function convertArgsToJSONSchema(args) {
142
- // If it's already a JSON schema-like object
143
- if (typeof args === 'object' && args !== null && 'type' in args) {
144
- return args;
145
- }
146
- // Convert SimpleSchema to JSON Schema
147
- const properties = {};
148
- const required = [];
149
- if (typeof args === 'object' && args !== null) {
150
- for (const [key, value] of Object.entries(args)) {
151
- required.push(key); // All properties required for cross-provider compatibility
152
- properties[key] = convertValueToJSONSchema(value);
153
- }
154
- }
155
- return {
156
- type: 'object',
157
- properties,
158
- required,
159
- additionalProperties: false, // Required for OpenAI compatibility
160
- };
161
- }
162
- /**
163
- * Convert a single value to JSON Schema
164
- */
165
- function convertValueToJSONSchema(value) {
166
- if (typeof value === 'string') {
167
- // Check for type hints: 'description (number)', 'description (boolean)', etc.
168
- const typeMatch = value.match(/^(.+?)\s*\((number|boolean|integer|date)\)$/i);
169
- if (typeMatch) {
170
- const description = typeMatch[1];
171
- const type = typeMatch[2];
172
- switch (type.toLowerCase()) {
173
- case 'number':
174
- return { type: 'number', description: description.trim() };
175
- case 'integer':
176
- return { type: 'integer', description: description.trim() };
177
- case 'boolean':
178
- return { type: 'boolean', description: description.trim() };
179
- case 'date':
180
- return { type: 'string', format: 'date-time', description: description.trim() };
181
- }
182
- }
183
- // Check for enum: 'option1 | option2 | option3'
184
- if (value.includes(' | ')) {
185
- const options = value.split(' | ').map(s => s.trim());
186
- return { type: 'string', enum: options };
187
- }
188
- return { type: 'string', description: value };
189
- }
190
- if (Array.isArray(value) && value.length === 1) {
191
- const [desc] = value;
192
- if (typeof desc === 'string') {
193
- return { type: 'array', items: { type: 'string' }, description: desc };
194
- }
195
- if (typeof desc === 'number') {
196
- return { type: 'array', items: { type: 'number' } };
197
- }
198
- return { type: 'array', items: convertValueToJSONSchema(desc) };
199
- }
200
- if (typeof value === 'object' && value !== null) {
201
- return convertArgsToJSONSchema(value);
202
- }
203
- return { type: 'string' };
204
- }
205
- /**
206
- * Fill template with values
207
- */
208
- function fillTemplate(template, args) {
209
- return template.replace(/\{\{(\w+)\}\}/g, (_, key) => String(args[key] ?? ''));
210
- }
211
- /**
212
- * Execute a code function - generates code with tests and examples
213
- */
214
- async function executeCodeFunction(definition, args) {
215
- const { name, description, language = 'typescript', instructions, includeTests = true, includeExamples = true } = definition;
216
- const argsDescription = JSON.stringify(args, null, 2);
217
- const result = await generateObject({
218
- model: 'sonnet',
219
- schema: {
220
- code: 'The complete implementation code with JSDoc comments',
221
- tests: includeTests ? 'Vitest test code for the implementation' : undefined,
222
- examples: includeExamples ? 'Example usage code' : undefined,
223
- documentation: 'JSDoc or equivalent documentation string',
224
- },
225
- system: `You are an expert ${language} developer. Generate clean, well-documented, production-ready code.`,
226
- prompt: `Generate a ${language} function with the following specification:
227
-
228
- Name: ${name}
229
- Description: ${description || 'No description provided'}
230
- Arguments: ${argsDescription}
231
- Return Type: ${JSON.stringify(definition.returnType)}
232
-
233
- ${instructions ? `Additional Instructions: ${instructions}` : ''}
234
-
235
- Requirements:
236
- - Include comprehensive JSDoc comments
237
- - Follow best practices for ${language}
238
- - Handle edge cases appropriately
239
- ${includeTests ? '- Include vitest tests that cover main functionality and edge cases' : ''}
240
- ${includeExamples ? '- Include example usage showing how to call the function' : ''}`,
241
- });
242
- const obj = result.object;
243
- return {
244
- code: obj.code,
245
- tests: obj.tests,
246
- examples: obj.examples,
247
- language,
248
- documentation: obj.documentation,
249
- };
250
- }
251
- /**
252
- * Execute a generative function - uses AI to generate content
253
- */
254
- async function executeGenerativeFunction(definition, args) {
255
- const { output, system, promptTemplate, model = 'sonnet', temperature, returnType } = definition;
256
- const prompt = promptTemplate
257
- ? fillTemplate(promptTemplate, args)
258
- : JSON.stringify(args);
259
- switch (output) {
260
- case 'string': {
261
- const result = await generateObject({
262
- model,
263
- schema: { text: 'The generated text response' },
264
- system,
265
- prompt,
266
- temperature,
267
- });
268
- return result.object.text;
269
- }
270
- case 'object': {
271
- const objectSchema = returnType || { result: 'The generated result' };
272
- const result = await generateObject({
273
- model,
274
- schema: objectSchema,
275
- system,
276
- prompt,
277
- temperature,
278
- });
279
- return result.object;
280
- }
281
- case 'image': {
282
- const client = getDefaultAIClient();
283
- return client.image(prompt);
284
- }
285
- case 'video': {
286
- const client = getDefaultAIClient();
287
- return client.video(prompt);
288
- }
289
- default:
290
- throw new Error(`Unknown output type: ${output}`);
291
- }
292
- }
293
- /**
294
- * Execute an agentic function - runs in a loop with tools
295
- */
296
- async function executeAgenticFunction(definition, args) {
297
- const { instructions, promptTemplate, tools = [], maxIterations = 10, model = 'sonnet', returnType } = definition;
298
- const prompt = promptTemplate
299
- ? fillTemplate(promptTemplate, args)
300
- : JSON.stringify(args);
301
- // Build system prompt with tool descriptions
302
- const toolDescriptions = tools.map(t => `- ${t.name}: ${t.description}`).join('\n');
303
- const systemPrompt = `${instructions}
304
-
305
- Available tools:
306
- ${toolDescriptions || 'No tools available'}
307
-
308
- Work step by step to accomplish the task. When you have completed the task, provide your final result.`;
309
- let iteration = 0;
310
- const toolResults = [];
311
- // Simple agent loop
312
- while (iteration < maxIterations) {
313
- iteration++;
314
- const result = await generateObject({
315
- model,
316
- schema: {
317
- thinking: 'Your step-by-step reasoning',
318
- toolCall: {
319
- name: 'Tool to call (or "done" if finished)',
320
- arguments: 'Arguments for the tool as JSON string',
321
- },
322
- finalResult: returnType || 'The final result if done',
323
- },
324
- system: systemPrompt,
325
- prompt: `Task: ${prompt}
326
-
327
- Previous tool results:
328
- ${toolResults.map((r, i) => `Step ${i + 1}: ${JSON.stringify(r)}`).join('\n') || 'None yet'}
329
-
330
- What is your next step?`,
331
- });
332
- const response = result.object;
333
- if (response.toolCall.name === 'done' || response.finalResult) {
334
- return response.finalResult;
335
- }
336
- // Execute tool call
337
- const tool = tools.find(t => t.name === response.toolCall.name);
338
- if (tool) {
339
- const toolArgs = JSON.parse(response.toolCall.arguments || '{}');
340
- const toolResult = await tool.handler(toolArgs);
341
- toolResults.push({ tool: response.toolCall.name, result: toolResult });
342
- }
343
- else {
344
- toolResults.push({ error: `Tool not found: ${response.toolCall.name}` });
345
- }
346
- }
347
- throw new Error(`Agent exceeded maximum iterations (${maxIterations})`);
348
- }
349
- /**
350
- * Execute a human function - generates UI and waits for human input
351
- *
352
- * **Note: This function currently returns placeholder/mock data.**
353
- *
354
- * In a complete implementation, this function would:
355
- * 1. Generate channel-specific UI (Slack blocks, email templates, web forms, etc.)
356
- * 2. Send the generated UI to the appropriate channel
357
- * 3. Wait for human response with optional timeout
358
- * 4. Validate and return the human's response
359
- *
360
- * The current implementation generates the UI artifacts but returns a pending
361
- * placeholder instead of actually sending to the channel and waiting for response.
362
- * This allows testing the UI generation without requiring actual channel integrations.
363
- *
364
- * @param definition - The human function definition with channel and instructions
365
- * @param args - Arguments to pass to the function
366
- * @returns A placeholder result with `_pending: true` and generated artifacts
4
+ * This module is a re-export layer that delegates to focused modules:
5
+ * - ai-schemas.ts - Schema-based AI function generation
6
+ * - function-registry.ts - Function definition and registry
7
+ * - primitives.ts - Auto-define proxy functionality (`define`, `createSmartAI`, `aiProxy`)
367
8
  *
368
- * @example
369
- * ```ts
370
- * // The result will be a placeholder, not an actual human response:
371
- * // {
372
- * // _pending: true,
373
- * // channel: 'workspace',
374
- * // artifacts: { ... generated UI ... },
375
- * // expectedResponseType: { approved: boolean }
376
- * // }
377
- * ```
9
+ * All exports are maintained for backward compatibility.
378
10
  */
379
- async function executeHumanFunction(definition, args) {
380
- const { channel, instructions, promptTemplate, returnType } = definition;
381
- const prompt = promptTemplate
382
- ? fillTemplate(promptTemplate, args)
383
- : JSON.stringify(args);
384
- // Generate channel-specific UI
385
- const uiSchema = {
386
- // New HumanChannel types
387
- chat: {
388
- message: 'Chat message to send',
389
- options: ['Response options if applicable'],
390
- },
391
- email: {
392
- subject: 'Email subject',
393
- html: 'Email HTML body',
394
- text: 'Plain text fallback',
395
- },
396
- phone: {
397
- script: 'Phone call script',
398
- keyPoints: ['Key points to cover'],
399
- },
400
- sms: {
401
- text: 'SMS message text (max 160 chars)',
402
- },
403
- workspace: {
404
- blocks: ['Workspace/Slack BlockKit blocks as JSON array'],
405
- text: 'Plain text fallback',
406
- },
407
- web: {
408
- component: 'React component code for the form',
409
- schema: 'JSON schema for the form fields',
410
- },
411
- // Legacy fallback
412
- custom: {
413
- data: 'Structured data for custom implementation',
414
- instructions: 'Instructions for the human',
415
- },
416
- };
417
- const result = await generateObject({
418
- model: 'sonnet',
419
- schema: uiSchema[channel] ?? uiSchema.custom,
420
- system: `Generate ${channel} UI/content for a human-in-the-loop task.`,
421
- prompt: `Task: ${instructions}
422
-
423
- Input data:
424
- ${prompt}
425
-
426
- Expected response format:
427
- ${JSON.stringify(returnType)}
428
-
429
- Generate the appropriate ${channel} UI/content to collect this response from a human.`,
430
- });
431
- // NOTE: This is a placeholder implementation.
432
- // In a real implementation, this would:
433
- // 1. Send the generated UI to the appropriate channel (Slack, email, etc.)
434
- // 2. Wait for human response with optional timeout
435
- // 3. Return the validated response
436
- //
437
- // Current behavior: Returns generated artifacts as a pending placeholder
438
- return {
439
- _pending: true,
440
- channel,
441
- artifacts: result.object,
442
- expectedResponseType: returnType,
443
- };
444
- }
11
+ // ============================================================================
12
+ // Re-export from ai-schemas.ts - Schema-based AI functions
13
+ // ============================================================================
14
+ export { createSchemaFunctions, } from './ai-schemas.js';
15
+ // ============================================================================
16
+ // Re-export from function-registry.ts - Function definition and registry
17
+ // ============================================================================
18
+ export { defineFunction, createDefinedFunction, createFunctionRegistry, functions, resetGlobalRegistry, convertArgsToJSONSchema, fillTemplate, generateCode, } from './function-registry.js';
19
+ // ============================================================================
20
+ // Re-export from primitives.ts - Auto-define proxy functionality
21
+ // (formerly in ai-proxy.ts; inlined to give property-access tracking a single
22
+ // owner in ai-promise.ts)
23
+ // ============================================================================
24
+ export { define, createSmartAI, aiProxy as ai } from './primitives.js';
25
+ // ============================================================================
26
+ // Local exports - withTemplate utility
27
+ // ============================================================================
445
28
  /**
446
29
  * Helper to create a function that supports both regular calls and tagged template literals
447
30
  * @example
@@ -456,417 +39,51 @@ export function withTemplate(fn) {
456
39
  const strings = promptOrStrings;
457
40
  const values = args;
458
41
  const prompt = strings.reduce((acc, str, i) => acc + str + (values[i] ?? ''), '');
42
+ // Cast required: When called as a tagged template, additional args aren't provided.
43
+ // TArgs represents optional parameters that default to empty. TypeScript can't express
44
+ // that TArgs can be satisfied by an empty array when all elements are optional.
459
45
  return fn(prompt, ...[]);
460
46
  }
461
47
  // Regular function call
462
48
  return fn(promptOrStrings, ...args);
463
49
  };
464
50
  }
465
- // Default client management
466
- let defaultClient = null;
51
+ import { createSchemaFunctions } from './ai-schemas.js';
467
52
  /**
468
- * Configure the default AI client
469
- */
470
- export function configureAI(options) {
471
- defaultClient = AI(options);
472
- }
473
- /**
474
- * Get the default AI client, throwing if not configured
475
- */
476
- function getDefaultAIClient() {
477
- if (!defaultClient) {
478
- // Try to auto-configure from environment
479
- const wsUrl = typeof process !== 'undefined' ? process.env?.AI_WS_URL : undefined;
480
- const httpUrl = typeof process !== 'undefined' ? process.env?.AI_HTTP_URL : undefined;
481
- if (wsUrl) {
482
- defaultClient = AI({ wsUrl });
483
- }
484
- else if (httpUrl) {
485
- defaultClient = AI({ httpUrl });
486
- }
487
- else {
488
- throw new Error('AI client not configured. Call configureAI() first or set AI_WS_URL/AI_HTTP_URL environment variables.');
489
- }
490
- }
491
- return defaultClient;
492
- }
493
- /**
494
- * Base class for implementing AI services
495
- *
496
- * Extend this class to create your own AI service implementation.
497
- *
498
- * @example
499
- * ```ts
500
- * class MyAIService extends AIServiceTarget {
501
- * async generate(options: AIGenerateOptions): Promise<AIGenerateResult> {
502
- * // Your implementation
503
- * }
504
- * }
505
- * ```
506
- */
507
- export class AIServiceTarget extends RpcTarget {
508
- }
509
- /**
510
- * Standalone function for defining AI functions
53
+ * Create AI functions from schemas
511
54
  *
512
55
  * @example
513
56
  * ```ts
514
- * import { defineFunction } from 'ai-functions'
515
- *
516
- * const summarize = defineFunction({
517
- * type: 'generative',
518
- * name: 'summarize',
519
- * args: { text: 'Text to summarize' },
520
- * output: 'string',
521
- * promptTemplate: 'Summarize: {{text}}',
57
+ * const ai = AI({
58
+ * storyBrand: {
59
+ * hero: 'Who is the customer?',
60
+ * problem: {
61
+ * internal: 'What internal problem do they face?',
62
+ * external: 'What external challenge exists?',
63
+ * philosophical: 'Why is this wrong?',
64
+ * },
65
+ * guide: 'Who helps them? (the brand)',
66
+ * plan: ['What are the steps to success?'],
67
+ * callToAction: 'What should they do?',
68
+ * success: 'What does success look like?',
69
+ * failure: 'What happens if they fail?',
70
+ * },
71
+ * recipe: {
72
+ * name: 'Recipe name',
73
+ * type: 'food | drink | dessert',
74
+ * servings: 'How many servings? (number)',
75
+ * ingredients: ['List all ingredients'],
76
+ * steps: ['Cooking steps in order'],
77
+ * },
522
78
  * })
523
79
  *
524
- * const result = await summarize.call({ text: 'Long article...' })
80
+ * // Call the generated functions
81
+ * const brand = await ai.storyBrand('Acme Corp sells widgets')
82
+ * const dinner = await ai.recipe('Italian pasta for 4 people')
525
83
  * ```
526
84
  */
527
- export function defineFunction(definition) {
528
- return createDefinedFunction(definition);
529
- }
530
- // ============================================================================
531
- // Function Registry
532
- // ============================================================================
533
- /**
534
- * In-memory function registry
535
- */
536
- class InMemoryFunctionRegistry {
537
- functions = new Map();
538
- get(name) {
539
- return this.functions.get(name);
540
- }
541
- set(name, fn) {
542
- this.functions.set(name, fn);
543
- }
544
- has(name) {
545
- return this.functions.has(name);
546
- }
547
- list() {
548
- return Array.from(this.functions.keys());
549
- }
550
- delete(name) {
551
- return this.functions.delete(name);
552
- }
553
- clear() {
554
- this.functions.clear();
555
- }
556
- }
557
- /**
558
- * Global function registry
559
- *
560
- * Note: This is in-memory only. For persistence, use mdxai or mdxdb packages.
561
- */
562
- export const functions = new InMemoryFunctionRegistry();
563
- // ============================================================================
564
- // Auto-Define Functions
565
- // ============================================================================
566
- /**
567
- * Analyze a function call and determine what type of function it should be
568
- */
569
- async function analyzeFunction(name, args) {
570
- // Convert camelCase/snake_case to readable name
571
- const readableName = name
572
- .replace(/([A-Z])/g, ' $1')
573
- .replace(/_/g, ' ')
574
- .toLowerCase()
575
- .trim();
576
- const argDescriptions = Object.entries(args)
577
- .map(([key, value]) => {
578
- const type = Array.isArray(value) ? 'array' : typeof value;
579
- return ` - ${key}: ${type} (example: ${JSON.stringify(value).slice(0, 50)})`;
580
- })
581
- .join('\n');
582
- const result = await generateObject({
583
- model: 'sonnet',
584
- schema: {
585
- type: 'code | generative | agentic | human',
586
- reasoning: 'Why this function type is appropriate (1-2 sentences)',
587
- description: 'What this function does',
588
- output: 'string | object | image | video | audio',
589
- returnType: 'Schema for the return type as a SimpleSchema object',
590
- system: 'System prompt for the AI (if generative/agentic)',
591
- promptTemplate: 'Prompt template with {{arg}} placeholders',
592
- instructions: 'Instructions for agentic/human functions',
593
- needsTools: 'true | false',
594
- suggestedTools: ['Names of tools that might be needed'],
595
- channel: 'slack | email | web | sms | custom',
596
- },
597
- system: `You are an expert at designing AI functions. Analyze the function name and arguments to determine the best function type.
598
-
599
- Function Types:
600
- - "code": For generating executable code (calculations, algorithms, data transformations)
601
- - "generative": For generating content (text, summaries, translations, creative writing, structured data)
602
- - "agentic": For complex tasks requiring multiple steps, research, or tool use (research, planning, multi-step workflows)
603
- - "human": For tasks requiring human judgment, approval, or input (approvals, reviews, decisions)
604
-
605
- Guidelines:
606
- - Most functions should be "generative" - they generate content or structured data
607
- - Use "code" only when actual executable code needs to be generated
608
- - Use "agentic" when the task requires research, multiple steps, or external tool use
609
- - Use "human" when human judgment/approval is essential`,
610
- prompt: `Analyze this function call and determine how to define it:
611
-
612
- Function Name: ${name}
613
- Readable Name: ${readableName}
614
- Arguments:
615
- ${argDescriptions || ' (no arguments)'}
616
-
617
- Determine:
618
- 1. What type of function this should be
619
- 2. What it should return
620
- 3. How it should be implemented`,
621
- });
622
- const analysis = result.object;
623
- // Build the function definition based on the analysis
624
- let definition;
625
- const baseDefinition = {
626
- name,
627
- description: analysis.description,
628
- args: inferArgsSchema(args),
629
- returnType: analysis.returnType,
630
- };
631
- switch (analysis.type) {
632
- case 'code':
633
- definition = {
634
- ...baseDefinition,
635
- type: 'code',
636
- language: 'typescript',
637
- instructions: analysis.instructions,
638
- };
639
- break;
640
- case 'agentic':
641
- definition = {
642
- ...baseDefinition,
643
- type: 'agentic',
644
- instructions: analysis.instructions || `Complete the ${readableName} task`,
645
- promptTemplate: analysis.promptTemplate,
646
- tools: [], // Tools would need to be provided separately
647
- maxIterations: 10,
648
- };
649
- break;
650
- case 'human':
651
- definition = {
652
- ...baseDefinition,
653
- type: 'human',
654
- channel: (analysis.channel || 'web'),
655
- instructions: analysis.instructions || `Please review and respond to this ${readableName} request`,
656
- promptTemplate: analysis.promptTemplate,
657
- };
658
- break;
659
- case 'generative':
660
- default:
661
- definition = {
662
- ...baseDefinition,
663
- type: 'generative',
664
- output: (analysis.output || 'object'),
665
- system: analysis.system,
666
- promptTemplate: analysis.promptTemplate || `{{${Object.keys(args)[0] || 'input'}}}`,
667
- };
668
- break;
669
- }
670
- return {
671
- type: analysis.type,
672
- reasoning: analysis.reasoning,
673
- definition,
674
- };
675
- }
676
- /**
677
- * Infer a schema from example arguments
678
- */
679
- function inferArgsSchema(args) {
680
- const schema = {};
681
- for (const [key, value] of Object.entries(args)) {
682
- if (typeof value === 'string') {
683
- schema[key] = `The ${key.replace(/([A-Z])/g, ' $1').toLowerCase()}`;
684
- }
685
- else if (typeof value === 'number') {
686
- schema[key] = `The ${key.replace(/([A-Z])/g, ' $1').toLowerCase()} (number)`;
687
- }
688
- else if (typeof value === 'boolean') {
689
- schema[key] = `Whether ${key.replace(/([A-Z])/g, ' $1').toLowerCase()} (boolean)`;
690
- }
691
- else if (Array.isArray(value)) {
692
- if (value.length > 0 && typeof value[0] === 'string') {
693
- schema[key] = [`List of ${key.replace(/([A-Z])/g, ' $1').toLowerCase()}`];
694
- }
695
- else {
696
- schema[key] = [`Items for ${key.replace(/([A-Z])/g, ' $1').toLowerCase()}`];
697
- }
698
- }
699
- else if (typeof value === 'object' && value !== null) {
700
- schema[key] = inferArgsSchema(value);
701
- }
702
- else {
703
- schema[key] = `The ${key.replace(/([A-Z])/g, ' $1').toLowerCase()}`;
704
- }
705
- }
706
- return schema;
707
- }
708
- /**
709
- * Auto-define a function based on its name and arguments, or define with explicit definition
710
- *
711
- * When called with (name, args), uses AI to analyze and determine:
712
- * - What type of function it should be (code, generative, agentic, human)
713
- * - What it should return
714
- * - How it should be implemented
715
- *
716
- * When called with a FunctionDefinition, creates the function directly.
717
- *
718
- * @example
719
- * ```ts
720
- * // Auto-define from name and example args
721
- * const planTrip = await define('planTrip', { destination: 'Tokyo', travelers: 2 })
722
- *
723
- * // Or define explicitly
724
- * const summarize = define.generative({
725
- * name: 'summarize',
726
- * args: { text: 'Text to summarize' },
727
- * output: 'string',
728
- * })
729
- *
730
- * // Or with full definition
731
- * const fn = defineFunction({
732
- * type: 'generative',
733
- * name: 'translate',
734
- * args: { text: 'Text', lang: 'Target language' },
735
- * output: 'string',
736
- * })
737
- * ```
738
- */
739
- async function autoDefineImpl(name, args) {
740
- // Check if already defined
741
- const existing = functions.get(name);
742
- if (existing) {
743
- return existing;
744
- }
745
- // Analyze and define the function
746
- const { definition } = await analyzeFunction(name, args);
747
- // Create the defined function
748
- const definedFn = createDefinedFunction(definition);
749
- // Store in registry
750
- functions.set(name, definedFn);
751
- return definedFn;
752
- }
753
- /**
754
- * Define functions - auto-define or use typed helpers
755
- */
756
- export const define = Object.assign(autoDefineImpl, {
757
- /**
758
- * Define a code generation function
759
- */
760
- code: (definition) => {
761
- const fn = defineFunction({ type: 'code', ...definition });
762
- functions.set(definition.name, fn);
763
- return fn;
764
- },
765
- /**
766
- * Define a generative function
767
- */
768
- generative: (definition) => {
769
- const fn = defineFunction({ type: 'generative', ...definition });
770
- functions.set(definition.name, fn);
771
- return fn;
772
- },
773
- /**
774
- * Define an agentic function
775
- */
776
- agentic: (definition) => {
777
- const fn = defineFunction({ type: 'agentic', ...definition });
778
- functions.set(definition.name, fn);
779
- return fn;
780
- },
781
- /**
782
- * Define a human-in-the-loop function
783
- */
784
- human: (definition) => {
785
- const fn = defineFunction({ type: 'human', ...definition });
786
- functions.set(definition.name, fn);
787
- return fn;
788
- },
789
- });
790
- // ============================================================================
791
- // AI() - Smart AI Client with Auto-Definition
792
- // ============================================================================
793
- /** Known built-in method names that should not be auto-defined */
794
- const BUILTIN_METHODS = new Set([
795
- 'do', 'is', 'code', 'decide', 'diagram', 'generate', 'image', 'video', 'write', 'list', 'lists',
796
- 'functions', 'define', 'defineFunction', 'then', 'catch', 'finally',
797
- ]);
798
- /**
799
- * Create a smart AI client that auto-defines functions on first call
800
- *
801
- * @example
802
- * ```ts
803
- * const ai = AI()
804
- *
805
- * // First call - auto-defines the function
806
- * const trip = await ai.planTrip({
807
- * destination: 'Tokyo',
808
- * dates: { start: '2024-03-01', end: '2024-03-10' },
809
- * travelers: 2,
810
- * })
811
- *
812
- * // Second call - uses cached definition (in-memory)
813
- * const trip2 = await ai.planTrip({
814
- * destination: 'Paris',
815
- * dates: { start: '2024-06-01', end: '2024-06-07' },
816
- * travelers: 4,
817
- * })
818
- *
819
- * // Access registry and define
820
- * console.log(ai.functions.list()) // ['planTrip']
821
- * ai.define.generative({ name: 'summarize', ... })
822
- * ```
823
- */
824
- function createSmartAI() {
825
- const base = {
826
- functions,
827
- define,
828
- defineFunction,
829
- };
830
- return new Proxy(base, {
831
- get(target, prop) {
832
- // Return built-in properties
833
- if (prop in target) {
834
- return target[prop];
835
- }
836
- // Skip internal properties
837
- if (typeof prop === 'symbol' || prop.startsWith('_') || BUILTIN_METHODS.has(prop)) {
838
- return undefined;
839
- }
840
- // Return a function that auto-defines and calls
841
- return async (args = {}) => {
842
- // Check if function is already defined
843
- let fn = functions.get(prop);
844
- if (!fn) {
845
- // Auto-define the function
846
- fn = await define(prop, args);
847
- }
848
- // Call the function
849
- return fn.call(args);
850
- };
851
- },
852
- });
85
+ export function AI(schemas, defaultOptions) {
86
+ // Schema functions mode - create a function for each schema
87
+ return createSchemaFunctions(schemas, defaultOptions);
853
88
  }
854
- /**
855
- * Default AI instance with auto-define capability
856
- *
857
- * @example
858
- * ```ts
859
- * import { ai } from 'ai-functions'
860
- *
861
- * // Auto-define and call
862
- * const result = await ai.summarize({ text: 'Long article...' })
863
- *
864
- * // Access functions registry
865
- * ai.functions.list()
866
- *
867
- * // Define explicitly
868
- * ai.define.generative({ name: 'translate', ... })
869
- * ```
870
- */
871
- export const ai = createSmartAI();
872
89
  //# sourceMappingURL=ai.js.map