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.
- package/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-test.log +105 -0
- package/README.md +232 -37
- package/TODO.md +138 -0
- package/dist/ai-promise.d.ts +219 -0
- package/dist/ai-promise.d.ts.map +1 -0
- package/dist/ai-promise.js +610 -0
- package/dist/ai-promise.js.map +1 -0
- package/dist/ai.d.ts +285 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +842 -0
- package/dist/ai.js.map +1 -0
- package/dist/batch/anthropic.d.ts +23 -0
- package/dist/batch/anthropic.d.ts.map +1 -0
- package/dist/batch/anthropic.js +257 -0
- package/dist/batch/anthropic.js.map +1 -0
- package/dist/batch/bedrock.d.ts +64 -0
- package/dist/batch/bedrock.d.ts.map +1 -0
- package/dist/batch/bedrock.js +586 -0
- package/dist/batch/bedrock.js.map +1 -0
- package/dist/batch/cloudflare.d.ts +37 -0
- package/dist/batch/cloudflare.d.ts.map +1 -0
- package/dist/batch/cloudflare.js +289 -0
- package/dist/batch/cloudflare.js.map +1 -0
- package/dist/batch/google.d.ts +41 -0
- package/dist/batch/google.d.ts.map +1 -0
- package/dist/batch/google.js +360 -0
- package/dist/batch/google.js.map +1 -0
- package/dist/batch/index.d.ts +31 -0
- package/dist/batch/index.d.ts.map +1 -0
- package/dist/batch/index.js +31 -0
- package/dist/batch/index.js.map +1 -0
- package/dist/batch/memory.d.ts +44 -0
- package/dist/batch/memory.d.ts.map +1 -0
- package/dist/batch/memory.js +188 -0
- package/dist/batch/memory.js.map +1 -0
- package/dist/batch/openai.d.ts +37 -0
- package/dist/batch/openai.d.ts.map +1 -0
- package/dist/batch/openai.js +403 -0
- package/dist/batch/openai.js.map +1 -0
- package/dist/batch-map.d.ts +125 -0
- package/dist/batch-map.d.ts.map +1 -0
- package/dist/batch-map.js +406 -0
- package/dist/batch-map.js.map +1 -0
- package/dist/batch-queue.d.ts +273 -0
- package/dist/batch-queue.d.ts.map +1 -0
- package/dist/batch-queue.js +271 -0
- package/dist/batch-queue.js.map +1 -0
- package/dist/context.d.ts +133 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +267 -0
- package/dist/context.js.map +1 -0
- package/dist/embeddings.d.ts +123 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +170 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/eval/index.d.ts +8 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +8 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/models.d.ts +66 -0
- package/dist/eval/models.d.ts.map +1 -0
- package/dist/eval/models.js +120 -0
- package/dist/eval/models.js.map +1 -0
- package/dist/eval/runner.d.ts +64 -0
- package/dist/eval/runner.d.ts.map +1 -0
- package/dist/eval/runner.js +148 -0
- package/dist/eval/runner.js.map +1 -0
- package/dist/generate.d.ts +168 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +174 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives.d.ts +292 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +471 -0
- package/dist/primitives.js.map +1 -0
- package/dist/providers/cloudflare.d.ts +9 -0
- package/dist/providers/cloudflare.d.ts.map +1 -0
- package/dist/providers/cloudflare.js +9 -0
- package/dist/providers/cloudflare.js.map +1 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/schema.d.ts +54 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +109 -0
- package/dist/schema.js.map +1 -0
- package/dist/template.d.ts +73 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +129 -0
- package/dist/template.js.map +1 -0
- package/dist/types.d.ts +481 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/evalite.config.ts +19 -0
- package/evals/README.md +212 -0
- package/evals/classification.eval.ts +108 -0
- package/evals/marketing.eval.ts +370 -0
- package/evals/math.eval.ts +94 -0
- package/evals/run-evals.ts +166 -0
- package/evals/structured-output.eval.ts +143 -0
- package/evals/writing.eval.ts +117 -0
- package/examples/batch-blog-posts.ts +160 -0
- package/package.json +59 -43
- package/src/ai-promise.ts +784 -0
- package/src/ai.ts +1183 -0
- package/src/batch/anthropic.ts +375 -0
- package/src/batch/bedrock.ts +801 -0
- package/src/batch/cloudflare.ts +421 -0
- package/src/batch/google.ts +491 -0
- package/src/batch/index.ts +31 -0
- package/src/batch/memory.ts +253 -0
- package/src/batch/openai.ts +557 -0
- package/src/batch-map.ts +534 -0
- package/src/batch-queue.ts +493 -0
- package/src/context.ts +332 -0
- package/src/embeddings.ts +244 -0
- package/src/eval/index.ts +8 -0
- package/src/eval/models.ts +158 -0
- package/src/eval/runner.ts +217 -0
- package/src/generate.ts +245 -0
- package/src/index.ts +154 -0
- package/src/primitives.ts +612 -0
- package/src/providers/cloudflare.ts +15 -0
- package/src/providers/index.ts +14 -0
- package/src/schema.ts +147 -0
- package/src/template.ts +209 -0
- package/src/types.ts +540 -0
- package/test/README.md +105 -0
- package/test/ai-proxy.test.ts +192 -0
- package/test/async-iterators.test.ts +327 -0
- package/test/batch-background.test.ts +482 -0
- package/test/batch-blog-posts.test.ts +387 -0
- package/test/blog-generation.test.ts +510 -0
- package/test/browse-read.test.ts +611 -0
- package/test/core-functions.test.ts +694 -0
- package/test/decide.test.ts +393 -0
- package/test/define.test.ts +274 -0
- package/test/e2e-bedrock-manual.ts +163 -0
- package/test/e2e-bedrock.test.ts +191 -0
- package/test/e2e-flex-gateway.ts +157 -0
- package/test/e2e-flex-manual.ts +183 -0
- package/test/e2e-flex.test.ts +209 -0
- package/test/e2e-google-manual.ts +178 -0
- package/test/e2e-google.test.ts +216 -0
- package/test/embeddings.test.ts +284 -0
- package/test/evals/define-function.eval.test.ts +379 -0
- package/test/evals/primitives.eval.test.ts +384 -0
- package/test/function-types.test.ts +492 -0
- package/test/generate-core.test.ts +319 -0
- package/test/generate.test.ts +163 -0
- package/test/implicit-batch.test.ts +422 -0
- package/test/schema.test.ts +109 -0
- package/test/tagged-templates.test.ts +302 -0
- package/tsconfig.json +8 -6
- package/vitest.config.ts +42 -0
- package/LICENSE +0 -21
- package/db/cache.ts +0 -6
- package/db/mongo.ts +0 -75
- package/dist/mjs/db/cache.d.ts +0 -1
- package/dist/mjs/db/cache.js +0 -5
- package/dist/mjs/db/mongo.d.ts +0 -31
- package/dist/mjs/db/mongo.js +0 -48
- package/dist/mjs/examples/data.d.ts +0 -1105
- package/dist/mjs/examples/data.js +0 -1105
- package/dist/mjs/functions/ai.d.ts +0 -20
- package/dist/mjs/functions/ai.js +0 -83
- package/dist/mjs/functions/ai.test.d.ts +0 -1
- package/dist/mjs/functions/ai.test.js +0 -29
- package/dist/mjs/functions/gpt.d.ts +0 -4
- package/dist/mjs/functions/gpt.js +0 -10
- package/dist/mjs/functions/list.d.ts +0 -7
- package/dist/mjs/functions/list.js +0 -72
- package/dist/mjs/index.d.ts +0 -3
- package/dist/mjs/index.js +0 -3
- package/dist/mjs/queue/kafka.d.ts +0 -0
- package/dist/mjs/queue/kafka.js +0 -1
- package/dist/mjs/queue/memory.d.ts +0 -0
- package/dist/mjs/queue/memory.js +0 -1
- package/dist/mjs/queue/mongo.d.ts +0 -30
- package/dist/mjs/queue/mongo.js +0 -42
- package/dist/mjs/streams/kafka.d.ts +0 -0
- package/dist/mjs/streams/kafka.js +0 -1
- package/dist/mjs/streams/memory.d.ts +0 -0
- package/dist/mjs/streams/memory.js +0 -1
- package/dist/mjs/streams/mongo.d.ts +0 -0
- package/dist/mjs/streams/mongo.js +0 -1
- package/dist/mjs/streams/types.d.ts +0 -0
- package/dist/mjs/streams/types.js +0 -1
- package/dist/mjs/types.d.ts +0 -11
- package/dist/mjs/types.js +0 -1
- package/dist/mjs/utils/completion.d.ts +0 -9
- package/dist/mjs/utils/completion.js +0 -20
- package/dist/mjs/utils/schema.d.ts +0 -10
- package/dist/mjs/utils/schema.js +0 -72
- package/dist/mjs/utils/schema.test.d.ts +0 -1
- package/dist/mjs/utils/schema.test.js +0 -60
- package/dist/mjs/utils/state.d.ts +0 -1
- package/dist/mjs/utils/state.js +0 -19
- package/examples/data.ts +0 -1105
- package/fixup +0 -11
- package/functions/ai.test.ts +0 -41
- package/functions/ai.ts +0 -115
- package/functions/gpt.ts +0 -12
- package/functions/list.ts +0 -84
- package/index.ts +0 -3
- package/queue/kafka.ts +0 -0
- package/queue/memory.ts +0 -0
- package/queue/mongo.ts +0 -88
- package/streams/kafka.ts +0 -0
- package/streams/memory.ts +0 -0
- package/streams/mongo.ts +0 -0
- package/streams/types.ts +0 -0
- package/tsconfig-backup.json +0 -105
- package/tsconfig-base.json +0 -26
- package/tsconfig-cjs.json +0 -8
- package/types.ts +0 -12
- package/utils/completion.ts +0 -28
- package/utils/schema.test.ts +0 -69
- package/utils/schema.ts +0 -74
- package/utils/state.ts +0 -23
package/src/schema.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simplified schema syntax for AI generation
|
|
3
|
+
*
|
|
4
|
+
* Converts human-readable schema definitions to Zod schemas:
|
|
5
|
+
* - 'description' → z.string().describe('description')
|
|
6
|
+
* - 'description (number)' → z.number().describe('description')
|
|
7
|
+
* - 'description (boolean)' → z.boolean().describe('description')
|
|
8
|
+
* - 'description (integer)' → z.number().int().describe('description')
|
|
9
|
+
* - 'description (date)' → z.string().datetime().describe('description')
|
|
10
|
+
* - 'opt1 | opt2 | opt3' → z.enum(['opt1', 'opt2', 'opt3'])
|
|
11
|
+
* - ['description'] → z.array(z.string()).describe('description')
|
|
12
|
+
* - { nested } → z.object() recursively
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { z, type ZodTypeAny } from 'zod'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Simplified schema types
|
|
21
|
+
*/
|
|
22
|
+
export type SimpleSchema =
|
|
23
|
+
| string // z.string().describe(value)
|
|
24
|
+
| [string] // z.array(z.string()).describe(value)
|
|
25
|
+
| [number] // z.array(z.number()).describe(value)
|
|
26
|
+
| [SimpleSchema] // z.array(converted).describe(value)
|
|
27
|
+
| { [key: string]: SimpleSchema } // z.object() recursively
|
|
28
|
+
| ZodTypeAny // Pass-through for actual Zod schemas
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if value is a Zod schema
|
|
32
|
+
*/
|
|
33
|
+
function isZodSchema(value: unknown): value is ZodTypeAny {
|
|
34
|
+
return value !== null &&
|
|
35
|
+
typeof value === 'object' &&
|
|
36
|
+
'_def' in value &&
|
|
37
|
+
'parse' in value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert a simplified schema to a Zod schema
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { schema } from 'ai-functions'
|
|
46
|
+
* import { z } from 'zod'
|
|
47
|
+
*
|
|
48
|
+
* // These are equivalent:
|
|
49
|
+
* const simple = schema({
|
|
50
|
+
* name: 'What is the recipe name?',
|
|
51
|
+
* ingredients: ['List all ingredients'],
|
|
52
|
+
* steps: ['List all cooking steps'],
|
|
53
|
+
* })
|
|
54
|
+
*
|
|
55
|
+
* const zod = z.object({
|
|
56
|
+
* name: z.string().describe('What is the recipe name?'),
|
|
57
|
+
* ingredients: z.array(z.string()).describe('List all ingredients'),
|
|
58
|
+
* steps: z.array(z.string()).describe('List all cooking steps'),
|
|
59
|
+
* })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function schema<T extends SimpleSchema>(input: T): ZodTypeAny {
|
|
63
|
+
return convertToZod(input)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function convertToZod(input: SimpleSchema): ZodTypeAny {
|
|
67
|
+
// Already a Zod schema - pass through
|
|
68
|
+
if (isZodSchema(input)) {
|
|
69
|
+
return input
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// String handling
|
|
73
|
+
if (typeof input === 'string') {
|
|
74
|
+
// Enum syntax: 'option1 | option2 | option3'
|
|
75
|
+
if (input.includes(' | ')) {
|
|
76
|
+
const options = input.split(' | ').map(s => s.trim())
|
|
77
|
+
return z.enum(options as [string, ...string[]])
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Type hint syntax: 'description (type)'
|
|
81
|
+
const typeMatch = input.match(/^(.+?)\s*\((number|boolean|integer|date)\)$/i)
|
|
82
|
+
if (typeMatch) {
|
|
83
|
+
const [, description, type] = typeMatch
|
|
84
|
+
const desc = description!.trim()
|
|
85
|
+
switch (type!.toLowerCase()) {
|
|
86
|
+
case 'number':
|
|
87
|
+
return z.number().describe(desc)
|
|
88
|
+
case 'integer':
|
|
89
|
+
return z.number().int().describe(desc)
|
|
90
|
+
case 'boolean':
|
|
91
|
+
return z.boolean().describe(desc)
|
|
92
|
+
case 'date':
|
|
93
|
+
return z.string().datetime().describe(desc)
|
|
94
|
+
default:
|
|
95
|
+
return z.string().describe(desc)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Regular string description → z.string().describe()
|
|
100
|
+
return z.string().describe(input)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Array with single element → z.array().describe()
|
|
104
|
+
if (Array.isArray(input) && input.length === 1) {
|
|
105
|
+
const [desc] = input
|
|
106
|
+
|
|
107
|
+
// [string] → z.array(z.string()).describe(string)
|
|
108
|
+
if (typeof desc === 'string') {
|
|
109
|
+
return z.array(z.string()).describe(desc)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// [number] → z.array(z.number()) - number as type indicator
|
|
113
|
+
if (typeof desc === 'number') {
|
|
114
|
+
return z.array(z.number())
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// [SimpleSchema] → z.array(converted)
|
|
118
|
+
return z.array(convertToZod(desc as SimpleSchema))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Object → z.object() with recursive conversion
|
|
122
|
+
if (typeof input === 'object' && input !== null) {
|
|
123
|
+
const shape: Record<string, ZodTypeAny> = {}
|
|
124
|
+
|
|
125
|
+
for (const [key, value] of Object.entries(input)) {
|
|
126
|
+
shape[key] = convertToZod(value as SimpleSchema)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return z.object(shape)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Fallback - shouldn't reach here
|
|
133
|
+
return z.unknown()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Type helper to infer the output type from a simple schema
|
|
138
|
+
*/
|
|
139
|
+
export type InferSimpleSchema<T> = T extends string
|
|
140
|
+
? string
|
|
141
|
+
: T extends [string]
|
|
142
|
+
? string[]
|
|
143
|
+
: T extends [number]
|
|
144
|
+
? number[]
|
|
145
|
+
: T extends { [K in keyof T]: SimpleSchema }
|
|
146
|
+
? { [K in keyof T]: InferSimpleSchema<T[K]> }
|
|
147
|
+
: unknown
|
package/src/template.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tagged template literal utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides support for tagged template syntax across all AI functions:
|
|
5
|
+
* - fn`prompt ${variable}` - template literal syntax
|
|
6
|
+
* - Objects/arrays auto-convert to YAML
|
|
7
|
+
* - Options chaining: fn`prompt`({ model: '...' })
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { stringify } from 'yaml'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Common options for all AI functions
|
|
16
|
+
*/
|
|
17
|
+
export interface FunctionOptions {
|
|
18
|
+
/** Model to use (e.g., 'claude-opus-4-5', 'gpt-5-1', 'gemini-3-pro') */
|
|
19
|
+
model?: string
|
|
20
|
+
/** Thinking level: 'none', 'low', 'medium', 'high', or token budget number */
|
|
21
|
+
thinking?: 'none' | 'low' | 'medium' | 'high' | number
|
|
22
|
+
/** Temperature (0-2) */
|
|
23
|
+
temperature?: number
|
|
24
|
+
/** Maximum tokens to generate */
|
|
25
|
+
maxTokens?: number
|
|
26
|
+
/** System prompt */
|
|
27
|
+
system?: string
|
|
28
|
+
/** Processing mode */
|
|
29
|
+
mode?: 'default' | 'background'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parse a tagged template literal into a prompt string
|
|
34
|
+
* Objects and arrays are converted to YAML for readability
|
|
35
|
+
*/
|
|
36
|
+
export function parseTemplate(strings: TemplateStringsArray, ...values: unknown[]): string {
|
|
37
|
+
return strings.reduce((result, str, i) => {
|
|
38
|
+
const value = values[i]
|
|
39
|
+
if (value === undefined) {
|
|
40
|
+
return result + str
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Convert objects/arrays to YAML
|
|
44
|
+
if (typeof value === 'object' && value !== null) {
|
|
45
|
+
const yaml = stringify(value).trim()
|
|
46
|
+
return result + str + '\n' + yaml
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Primitives use toString()
|
|
50
|
+
return result + str + String(value)
|
|
51
|
+
}, '')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Result type that is both a Promise and can be called with options
|
|
56
|
+
*/
|
|
57
|
+
export type ChainablePromise<T> = Promise<T> & {
|
|
58
|
+
(options?: FunctionOptions): Promise<T>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a chainable promise that supports both await and options chaining
|
|
63
|
+
*/
|
|
64
|
+
export function createChainablePromise<T>(
|
|
65
|
+
executor: (options?: FunctionOptions) => Promise<T>,
|
|
66
|
+
defaultOptions?: FunctionOptions
|
|
67
|
+
): ChainablePromise<T> {
|
|
68
|
+
// Create the base promise
|
|
69
|
+
const basePromise = executor(defaultOptions)
|
|
70
|
+
|
|
71
|
+
// Create a function that accepts options
|
|
72
|
+
const chainable = ((options?: FunctionOptions) => {
|
|
73
|
+
return executor({ ...defaultOptions, ...options })
|
|
74
|
+
}) as ChainablePromise<T>
|
|
75
|
+
|
|
76
|
+
// Make it thenable
|
|
77
|
+
chainable.then = basePromise.then.bind(basePromise)
|
|
78
|
+
chainable.catch = basePromise.catch.bind(basePromise)
|
|
79
|
+
;(chainable as Promise<T>).finally = basePromise.finally.bind(basePromise)
|
|
80
|
+
|
|
81
|
+
return chainable
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Template function signature
|
|
86
|
+
*/
|
|
87
|
+
export type TemplateFunction<T> = {
|
|
88
|
+
(strings: TemplateStringsArray, ...values: unknown[]): ChainablePromise<T>
|
|
89
|
+
(prompt: string, options?: FunctionOptions): Promise<T>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Create a function that supports both tagged templates and regular calls
|
|
94
|
+
*/
|
|
95
|
+
export function createTemplateFunction<T>(
|
|
96
|
+
handler: (prompt: string, options?: FunctionOptions) => Promise<T>
|
|
97
|
+
): TemplateFunction<T> {
|
|
98
|
+
function templateFn(
|
|
99
|
+
promptOrStrings: string | TemplateStringsArray,
|
|
100
|
+
...args: unknown[]
|
|
101
|
+
): Promise<T> | ChainablePromise<T> {
|
|
102
|
+
// Tagged template literal
|
|
103
|
+
if (Array.isArray(promptOrStrings) && 'raw' in promptOrStrings) {
|
|
104
|
+
const prompt = parseTemplate(promptOrStrings as TemplateStringsArray, ...args)
|
|
105
|
+
return createChainablePromise((options) => handler(prompt, options))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Regular function call
|
|
109
|
+
return handler(promptOrStrings as string, args[0] as FunctionOptions | undefined)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return templateFn as TemplateFunction<T>
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create a function with batch support
|
|
117
|
+
*/
|
|
118
|
+
export interface BatchableFunction<T, TInput = string> extends TemplateFunction<T> {
|
|
119
|
+
batch: (inputs: TInput[]) => Promise<T[]>
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Add batch capability to a template function
|
|
124
|
+
*/
|
|
125
|
+
export function withBatch<T, TInput = string>(
|
|
126
|
+
fn: TemplateFunction<T>,
|
|
127
|
+
batchHandler: (inputs: TInput[]) => Promise<T[]>
|
|
128
|
+
): BatchableFunction<T, TInput> {
|
|
129
|
+
const batchable = fn as BatchableFunction<T, TInput>
|
|
130
|
+
batchable.batch = batchHandler
|
|
131
|
+
return batchable
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Create an async iterable from a streaming generator
|
|
136
|
+
*/
|
|
137
|
+
export function createAsyncIterable<T>(
|
|
138
|
+
items: T[] | (() => AsyncGenerator<T>)
|
|
139
|
+
): AsyncIterable<T> {
|
|
140
|
+
if (Array.isArray(items)) {
|
|
141
|
+
return {
|
|
142
|
+
async *[Symbol.asyncIterator]() {
|
|
143
|
+
for (const item of items) {
|
|
144
|
+
yield item
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
[Symbol.asyncIterator]: items,
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Create a result that is both a Promise (resolves to array) and AsyncIterable (streams items)
|
|
156
|
+
*/
|
|
157
|
+
export type StreamableList<T> = Promise<T[]> & AsyncIterable<T>
|
|
158
|
+
|
|
159
|
+
export function createStreamableList<T>(
|
|
160
|
+
getItems: () => Promise<T[]>,
|
|
161
|
+
streamItems?: () => AsyncGenerator<T>
|
|
162
|
+
): StreamableList<T> {
|
|
163
|
+
const promise = getItems()
|
|
164
|
+
|
|
165
|
+
const asyncIterator = streamItems
|
|
166
|
+
? streamItems
|
|
167
|
+
: async function* () {
|
|
168
|
+
const items = await promise
|
|
169
|
+
for (const item of items) {
|
|
170
|
+
yield item
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Create a proper Promise-like object with async iterator
|
|
175
|
+
const result = Object.create(null) as StreamableList<T>
|
|
176
|
+
|
|
177
|
+
// Add Promise methods
|
|
178
|
+
Object.defineProperty(result, 'then', {
|
|
179
|
+
value: promise.then.bind(promise),
|
|
180
|
+
writable: false,
|
|
181
|
+
enumerable: false,
|
|
182
|
+
})
|
|
183
|
+
Object.defineProperty(result, 'catch', {
|
|
184
|
+
value: promise.catch.bind(promise),
|
|
185
|
+
writable: false,
|
|
186
|
+
enumerable: false,
|
|
187
|
+
})
|
|
188
|
+
Object.defineProperty(result, 'finally', {
|
|
189
|
+
value: promise.finally.bind(promise),
|
|
190
|
+
writable: false,
|
|
191
|
+
enumerable: false,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
// Add async iterator
|
|
195
|
+
Object.defineProperty(result, Symbol.asyncIterator, {
|
|
196
|
+
value: asyncIterator,
|
|
197
|
+
writable: false,
|
|
198
|
+
enumerable: false,
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Add Symbol.toStringTag for Promise compatibility
|
|
202
|
+
Object.defineProperty(result, Symbol.toStringTag, {
|
|
203
|
+
value: 'Promise',
|
|
204
|
+
writable: false,
|
|
205
|
+
enumerable: false,
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
return result
|
|
209
|
+
}
|