UNPKG

ai-functions

Version:

Core AI primitives for building intelligent applications

266 lines 9.81 kB
/** * AIPromise - Promise pipelining for AI functions * * This enables: * - Property access tracking for dynamic schema inference * - Promise pipelining without await * - Magical .map() for batch processing * - Dependency graph resolution * * @example * ```ts * // Dynamic schema from destructuring * const { summary, keyPoints, conclusion } = ai`write about ${topic}` * * // Pipeline without await * const isValid = is`${conclusion} is solid given ${keyPoints}` * * // Batch process with map * const ideas = list`startup ideas` * const evaluated = await ideas.map(idea => ({ * idea, * viable: is`${idea} is viable`, * market: ai`market size for ${idea}`, * })) * * // Only await at the end * if (await isValid) { ... } * ``` * * @packageDocumentation */ import type { SimpleSchema } from './schema.js'; import type { FunctionOptions } from './template.js'; import { BatchMapPromise } from './batch-map.js'; /** * Options for streaming */ export interface StreamOptions { /** Abort signal for cancellation */ abortSignal?: AbortSignal; } /** * Streaming result wrapper that provides both AsyncIterable interface * and access to the final result */ export interface StreamingAIPromise<T> extends AsyncIterable<T extends string ? string : Partial<T>> { /** Stream of text chunks (for text generation) */ textStream: AsyncIterable<string>; /** Stream of partial objects (for object generation) */ partialObjectStream: AsyncIterable<Partial<T>>; /** Promise that resolves to the final complete result */ result: Promise<T>; /** Promise interface - then() */ then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>; } /** Symbol to identify AIPromise instances */ export declare const AI_PROMISE_SYMBOL: unique symbol; /** Symbol to get the raw AIPromise from a proxy */ export declare const RAW_PROMISE_SYMBOL: unique symbol; /** Recording mode for map() */ export declare const RECORDING_MODE: unique symbol; /** Dependency tracking */ interface Dependency { promise: AIPromise<unknown>; path: string[]; } /** Options for AIPromise creation */ export interface AIPromiseOptions extends FunctionOptions { /** The type of generation */ type?: 'text' | 'object' | 'list' | 'lists' | 'boolean' | 'extract'; /** Base schema (can be extended by property access) */ baseSchema?: SimpleSchema; /** Parent promise this was derived from */ parent?: AIPromise<unknown>; /** Property path from parent */ propertyPath?: string[]; } /** * AIPromise - Promise wrapper for AI functions * * Acts as both a Promise AND a stub that: * - Tracks property accesses for dynamic schema inference * - Records dependencies for promise pipelining * - Supports .map() for batch processing */ export declare class AIPromise<T> implements PromiseLike<T> { /** Marker to identify AIPromise instances */ readonly [AI_PROMISE_SYMBOL] = true; /** The prompt that will generate this value */ private _prompt; /** Options for generation */ private _options; /** Properties accessed on this promise (for schema inference) */ private _accessedProps; /** Property path from parent (for nested access) */ private _propertyPath; /** Parent promise (if this is a property access) */ private _parent; /** Dependencies (other AIPromises used in our prompt) */ private _dependencies; /** Cached resolver promise */ private _resolver; /** Resolved value (cached after first resolution) */ private _resolvedValue; /** Whether this promise has been resolved */ private _isResolved; /** Whether we're in recording mode */ private _isRecording; constructor(prompt: string, options?: AIPromiseOptions); /** Get the prompt */ get prompt(): string; /** Get the property path */ get path(): string[]; /** Check if resolved */ get isResolved(): boolean; /** Get accessed properties */ get accessedProps(): Set<string>; /** * Add a dependency (another AIPromise used in this one's prompt) */ addDependency(promise: AIPromise<unknown>, path?: string[]): void; /** * Resolve this promise */ resolve(): Promise<T>; /** * Build schema from accessed properties and base schema */ private _buildSchema; /** * Map over array results - automatically batches operations! * * When you map over a list, the operations are captured and * automatically batched when resolved. Uses provider batch APIs * for cost savings (50% discount) when beneficial. * * @example * ```ts * // Simple map - each title becomes a blog post * const titles = await list`10 blog post titles` * const posts = titles.map(title => write`blog post: # ${title}`) * console.log(await posts) // 10 blog posts via batch API * * // Complex map - multiple operations per item * const ideas = await list`startup ideas` * const evaluated = await ideas.map(idea => ({ * idea, * viable: is`${idea} is viable`, * market: ai`market size for ${idea}`, * })) * ``` */ map<U>(callback: (item: T extends (infer I)[] ? I : T, index: number) => U): BatchMapPromise<U>; /** * Map with explicit batch options * * @example * ```ts * // Force immediate execution (no batch API) * const posts = titles.mapImmediate(title => write`blog post: ${title}`) * * // Force batch API (even for small lists) * const posts = titles.mapDeferred(title => write`blog post: ${title}`) * ``` */ mapImmediate<U>(callback: (item: T extends (infer I)[] ? I : T, index: number) => U): BatchMapPromise<U>; mapDeferred<U>(callback: (item: T extends (infer I)[] ? I : T, index: number) => U): BatchMapPromise<U>; /** * ForEach with automatic batching * * @example * ```ts * await list`startup ideas`.forEach(async idea => { * console.log(await is`${idea} is viable`) * }) * ``` */ forEach(callback: (item: T extends (infer I)[] ? I : T, index: number) => void | Promise<void>): Promise<void>; /** * Async iterator support with smart batching */ [Symbol.asyncIterator](): AsyncIterator<T extends (infer I)[] ? I : T>; /** * Stream the AI generation - returns chunks as they arrive * * For text generation, yields string chunks. * For object generation, yields partial objects as they build up. * For list generation, yields items as they're generated. * * @example * ```ts * // Text streaming * const stream = write`Write a story`.stream() * for await (const chunk of stream.textStream) { * process.stdout.write(chunk) * } * * // Object streaming with partial updates * const stream = ai`Generate a recipe`.stream() * for await (const partial of stream.partialObjectStream) { * console.log('Building:', partial) * } * * // Get final result after streaming * const finalResult = await stream.result * ``` */ stream(options?: StreamOptions): StreamingAIPromise<T>; /** * Promise interface - then() */ then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>; /** * Promise interface - catch() */ catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<T | TResult>; /** * Promise interface - finally() */ finally(onfinally?: (() => void) | null): Promise<T>; } /** * Check if a value is an AIPromise */ export declare function isAIPromise(value: unknown): value is AIPromise<unknown>; /** * Get the raw AIPromise from a proxied value */ export declare function getRawPromise<T>(value: AIPromise<T>): AIPromise<T>; /** * Create an AIPromise for text generation */ export declare function createTextPromise(prompt: string, options?: FunctionOptions): AIPromise<string>; /** * Create an AIPromise for object generation with dynamic schema */ export declare function createObjectPromise<T = unknown>(prompt: string, options?: FunctionOptions): AIPromise<T>; /** * Create an AIPromise for list generation */ export declare function createListPromise(prompt: string, options?: FunctionOptions): AIPromise<string[]>; /** * Create an AIPromise for multiple lists generation */ export declare function createListsPromise(prompt: string, options?: FunctionOptions): AIPromise<Record<string, string[]>>; /** * Create an AIPromise for boolean/is check */ export declare function createBooleanPromise(prompt: string, options?: FunctionOptions): AIPromise<boolean>; /** * Create an AIPromise for extraction */ export declare function createExtractPromise<T = unknown>(prompt: string, options?: FunctionOptions): AIPromise<T[]>; /** * Parse template literals and track AIPromise dependencies */ export declare function parseTemplateWithDependencies(strings: TemplateStringsArray, ...values: unknown[]): { prompt: string; dependencies: Dependency[]; }; /** * Create a template function that returns AIPromise */ export declare function createAITemplateFunction<T>(type: AIPromiseOptions['type'], baseOptions?: FunctionOptions): ((strings: TemplateStringsArray, ...values: unknown[]) => AIPromise<T>) & ((prompt: string, options?: FunctionOptions) => AIPromise<T>); export {}; //# sourceMappingURL=ai-promise.d.ts.map