ai-functions 0.2.19 → 0.4.0

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