ai-functions 2.1.3 → 2.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 +1 -1
- package/CHANGELOG.md +90 -1
- package/README.md +38 -0
- package/dist/ai-promise.d.ts +3 -3
- package/dist/ai-promise.d.ts.map +1 -1
- package/dist/ai-promise.js +135 -64
- package/dist/ai-promise.js.map +1 -1
- package/dist/ai-schemas.d.ts +56 -0
- package/dist/ai-schemas.d.ts.map +1 -0
- package/dist/ai-schemas.js +53 -0
- package/dist/ai-schemas.js.map +1 -0
- package/dist/ai.d.ts +16 -242
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +51 -858
- package/dist/ai.js.map +1 -1
- package/dist/batch/anthropic.d.ts +6 -4
- package/dist/batch/anthropic.d.ts.map +1 -1
- package/dist/batch/anthropic.js +83 -145
- package/dist/batch/anthropic.js.map +1 -1
- package/dist/batch/bedrock.d.ts +8 -30
- package/dist/batch/bedrock.d.ts.map +1 -1
- package/dist/batch/bedrock.js +155 -338
- package/dist/batch/bedrock.js.map +1 -1
- package/dist/batch/cloudflare.d.ts +8 -20
- package/dist/batch/cloudflare.d.ts.map +1 -1
- package/dist/batch/cloudflare.js +68 -189
- package/dist/batch/cloudflare.js.map +1 -1
- package/dist/batch/google.d.ts +6 -20
- package/dist/batch/google.d.ts.map +1 -1
- package/dist/batch/google.js +70 -238
- package/dist/batch/google.js.map +1 -1
- package/dist/batch/index.d.ts +4 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +4 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/memory.d.ts +1 -1
- package/dist/batch/memory.d.ts.map +1 -1
- package/dist/batch/memory.js +14 -10
- package/dist/batch/memory.js.map +1 -1
- package/dist/batch/openai.d.ts +11 -14
- package/dist/batch/openai.d.ts.map +1 -1
- package/dist/batch/openai.js +52 -156
- package/dist/batch/openai.js.map +1 -1
- package/dist/batch/provider.d.ts +111 -0
- package/dist/batch/provider.d.ts.map +1 -0
- package/dist/batch/provider.js +233 -0
- package/dist/batch/provider.js.map +1 -0
- package/dist/batch-map.d.ts.map +1 -1
- package/dist/batch-map.js +23 -17
- package/dist/batch-map.js.map +1 -1
- package/dist/batch-queue.d.ts +65 -0
- package/dist/batch-queue.d.ts.map +1 -1
- package/dist/batch-queue.js +169 -14
- package/dist/batch-queue.js.map +1 -1
- package/dist/budget.d.ts.map +1 -1
- package/dist/budget.js +27 -14
- package/dist/budget.js.map +1 -1
- package/dist/cache.d.ts +23 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +36 -15
- package/dist/cache.js.map +1 -1
- package/dist/context.d.ts +26 -8
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -62
- package/dist/context.js.map +1 -1
- package/dist/digital-objects-registry.d.ts +229 -0
- package/dist/digital-objects-registry.d.ts.map +1 -0
- package/dist/digital-objects-registry.js +617 -0
- package/dist/digital-objects-registry.js.map +1 -0
- package/dist/embeddings.d.ts +2 -2
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/eval/runner.d.ts +8 -0
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +41 -35
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval-log/in-memory.d.ts +34 -0
- package/dist/eval-log/in-memory.d.ts.map +1 -0
- package/dist/eval-log/in-memory.js +84 -0
- package/dist/eval-log/in-memory.js.map +1 -0
- package/dist/eval-log/index.d.ts +29 -0
- package/dist/eval-log/index.d.ts.map +1 -0
- package/dist/eval-log/index.js +39 -0
- package/dist/eval-log/index.js.map +1 -0
- package/dist/eval-log/types.d.ts +101 -0
- package/dist/eval-log/types.d.ts.map +1 -0
- package/dist/eval-log/types.js +16 -0
- package/dist/eval-log/types.js.map +1 -0
- package/dist/function-registry.d.ts +176 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +685 -0
- package/dist/function-registry.js.map +1 -0
- package/dist/generate.d.ts +9 -3
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +18 -18
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -18
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +118 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +187 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware/budget.d.ts +84 -0
- package/dist/middleware/budget.d.ts.map +1 -0
- package/dist/middleware/budget.js +110 -0
- package/dist/middleware/budget.js.map +1 -0
- package/dist/middleware/cache.d.ts +103 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +228 -0
- package/dist/middleware/cache.js.map +1 -0
- package/dist/middleware/embed-cache.d.ts +99 -0
- package/dist/middleware/embed-cache.d.ts.map +1 -0
- package/dist/middleware/embed-cache.js +128 -0
- package/dist/middleware/embed-cache.js.map +1 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/trace.d.ts +103 -0
- package/dist/middleware/trace.d.ts.map +1 -0
- package/dist/middleware/trace.js +176 -0
- package/dist/middleware/trace.js.map +1 -0
- package/dist/primitives.d.ts +120 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +398 -26
- package/dist/primitives.js.map +1 -1
- package/dist/retry.d.ts +66 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +115 -8
- package/dist/retry.js.map +1 -1
- package/dist/sandbox.d.ts +36 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +44 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/schema.js +2 -2
- package/dist/schema.js.map +1 -1
- package/dist/telemetry.d.ts +128 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +285 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +6 -1
- package/dist/template.js.map +1 -1
- package/dist/tool-orchestration.d.ts +66 -4
- package/dist/tool-orchestration.d.ts.map +1 -1
- package/dist/tool-orchestration.js +123 -23
- package/dist/tool-orchestration.js.map +1 -1
- package/dist/type-guards.d.ts +28 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +29 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types.d.ts +155 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +36 -1
- package/dist/types.js.map +1 -1
- package/dist/wrap-for-v3.d.ts +80 -0
- package/dist/wrap-for-v3.d.ts.map +1 -0
- package/dist/wrap-for-v3.js +89 -0
- package/dist/wrap-for-v3.js.map +1 -0
- package/examples/00-quickstart.ts +232 -0
- package/examples/01-rag-chatbot.ts +212 -0
- package/examples/02-multi-agent-research.ts +290 -0
- package/examples/03-email-classification.ts +379 -0
- package/examples/04-content-moderation.ts +400 -0
- package/examples/05-document-extraction.ts +455 -0
- package/examples/06-streaming-chat-nextjs.ts +437 -0
- package/examples/07-cloudflare-worker.ts +483 -0
- package/examples/08-batch-processing.ts +491 -0
- package/examples/09-budget-constrained.ts +527 -0
- package/examples/10-tool-orchestration.ts +565 -0
- package/examples/11-retry-resilience.ts +403 -0
- package/examples/12-caching-strategies.ts +422 -0
- package/examples/README.md +145 -0
- package/package.json +29 -25
- package/src/ai-promise.ts +226 -140
- package/src/ai-schemas.ts +122 -0
- package/src/ai.ts +71 -1176
- package/src/batch/anthropic.ts +96 -161
- package/src/batch/bedrock.ts +203 -454
- package/src/batch/cloudflare.ts +99 -282
- package/src/batch/google.ts +91 -297
- package/src/batch/index.ts +4 -1
- package/src/batch/memory.ts +15 -10
- package/src/batch/openai.ts +65 -193
- package/src/batch/provider.ts +336 -0
- package/src/batch-map.ts +29 -24
- package/src/batch-queue.ts +200 -11
- package/src/budget.ts +31 -18
- package/src/cache.ts +45 -17
- package/src/context.ts +106 -77
- package/src/digital-objects-registry.ts +750 -0
- package/src/errors.ts +37 -0
- package/src/eval/runner.ts +60 -36
- package/src/eval-log/in-memory.ts +90 -0
- package/src/eval-log/index.ts +46 -0
- package/src/eval-log/types.ts +110 -0
- package/src/function-registry.ts +874 -0
- package/src/generate.ts +33 -28
- package/src/index.ts +122 -21
- package/src/logger.ts +232 -0
- package/src/middleware/budget.ts +171 -0
- package/src/middleware/cache.ts +299 -0
- package/src/middleware/embed-cache.ts +195 -0
- package/src/middleware/index.ts +23 -0
- package/src/middleware/trace.ts +248 -0
- package/src/primitives.ts +589 -62
- package/src/retry.ts +144 -18
- package/src/sandbox.ts +52 -0
- package/src/schema.ts +8 -8
- package/src/telemetry.ts +403 -0
- package/src/template.ts +8 -4
- package/src/tool-orchestration.ts +213 -48
- package/src/type-guards.ts +31 -0
- package/src/types.ts +186 -27
- package/src/wrap-for-v3.ts +105 -0
- package/test/ai-promise.test.ts +1080 -0
- package/test/ai-proxy.test.ts +1 -1
- package/test/batch-autosubmit-errors.test.ts +49 -37
- package/test/batch-blog-posts.test.ts +87 -129
- package/test/core-functions.test.ts +183 -579
- package/test/decide.test.ts +154 -322
- package/test/define.test.ts +211 -8
- package/test/digital-objects-registry.test.ts +760 -0
- package/test/embedding-cache-middleware.test.ts +140 -0
- package/test/fill-template.test.ts +89 -0
- package/test/generate-core.test.ts +140 -229
- package/test/implicit-batch.test.ts +22 -65
- package/test/retry-policy-integration.test.ts +117 -0
- package/test/sandbox-execution.test.ts +155 -0
- package/test/schema.test.ts +55 -19
- package/test/template.test.ts +1164 -0
- package/test/tool-orchestration.test.ts +270 -0
- package/test/wrap-for-v3.test.ts +612 -0
- package/vitest.config.js +6 -0
- package/vitest.config.ts +20 -0
- package/LICENSE +0 -21
- package/dist/rpc/auth.d.ts +0 -69
- package/dist/rpc/auth.d.ts.map +0 -1
- package/dist/rpc/auth.js +0 -136
- package/dist/rpc/auth.js.map +0 -1
- package/dist/rpc/client.d.ts +0 -62
- package/dist/rpc/client.d.ts.map +0 -1
- package/dist/rpc/client.js +0 -103
- package/dist/rpc/client.js.map +0 -1
- package/dist/rpc/deferred.d.ts +0 -60
- package/dist/rpc/deferred.d.ts.map +0 -1
- package/dist/rpc/deferred.js +0 -96
- package/dist/rpc/deferred.js.map +0 -1
- package/dist/rpc/index.d.ts +0 -22
- package/dist/rpc/index.d.ts.map +0 -1
- package/dist/rpc/index.js +0 -38
- package/dist/rpc/index.js.map +0 -1
- package/dist/rpc/local.d.ts +0 -42
- package/dist/rpc/local.d.ts.map +0 -1
- package/dist/rpc/local.js +0 -50
- package/dist/rpc/local.js.map +0 -1
- package/dist/rpc/server.d.ts +0 -165
- package/dist/rpc/server.d.ts.map +0 -1
- package/dist/rpc/server.js +0 -405
- package/dist/rpc/server.js.map +0 -1
- package/dist/rpc/session.d.ts +0 -32
- package/dist/rpc/session.d.ts.map +0 -1
- package/dist/rpc/session.js +0 -43
- package/dist/rpc/session.js.map +0 -1
- package/dist/rpc/transport.d.ts +0 -306
- package/dist/rpc/transport.d.ts.map +0 -1
- package/dist/rpc/transport.js +0 -731
- package/dist/rpc/transport.js.map +0 -1
- package/src/batch/anthropic.js +0 -256
- package/src/batch/bedrock.js +0 -584
- package/src/batch/cloudflare.js +0 -287
- package/src/batch/google.js +0 -359
- package/src/batch/index.js +0 -30
- package/src/batch/memory.js +0 -187
- package/src/batch/openai.js +0 -402
- package/src/eval/index.js +0 -7
- package/src/eval/models.js +0 -119
- package/src/eval/runner.js +0 -147
- package/test/schema.test.js +0 -96
package/src/ai-promise.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AIPromise -
|
|
2
|
+
* AIPromise - Promise pipelining for AI functions
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* This enables:
|
|
5
5
|
* - Property access tracking for dynamic schema inference
|
|
6
6
|
* - Promise pipelining without await
|
|
7
7
|
* - Magical .map() for batch processing
|
|
@@ -58,7 +58,8 @@ export interface StreamOptions {
|
|
|
58
58
|
* Streaming result wrapper that provides both AsyncIterable interface
|
|
59
59
|
* and access to the final result
|
|
60
60
|
*/
|
|
61
|
-
export interface StreamingAIPromise<T>
|
|
61
|
+
export interface StreamingAIPromise<T>
|
|
62
|
+
extends AsyncIterable<T extends string ? string : Partial<T>> {
|
|
62
63
|
/** Stream of text chunks (for text generation) */
|
|
63
64
|
textStream: AsyncIterable<string>
|
|
64
65
|
/** Stream of partial objects (for object generation) */
|
|
@@ -131,7 +132,7 @@ let resolutionScheduled = false
|
|
|
131
132
|
// ============================================================================
|
|
132
133
|
|
|
133
134
|
/**
|
|
134
|
-
* AIPromise -
|
|
135
|
+
* AIPromise - Promise wrapper for AI functions
|
|
135
136
|
*
|
|
136
137
|
* Acts as both a Promise AND a stub that:
|
|
137
138
|
* - Tracks property accesses for dynamic schema inference
|
|
@@ -233,17 +234,15 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
233
234
|
const resolvedDeps: Record<string, unknown> = {}
|
|
234
235
|
for (const dep of this._dependencies) {
|
|
235
236
|
const value = await dep.promise.resolve()
|
|
236
|
-
const key =
|
|
237
|
+
const key =
|
|
238
|
+
dep.path.length > 0 ? dep.path.join('.') : `dep_${this._dependencies.indexOf(dep)}`
|
|
237
239
|
resolvedDeps[key] = value
|
|
238
240
|
}
|
|
239
241
|
|
|
240
242
|
// Substitute resolved dependencies into prompt
|
|
241
243
|
let finalPrompt = this._prompt
|
|
242
244
|
for (const [key, value] of Object.entries(resolvedDeps)) {
|
|
243
|
-
finalPrompt = finalPrompt.replace(
|
|
244
|
-
new RegExp(`\\$\\{${key}\\}`, 'g'),
|
|
245
|
-
String(value)
|
|
246
|
-
)
|
|
245
|
+
finalPrompt = finalPrompt.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), String(value))
|
|
247
246
|
}
|
|
248
247
|
|
|
249
248
|
// Build schema from accessed properties
|
|
@@ -254,9 +253,9 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
254
253
|
model: this._options.model || 'sonnet',
|
|
255
254
|
schema,
|
|
256
255
|
prompt: finalPrompt,
|
|
257
|
-
system: this._options.system,
|
|
258
|
-
temperature: this._options.temperature,
|
|
259
|
-
maxTokens: this._options.maxTokens,
|
|
256
|
+
...(this._options.system !== undefined && { system: this._options.system }),
|
|
257
|
+
...(this._options.temperature !== undefined && { temperature: this._options.temperature }),
|
|
258
|
+
...(this._options.maxTokens !== undefined && { maxTokens: this._options.maxTokens }),
|
|
260
259
|
})
|
|
261
260
|
|
|
262
261
|
// Extract the value based on type
|
|
@@ -264,16 +263,31 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
264
263
|
// 1. Runtime type checking validates the response structure
|
|
265
264
|
// 2. The type parameter T corresponds to the expected output type for each mode
|
|
266
265
|
let value = result.object as T
|
|
267
|
-
if (
|
|
266
|
+
if (
|
|
267
|
+
this._options.type === 'text' &&
|
|
268
|
+
typeof value === 'object' &&
|
|
269
|
+
value !== null &&
|
|
270
|
+
'text' in value
|
|
271
|
+
) {
|
|
268
272
|
value = (value as { text: T }).text
|
|
269
|
-
} else if (
|
|
273
|
+
} else if (
|
|
274
|
+
this._options.type === 'boolean' &&
|
|
275
|
+
typeof value === 'object' &&
|
|
276
|
+
value !== null &&
|
|
277
|
+
'answer' in value
|
|
278
|
+
) {
|
|
270
279
|
const answer = (value as { answer: string | boolean }).answer
|
|
271
280
|
// When type === 'boolean', T is constrained to boolean at the call site.
|
|
272
281
|
// TypeScript can't express this dependent relationship, so we use a simple cast.
|
|
273
282
|
// Runtime validation: answer is verified to be 'true', 'false', or boolean.
|
|
274
283
|
const booleanValue = answer === 'true' || answer === true
|
|
275
284
|
value = booleanValue as T
|
|
276
|
-
} else if (
|
|
285
|
+
} else if (
|
|
286
|
+
(this._options.type === 'list' || this._options.type === 'extract') &&
|
|
287
|
+
typeof value === 'object' &&
|
|
288
|
+
value !== null &&
|
|
289
|
+
'items' in value
|
|
290
|
+
) {
|
|
277
291
|
value = (value as { items: T }).items
|
|
278
292
|
}
|
|
279
293
|
|
|
@@ -301,7 +315,11 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
301
315
|
case 'list':
|
|
302
316
|
return { items: ['List items'] }
|
|
303
317
|
case 'extract':
|
|
304
|
-
return {
|
|
318
|
+
return {
|
|
319
|
+
items: [
|
|
320
|
+
'Array of extracted items as strings - extract ALL matching items from the text',
|
|
321
|
+
],
|
|
322
|
+
}
|
|
305
323
|
case 'lists':
|
|
306
324
|
return { categories: ['Category names'], data: 'JSON object with categorized lists' }
|
|
307
325
|
case 'boolean':
|
|
@@ -380,30 +398,31 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
380
398
|
* }))
|
|
381
399
|
* ```
|
|
382
400
|
*/
|
|
383
|
-
map<U>(
|
|
384
|
-
callback: (item: T extends (infer I)[] ? I : T, index: number) => U
|
|
385
|
-
): BatchMapPromise<U> {
|
|
401
|
+
map<U>(callback: (item: T extends (infer I)[] ? I : T, index: number) => U): BatchMapPromise<U> {
|
|
386
402
|
// Create a wrapper that resolves this promise first, then maps
|
|
387
403
|
const mapPromise = new BatchMapPromise<U>([], [], {})
|
|
388
404
|
|
|
389
405
|
// Override the resolve to first get the list items
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
406
|
+
// Type assertion: BatchMapPromise.resolve is a public method that we're replacing
|
|
407
|
+
// with a compatible async function returning Promise<U[]>
|
|
408
|
+
const self = this
|
|
409
|
+
Object.defineProperty(mapPromise, 'resolve', {
|
|
410
|
+
value: async function (): Promise<U[]> {
|
|
411
|
+
// First, resolve the list
|
|
412
|
+
const items = await self.resolve()
|
|
413
|
+
|
|
414
|
+
if (!Array.isArray(items)) {
|
|
415
|
+
throw new Error('Cannot map over non-array result')
|
|
416
|
+
}
|
|
398
417
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
items as (T extends (infer I)[] ? I : T)[],
|
|
402
|
-
callback
|
|
403
|
-
)
|
|
418
|
+
// Now create the actual batch map with the resolved items
|
|
419
|
+
const actualBatchMap = createBatchMap(items as (T extends (infer I)[] ? I : T)[], callback)
|
|
404
420
|
|
|
405
|
-
|
|
406
|
-
|
|
421
|
+
return actualBatchMap.resolve()
|
|
422
|
+
},
|
|
423
|
+
writable: true,
|
|
424
|
+
configurable: true,
|
|
425
|
+
})
|
|
407
426
|
|
|
408
427
|
return mapPromise
|
|
409
428
|
}
|
|
@@ -424,19 +443,24 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
424
443
|
callback: (item: T extends (infer I)[] ? I : T, index: number) => U
|
|
425
444
|
): BatchMapPromise<U> {
|
|
426
445
|
const mapPromise = new BatchMapPromise<U>([], [], { immediate: true })
|
|
446
|
+
const self = this
|
|
427
447
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
448
|
+
Object.defineProperty(mapPromise, 'resolve', {
|
|
449
|
+
value: async function (): Promise<U[]> {
|
|
450
|
+
const items = await self.resolve()
|
|
451
|
+
if (!Array.isArray(items)) {
|
|
452
|
+
throw new Error('Cannot map over non-array result')
|
|
453
|
+
}
|
|
454
|
+
const actualBatchMap = createBatchMap(
|
|
455
|
+
items as (T extends (infer I)[] ? I : T)[],
|
|
456
|
+
callback,
|
|
457
|
+
{ immediate: true }
|
|
458
|
+
)
|
|
459
|
+
return actualBatchMap.resolve()
|
|
460
|
+
},
|
|
461
|
+
writable: true,
|
|
462
|
+
configurable: true,
|
|
463
|
+
})
|
|
440
464
|
|
|
441
465
|
return mapPromise
|
|
442
466
|
}
|
|
@@ -445,19 +469,24 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
445
469
|
callback: (item: T extends (infer I)[] ? I : T, index: number) => U
|
|
446
470
|
): BatchMapPromise<U> {
|
|
447
471
|
const mapPromise = new BatchMapPromise<U>([], [], { deferred: true })
|
|
472
|
+
const self = this
|
|
448
473
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
474
|
+
Object.defineProperty(mapPromise, 'resolve', {
|
|
475
|
+
value: async function (): Promise<U[]> {
|
|
476
|
+
const items = await self.resolve()
|
|
477
|
+
if (!Array.isArray(items)) {
|
|
478
|
+
throw new Error('Cannot map over non-array result')
|
|
479
|
+
}
|
|
480
|
+
const actualBatchMap = createBatchMap(
|
|
481
|
+
items as (T extends (infer I)[] ? I : T)[],
|
|
482
|
+
callback,
|
|
483
|
+
{ deferred: true }
|
|
484
|
+
)
|
|
485
|
+
return actualBatchMap.resolve()
|
|
486
|
+
},
|
|
487
|
+
writable: true,
|
|
488
|
+
configurable: true,
|
|
489
|
+
})
|
|
461
490
|
|
|
462
491
|
return mapPromise
|
|
463
492
|
}
|
|
@@ -481,7 +510,8 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
481
510
|
await callback(items[i], i)
|
|
482
511
|
}
|
|
483
512
|
} else {
|
|
484
|
-
|
|
513
|
+
// When T is not an array, the conditional type T extends (infer I)[] ? I : T resolves to T
|
|
514
|
+
await callback(items as T extends (infer I)[] ? I : T, 0)
|
|
485
515
|
}
|
|
486
516
|
}
|
|
487
517
|
|
|
@@ -492,10 +522,12 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
492
522
|
const items = await this.resolve()
|
|
493
523
|
if (Array.isArray(items)) {
|
|
494
524
|
for (const item of items) {
|
|
495
|
-
|
|
525
|
+
// Each array item is the inferred element type I when T extends I[]
|
|
526
|
+
yield item as T extends (infer I)[] ? I : T
|
|
496
527
|
}
|
|
497
528
|
} else {
|
|
498
|
-
|
|
529
|
+
// When T is not an array, the item type is T itself
|
|
530
|
+
yield items as T extends (infer I)[] ? I : T
|
|
499
531
|
}
|
|
500
532
|
}
|
|
501
533
|
|
|
@@ -583,28 +615,44 @@ export class AIPromise<T> implements PromiseLike<T> {
|
|
|
583
615
|
// ============================================================================
|
|
584
616
|
|
|
585
617
|
const PROXY_HANDLERS: ProxyHandler<AIPromise<unknown>> = {
|
|
586
|
-
get(target, prop: string | symbol,
|
|
618
|
+
get(target, prop: string | symbol, _receiver) {
|
|
587
619
|
// Handle symbols
|
|
588
620
|
if (typeof prop === 'symbol') {
|
|
589
621
|
if (prop === AI_PROMISE_SYMBOL) return true
|
|
590
622
|
if (prop === RAW_PROMISE_SYMBOL) return target
|
|
591
623
|
if (prop === Symbol.asyncIterator) return target[Symbol.asyncIterator].bind(target)
|
|
592
|
-
return (target as
|
|
624
|
+
return (target as unknown as Record<symbol, unknown>)[prop]
|
|
593
625
|
}
|
|
594
626
|
|
|
595
627
|
// Handle promise methods
|
|
596
628
|
if (prop === 'then' || prop === 'catch' || prop === 'finally') {
|
|
597
|
-
|
|
629
|
+
const method = (target as unknown as Record<string, (...args: unknown[]) => unknown>)[prop]
|
|
630
|
+
return method?.bind(target)
|
|
598
631
|
}
|
|
599
632
|
|
|
600
633
|
// Handle AIPromise methods
|
|
601
|
-
if (
|
|
602
|
-
|
|
634
|
+
if (
|
|
635
|
+
prop === 'map' ||
|
|
636
|
+
prop === 'forEach' ||
|
|
637
|
+
prop === 'resolve' ||
|
|
638
|
+
prop === 'stream' ||
|
|
639
|
+
prop === 'addDependency' ||
|
|
640
|
+
prop === 'mapImmediate' ||
|
|
641
|
+
prop === 'mapDeferred'
|
|
642
|
+
) {
|
|
643
|
+
const method = (target as unknown as Record<string, (...args: unknown[]) => unknown>)[prop]
|
|
644
|
+
return method?.bind(target)
|
|
603
645
|
}
|
|
604
646
|
|
|
605
647
|
// Handle internal properties
|
|
606
|
-
if (
|
|
607
|
-
|
|
648
|
+
if (
|
|
649
|
+
prop.startsWith('_') ||
|
|
650
|
+
prop === 'prompt' ||
|
|
651
|
+
prop === 'path' ||
|
|
652
|
+
prop === 'isResolved' ||
|
|
653
|
+
prop === 'accessedProps'
|
|
654
|
+
) {
|
|
655
|
+
return (target as unknown as Record<string, unknown>)[prop]
|
|
608
656
|
}
|
|
609
657
|
|
|
610
658
|
// Track property access for schema inference
|
|
@@ -616,14 +664,11 @@ const PROXY_HANDLERS: ProxyHandler<AIPromise<unknown>> = {
|
|
|
616
664
|
}
|
|
617
665
|
|
|
618
666
|
// Return a new AIPromise for the property path
|
|
619
|
-
return new AIPromise<unknown>(
|
|
620
|
-
target
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
propertyPath: [...target.path, prop],
|
|
625
|
-
}
|
|
626
|
-
)
|
|
667
|
+
return new AIPromise<unknown>(target.prompt, {
|
|
668
|
+
...target['_options'],
|
|
669
|
+
parent: target,
|
|
670
|
+
propertyPath: [...target.path, prop],
|
|
671
|
+
})
|
|
627
672
|
},
|
|
628
673
|
|
|
629
674
|
// Prevent mutation
|
|
@@ -636,10 +681,11 @@ const PROXY_HANDLERS: ProxyHandler<AIPromise<unknown>> = {
|
|
|
636
681
|
},
|
|
637
682
|
|
|
638
683
|
// Handle function calls (for chained methods)
|
|
639
|
-
apply(target,
|
|
684
|
+
apply(target, _thisArg, args) {
|
|
640
685
|
// If the target is callable (e.g., from a template function), call it
|
|
641
|
-
|
|
642
|
-
|
|
686
|
+
const call = (target as unknown as Record<string, unknown>)['_call']
|
|
687
|
+
if (typeof call === 'function') {
|
|
688
|
+
return (call as (...args: unknown[]) => unknown)(...args)
|
|
643
689
|
}
|
|
644
690
|
throw new Error('AIPromise is not callable')
|
|
645
691
|
},
|
|
@@ -685,10 +731,12 @@ function analyzeRecordingResult(result: unknown, recording: MapRecording): Simpl
|
|
|
685
731
|
// Infer schema from the promise's accessed properties or type
|
|
686
732
|
if (aiPromise.accessedProps.size > 0) {
|
|
687
733
|
schema[key] = Object.fromEntries(
|
|
688
|
-
Array.from(aiPromise.accessedProps).map(p => [p, `The ${p}`])
|
|
734
|
+
Array.from(aiPromise.accessedProps).map((p) => [p, `The ${p}`])
|
|
689
735
|
)
|
|
690
736
|
} else {
|
|
691
|
-
|
|
737
|
+
// Access private _options through type-safe assertion
|
|
738
|
+
const options = (aiPromise as unknown as { _options: AIPromiseOptions })._options
|
|
739
|
+
const type = options?.type
|
|
692
740
|
if (type === 'boolean') {
|
|
693
741
|
schema[key] = 'true | false'
|
|
694
742
|
} else if (type === 'list') {
|
|
@@ -717,7 +765,7 @@ export function isAIPromise(value: unknown): value is AIPromise<unknown> {
|
|
|
717
765
|
value !== null &&
|
|
718
766
|
typeof value === 'object' &&
|
|
719
767
|
AI_PROMISE_SYMBOL in value &&
|
|
720
|
-
(value as
|
|
768
|
+
(value as Record<symbol, unknown>)[AI_PROMISE_SYMBOL] === true
|
|
721
769
|
)
|
|
722
770
|
}
|
|
723
771
|
|
|
@@ -725,10 +773,8 @@ export function isAIPromise(value: unknown): value is AIPromise<unknown> {
|
|
|
725
773
|
* Get the raw AIPromise from a proxied value
|
|
726
774
|
*/
|
|
727
775
|
export function getRawPromise<T>(value: AIPromise<T>): AIPromise<T> {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}
|
|
731
|
-
return value
|
|
776
|
+
const raw = (value as unknown as Record<symbol, AIPromise<T> | undefined>)[RAW_PROMISE_SYMBOL]
|
|
777
|
+
return raw ?? value
|
|
732
778
|
}
|
|
733
779
|
|
|
734
780
|
// ============================================================================
|
|
@@ -745,7 +791,10 @@ export function createTextPromise(prompt: string, options?: FunctionOptions): AI
|
|
|
745
791
|
/**
|
|
746
792
|
* Create an AIPromise for object generation with dynamic schema
|
|
747
793
|
*/
|
|
748
|
-
export function createObjectPromise<T = unknown>(
|
|
794
|
+
export function createObjectPromise<T = unknown>(
|
|
795
|
+
prompt: string,
|
|
796
|
+
options?: FunctionOptions
|
|
797
|
+
): AIPromise<T> {
|
|
749
798
|
return new AIPromise<T>(prompt, { ...options, type: 'object' })
|
|
750
799
|
}
|
|
751
800
|
|
|
@@ -759,21 +808,30 @@ export function createListPromise(prompt: string, options?: FunctionOptions): AI
|
|
|
759
808
|
/**
|
|
760
809
|
* Create an AIPromise for multiple lists generation
|
|
761
810
|
*/
|
|
762
|
-
export function createListsPromise(
|
|
811
|
+
export function createListsPromise(
|
|
812
|
+
prompt: string,
|
|
813
|
+
options?: FunctionOptions
|
|
814
|
+
): AIPromise<Record<string, string[]>> {
|
|
763
815
|
return new AIPromise<Record<string, string[]>>(prompt, { ...options, type: 'lists' })
|
|
764
816
|
}
|
|
765
817
|
|
|
766
818
|
/**
|
|
767
819
|
* Create an AIPromise for boolean/is check
|
|
768
820
|
*/
|
|
769
|
-
export function createBooleanPromise(
|
|
821
|
+
export function createBooleanPromise(
|
|
822
|
+
prompt: string,
|
|
823
|
+
options?: FunctionOptions
|
|
824
|
+
): AIPromise<boolean> {
|
|
770
825
|
return new AIPromise<boolean>(prompt, { ...options, type: 'boolean' })
|
|
771
826
|
}
|
|
772
827
|
|
|
773
828
|
/**
|
|
774
829
|
* Create an AIPromise for extraction
|
|
775
830
|
*/
|
|
776
|
-
export function createExtractPromise<T = unknown>(
|
|
831
|
+
export function createExtractPromise<T = unknown>(
|
|
832
|
+
prompt: string,
|
|
833
|
+
options?: FunctionOptions
|
|
834
|
+
): AIPromise<T[]> {
|
|
777
835
|
return new AIPromise<T[]>(prompt, { ...options, type: 'extract' })
|
|
778
836
|
}
|
|
779
837
|
|
|
@@ -820,15 +878,14 @@ export function createAITemplateFunction<T>(
|
|
|
820
878
|
type: AIPromiseOptions['type'],
|
|
821
879
|
baseOptions?: FunctionOptions
|
|
822
880
|
): ((strings: TemplateStringsArray, ...values: unknown[]) => AIPromise<T>) &
|
|
823
|
-
|
|
824
|
-
|
|
881
|
+
((prompt: string, options?: FunctionOptions) => AIPromise<T>) {
|
|
825
882
|
function templateFn(
|
|
826
883
|
promptOrStrings: string | TemplateStringsArray,
|
|
827
884
|
...args: unknown[]
|
|
828
885
|
): AIPromise<T> {
|
|
829
886
|
let prompt: string
|
|
830
887
|
let dependencies: Dependency[] = []
|
|
831
|
-
let options: FunctionOptions = { ...baseOptions }
|
|
888
|
+
let options: FunctionOptions & { baseSchema?: SimpleSchema } = { ...baseOptions }
|
|
832
889
|
|
|
833
890
|
if (Array.isArray(promptOrStrings) && 'raw' in promptOrStrings) {
|
|
834
891
|
// Tagged template literal
|
|
@@ -845,11 +902,21 @@ export function createAITemplateFunction<T>(
|
|
|
845
902
|
|
|
846
903
|
// If we're in recording mode (inside a .map() callback), capture this operation
|
|
847
904
|
if (isInRecordingMode()) {
|
|
848
|
-
const batchType =
|
|
849
|
-
|
|
905
|
+
const batchType =
|
|
906
|
+
type === 'text'
|
|
907
|
+
? 'text'
|
|
908
|
+
: type === 'boolean'
|
|
909
|
+
? 'boolean'
|
|
910
|
+
: type === 'list'
|
|
911
|
+
? 'list'
|
|
912
|
+
: 'object'
|
|
913
|
+
captureOperation(prompt, batchType, options.baseSchema, options.system)
|
|
850
914
|
}
|
|
851
915
|
|
|
852
|
-
const promise = new AIPromise<T>(prompt, {
|
|
916
|
+
const promise = new AIPromise<T>(prompt, {
|
|
917
|
+
...options,
|
|
918
|
+
...(type !== undefined && { type }),
|
|
919
|
+
})
|
|
853
920
|
|
|
854
921
|
// Add dependencies
|
|
855
922
|
for (const dep of dependencies) {
|
|
@@ -859,7 +926,9 @@ export function createAITemplateFunction<T>(
|
|
|
859
926
|
return promise
|
|
860
927
|
}
|
|
861
928
|
|
|
862
|
-
|
|
929
|
+
// Return type matches the declared intersection type
|
|
930
|
+
return templateFn as ((strings: TemplateStringsArray, ...values: unknown[]) => AIPromise<T>) &
|
|
931
|
+
((prompt: string, options?: FunctionOptions) => AIPromise<T>)
|
|
863
932
|
}
|
|
864
933
|
|
|
865
934
|
// ============================================================================
|
|
@@ -880,8 +949,8 @@ function createStreamingAIPromise<T>(
|
|
|
880
949
|
options?: StreamOptions
|
|
881
950
|
): StreamingAIPromise<T> {
|
|
882
951
|
const rawPromise = getRawPromise(promise)
|
|
883
|
-
const promiseOptions = (rawPromise as
|
|
884
|
-
const dependencies = (rawPromise as
|
|
952
|
+
const promiseOptions = (rawPromise as unknown as { _options: AIPromiseOptions })._options
|
|
953
|
+
const dependencies = (rawPromise as unknown as { _dependencies: Dependency[] })._dependencies
|
|
885
954
|
|
|
886
955
|
// Result promise state
|
|
887
956
|
let resultResolve: (value: T) => void
|
|
@@ -910,10 +979,7 @@ function createStreamingAIPromise<T>(
|
|
|
910
979
|
|
|
911
980
|
let finalPrompt = rawPromise.prompt
|
|
912
981
|
for (const [key, value] of Object.entries(resolvedDeps)) {
|
|
913
|
-
finalPrompt = finalPrompt.replace(
|
|
914
|
-
new RegExp(`\\$\\{${key}\\}`, 'g'),
|
|
915
|
-
String(value)
|
|
916
|
-
)
|
|
982
|
+
finalPrompt = finalPrompt.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), String(value))
|
|
917
983
|
}
|
|
918
984
|
|
|
919
985
|
return finalPrompt
|
|
@@ -921,7 +987,7 @@ function createStreamingAIPromise<T>(
|
|
|
921
987
|
|
|
922
988
|
// Build schema from accessed properties
|
|
923
989
|
const buildSchema = (): SimpleSchema => {
|
|
924
|
-
return (rawPromise as
|
|
990
|
+
return (rawPromise as unknown as { _buildSchema: () => SimpleSchema })._buildSchema()
|
|
925
991
|
}
|
|
926
992
|
|
|
927
993
|
// Extract value based on type (same logic as resolve())
|
|
@@ -930,16 +996,31 @@ function createStreamingAIPromise<T>(
|
|
|
930
996
|
// 2. The type parameter T corresponds to the expected output type for each mode
|
|
931
997
|
const extractFinalValue = (obj: unknown): T => {
|
|
932
998
|
let value = obj as T
|
|
933
|
-
if (
|
|
999
|
+
if (
|
|
1000
|
+
promiseOptions.type === 'text' &&
|
|
1001
|
+
typeof value === 'object' &&
|
|
1002
|
+
value !== null &&
|
|
1003
|
+
'text' in value
|
|
1004
|
+
) {
|
|
934
1005
|
value = (value as { text: T }).text
|
|
935
|
-
} else if (
|
|
1006
|
+
} else if (
|
|
1007
|
+
promiseOptions.type === 'boolean' &&
|
|
1008
|
+
typeof value === 'object' &&
|
|
1009
|
+
value !== null &&
|
|
1010
|
+
'answer' in value
|
|
1011
|
+
) {
|
|
936
1012
|
const answer = (value as { answer: string | boolean }).answer
|
|
937
1013
|
// When type === 'boolean', T is constrained to boolean at the call site.
|
|
938
1014
|
// TypeScript can't express this dependent relationship, so we use a simple cast.
|
|
939
1015
|
// Runtime validation: answer is verified to be 'true', 'false', or boolean.
|
|
940
1016
|
const booleanValue = answer === 'true' || answer === true
|
|
941
1017
|
value = booleanValue as T
|
|
942
|
-
} else if (
|
|
1018
|
+
} else if (
|
|
1019
|
+
(promiseOptions.type === 'list' || promiseOptions.type === 'extract') &&
|
|
1020
|
+
typeof value === 'object' &&
|
|
1021
|
+
value !== null &&
|
|
1022
|
+
'items' in value
|
|
1023
|
+
) {
|
|
943
1024
|
value = (value as { items: T }).items
|
|
944
1025
|
}
|
|
945
1026
|
return value
|
|
@@ -968,10 +1049,12 @@ function createStreamingAIPromise<T>(
|
|
|
968
1049
|
const result = await streamText({
|
|
969
1050
|
model: promiseOptions.model || 'sonnet',
|
|
970
1051
|
prompt: finalPrompt,
|
|
971
|
-
system: promiseOptions.system,
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1052
|
+
...(promiseOptions.system !== undefined && { system: promiseOptions.system }),
|
|
1053
|
+
...(promiseOptions.temperature !== undefined && {
|
|
1054
|
+
temperature: promiseOptions.temperature,
|
|
1055
|
+
}),
|
|
1056
|
+
...(promiseOptions.maxTokens !== undefined && { maxTokens: promiseOptions.maxTokens }),
|
|
1057
|
+
...(options?.abortSignal !== undefined && { abortSignal: options.abortSignal }),
|
|
975
1058
|
})
|
|
976
1059
|
|
|
977
1060
|
let fullText = ''
|
|
@@ -1015,10 +1098,12 @@ function createStreamingAIPromise<T>(
|
|
|
1015
1098
|
model: promiseOptions.model || 'sonnet',
|
|
1016
1099
|
schema,
|
|
1017
1100
|
prompt: finalPrompt,
|
|
1018
|
-
system: promiseOptions.system,
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1101
|
+
...(promiseOptions.system !== undefined && { system: promiseOptions.system }),
|
|
1102
|
+
...(promiseOptions.temperature !== undefined && {
|
|
1103
|
+
temperature: promiseOptions.temperature,
|
|
1104
|
+
}),
|
|
1105
|
+
...(promiseOptions.maxTokens !== undefined && { maxTokens: promiseOptions.maxTokens }),
|
|
1106
|
+
...(options?.abortSignal !== undefined && { abortSignal: options.abortSignal }),
|
|
1022
1107
|
})
|
|
1023
1108
|
|
|
1024
1109
|
let lastPartial: Partial<T> = {} as Partial<T>
|
|
@@ -1041,7 +1126,8 @@ function createStreamingAIPromise<T>(
|
|
|
1041
1126
|
async function* createMainStream(): AsyncGenerator<T extends string ? string : Partial<T>> {
|
|
1042
1127
|
if (promiseOptions.type === 'text') {
|
|
1043
1128
|
for await (const chunk of createTextStream()) {
|
|
1044
|
-
|
|
1129
|
+
// When type is 'text', T is string, so the conditional type resolves to string
|
|
1130
|
+
yield chunk as T extends string ? string : Partial<T>
|
|
1045
1131
|
}
|
|
1046
1132
|
} else if (promiseOptions.type === 'list') {
|
|
1047
1133
|
// For lists, yield new items as they appear
|
|
@@ -1049,13 +1135,15 @@ function createStreamingAIPromise<T>(
|
|
|
1049
1135
|
for await (const partial of createPartialObjectStream()) {
|
|
1050
1136
|
const items = (partial as { items?: string[] }).items || []
|
|
1051
1137
|
for (let i = lastLength; i < items.length; i++) {
|
|
1052
|
-
|
|
1138
|
+
// List items are strings, cast to the conditional return type
|
|
1139
|
+
yield items[i] as T extends string ? string : Partial<T>
|
|
1053
1140
|
}
|
|
1054
1141
|
lastLength = items.length
|
|
1055
1142
|
}
|
|
1056
1143
|
} else {
|
|
1057
1144
|
for await (const partial of createPartialObjectStream()) {
|
|
1058
|
-
|
|
1145
|
+
// For object types, T is not string, so conditional type resolves to Partial<T>
|
|
1146
|
+
yield partial as T extends string ? string : Partial<T>
|
|
1059
1147
|
}
|
|
1060
1148
|
}
|
|
1061
1149
|
}
|
|
@@ -1089,28 +1177,26 @@ function createStreamingAIPromise<T>(
|
|
|
1089
1177
|
}
|
|
1090
1178
|
|
|
1091
1179
|
// Create a lazy result promise that starts streaming when accessed
|
|
1092
|
-
const lazyResult: Promise<T> & { _started?: boolean } = Object.assign(
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
)
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
)
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
}
|
|
1113
|
-
) as Promise<T> & { _started?: boolean }
|
|
1180
|
+
const lazyResult: Promise<T> & { _started?: boolean } = Object.assign({
|
|
1181
|
+
then<TResult1 = T, TResult2 = never>(
|
|
1182
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
|
1183
|
+
onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null
|
|
1184
|
+
): Promise<TResult1 | TResult2> {
|
|
1185
|
+
ensureStreamStarted()
|
|
1186
|
+
return resultPromise.then(onfulfilled, onrejected)
|
|
1187
|
+
},
|
|
1188
|
+
catch<TResult = never>(
|
|
1189
|
+
onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null
|
|
1190
|
+
): Promise<T | TResult> {
|
|
1191
|
+
ensureStreamStarted()
|
|
1192
|
+
return resultPromise.catch(onrejected)
|
|
1193
|
+
},
|
|
1194
|
+
finally(onfinally?: (() => void) | null): Promise<T> {
|
|
1195
|
+
ensureStreamStarted()
|
|
1196
|
+
return resultPromise.finally(onfinally)
|
|
1197
|
+
},
|
|
1198
|
+
[Symbol.toStringTag]: 'Promise' as const,
|
|
1199
|
+
}) as Promise<T> & { _started?: boolean }
|
|
1114
1200
|
|
|
1115
1201
|
// Create the streaming object
|
|
1116
1202
|
const streamingPromise: StreamingAIPromise<T> = {
|