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/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
@@ -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
+ }