@tanstack/ai
Version:
Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.
47 lines (46 loc) • 3.29 kB
TypeScript
import { CapabilityHandle } from './capabilities.js';
import { AnyChatMiddleware } from './types.js';
import { DefinedChatMiddleware } from './define.js';
/** Union of capability NAME literals from a tuple of handles. */
export type NamesOf<T extends ReadonlyArray<CapabilityHandle>> = T[number]['capabilityName'];
/** Names provided across a middleware array (imprecise middleware → `string`). */
export type ProvidedNames<TList extends ReadonlyArray<AnyChatMiddleware>> = NonNullable<TList[number]['provides']> extends infer P ? P extends ReadonlyArray<CapabilityHandle> ? NamesOf<P> : never : never;
/** Names required across a middleware array. */
export type RequiredNames<TList extends ReadonlyArray<AnyChatMiddleware>> = NonNullable<TList[number]['requires']> extends infer P ? P extends ReadonlyArray<CapabilityHandle> ? NamesOf<P> : never : never;
/**
* Branded marker surfaced when required capability names are missing from the
* provided set, so the compiler error names the gap instead of emitting an
* opaque "not assignable".
*/
export type MissingCapabilities<TMissing extends string> = {
[K in `✖ Missing capability "${TMissing}": no configured middleware provides it. Add a middleware whose \`provides\` includes it (and, with createChatMiddleware().use(), order the provider before this consumer).`]: never;
};
/**
* Missing capability names. When required names are imprecise (`string`, i.e.
* plain `ChatMiddleware` not authored via `defineChatMiddleware`), we cannot
* prove a gap, so we allow it (→ `never`). Otherwise the precise literals not
* present in the provided set.
*/
type MissingNames<TList extends ReadonlyArray<AnyChatMiddleware>> = string extends RequiredNames<TList> ? never : Exclude<RequiredNames<TList>, ProvidedNames<TList>>;
/**
* Resolves to `TList` when coverage holds, otherwise to a `MissingCapabilities`
* marker (not assignable to a middleware array) — producing a compile error at
* the `middleware` option that names the missing capability.
*/
export type CheckCoverage<TList extends ReadonlyArray<AnyChatMiddleware>> = [
MissingNames<TList>
] extends [never] ? TList : MissingCapabilities<MissingNames<TList>>;
/**
* Order-aware middleware builder. Each `.use()` requires that the middleware's
* required capability names are already in the accumulated provided set, then
* adds its provided names. `.build()` returns the ordered array.
*
* `TProvided` is the running union of provided capability name literals.
*/
export interface ChatMiddlewareBuilder<TList extends ReadonlyArray<AnyChatMiddleware>, TProvided extends string> {
use: <TRequires extends ReadonlyArray<CapabilityHandle>, TProvides extends ReadonlyArray<CapabilityHandle>, TContext = unknown>(middleware: [NamesOf<TRequires>] extends [TProvided] ? DefinedChatMiddleware<TContext, TRequires, TProvides> : DefinedChatMiddleware<TContext, TRequires, TProvides> & MissingCapabilities<Exclude<NamesOf<TRequires>, TProvided>>) => ChatMiddlewareBuilder<readonly [...TList, DefinedChatMiddleware<TContext, TRequires, TProvides>], TProvided | NamesOf<TProvides>>;
build: () => [...TList];
}
/** Create an order-aware middleware builder. */
export declare function createChatMiddleware(): ChatMiddlewareBuilder<readonly [], never>;
export {};