ai-functions
Version:
Core AI primitives for building intelligent applications
266 lines • 9.81 kB
TypeScript
/**
* 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