UNPKG

@tanstack/ai

Version:

Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.

94 lines (93 loc) 4.05 kB
/** Options accepted by a capability getter. */ export interface CapabilityGetOptions { /** When true, return undefined instead of throwing if the capability is absent. */ optional?: boolean; } /** * The minimal context shape a capability accessor needs. The full * `ChatMiddlewareContext` satisfies this (it has `capabilities`), so accessors * accept any middleware context without referencing `any`. */ export interface CapabilityContext { capabilities: CapabilityRegistry; } /** Reads a capability value off a context. Overloaded so the flag narrows the return. */ export interface CapabilityGetter<TValue> { (ctx: CapabilityContext): TValue; (ctx: CapabilityContext, opts: { optional: true; }): TValue | undefined; } /** Writes a capability value onto a context. */ export type CapabilityProvider<TValue> = (ctx: CapabilityContext, value: TValue) => void; /** * A capability handle. It is BOTH a `[get, provide]` tuple (array-destructurable) * AND the identity used in middleware `requires`/`provides` declarations. * * Runtime identity is this object's reference. The `capabilityName` literal is * used for diagnostics and COMPILE-TIME tracking only — capability names MUST be * unique across an app or the type-level coverage check conflates them. */ export type Capability<TValue = unknown, TName extends string = string> = readonly [ get: CapabilityGetter<TValue>, provide: CapabilityProvider<TValue> ] & { readonly capabilityName: TName; /** @internal Presence check for the post-setup assertion. */ has: (ctx: CapabilityContext) => boolean; }; /** * A capability handle with permissive value/name — for use as a constraint in * `requires`/`provides` arrays. Concentrates `any` in one named alias (same * convention as `AnyTextAdapter`/`AnyTool`); needed so `Capability<SpecificT>` * is assignable to the handle-array element type. */ export type CapabilityHandle = Capability<any, string>; /** * Per-request bookkeeping: which capabilities were provided, plus the * duplicate-provide notification. Capability VALUES live in per-capability * WeakMaps (see `createCapability`), not here — this only tracks presence. */ export declare class CapabilityRegistry { private readonly provided; private onDuplicate?; /** Register a callback fired when a handle is provided more than once. */ setOnDuplicate(cb: (name: string) => void): void; /** Record that `handle` was provided; fire the duplicate callback on repeats. */ markProvided(handle: CapabilityHandle): void; has(handle: CapabilityHandle): boolean; } /** * Create a capability. Returns a hybrid handle that destructures to * `[get, provide]` and is itself the identity for `requires`/`provides`. * * Curried so the value type is supplied explicitly while the name literal is * INFERRED from the argument: `createCapability<T>()('name')`. (A single call * `createCapability<T>('name')` cannot work — supplying `T` explicitly stops * TypeScript inferring the name, collapsing it to `string` and defeating the * compile-time coverage check that keys on the literal name.) * * @example Provider + consumer middleware * ```ts * const counterCapability = createCapability<{ value: number }>()('counter') * const [getCounter, provideCounter] = counterCapability * * const withCounter = defineChatMiddleware({ * name: 'counter', * provides: [counterCapability], * setup(ctx) { provideCounter(ctx, { value: 0 }) }, * }) * * const readsCounter = defineChatMiddleware({ * name: 'reads-counter', * requires: [counterCapability], * onChunk(ctx) { getCounter(ctx).value++ }, * }) * * chat({ adapter, messages, middleware: [withCounter, readsCounter] }) * ``` * * @remarks Capability `name`s must be unique across your app: compile-time * coverage tracking keys on the name literal (runtime keys on reference). */ export declare function createCapability<TValue = unknown>(): <const TName extends string>(name: TName) => Capability<TValue, TName>;