UNPKG

@tanstack/ai

Version:

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

256 lines (255 loc) 9.12 kB
import { DebugOption } from '../../logger/types.js'; import { TokenUsage } from '../../types.js'; import { GenerationMiddleware } from '../middleware/types.js'; import { EvaluateAdapter, EvaluateInstructions, EvaluateState, WireQuestion } from './adapter.js'; /** The adapter kind this activity handles */ export declare const kind: "evaluate"; /** Question key reserved for `result.meta`. */ declare const RESERVED_QUESTION_KEY: "meta"; /** Extract provider options from an EvaluateAdapter via ~types */ export type EvaluateProviderOptions<TAdapter> = TAdapter extends { '~types': { providerOptions: infer P extends object; }; } ? P : object; /** * Public choice answer. `.value` is the selected option key. */ export interface ChoiceAnswer<TValue extends string = string> { type: 'choice'; value: TValue; /** P(selected option). */ probability: number; confidence: number; probabilities: Record<TValue, number>; } /** * Public score answer. `.value` is the nearest level label. * `.score` is the raw TypeSafe fraction. */ export interface ScoreAnswer<TLevel extends string = string> { type: 'score'; value: TLevel; /** P(nearest level). */ probability: number; confidence: number; score: number; legend: Record<string, string>; probabilities: Record<string, number>; } /** * Public yes/no answer. `.value` is `true` when P(true) is 0.5 or more. * There is no `.confidence`. */ export interface BooleanAnswer { type: 'boolean'; value: boolean; /** P(true), from the wire `noul` field. */ probability: number; } export interface EvaluateResultMeta { /** Resolved model id from the provider. */ model: string; usage: TokenUsage; } /** * Map a helper question (or wire question) to its public answer type. */ export type InferEvaluateAnswer<TQuestion> = TQuestion extends { type: 'choice'; criteria: infer TCriteria; } ? TCriteria extends Record<string, string | null> ? ChoiceAnswer<Extract<keyof TCriteria, string>> : ChoiceAnswer : TQuestion extends { type: 'score'; criteria: infer TLevels; } ? TLevels extends ReadonlyArray<string> ? ScoreAnswer<TLevels[number] & string> : ScoreAnswer : TQuestion extends { type: 'noul'; } ? BooleanAnswer : never; /** * Result of `decide()`. Each question key is a top-level answer. * `meta` holds the resolved model id and usage. */ export type EvaluateResult<TQuestions extends Record<string, WireQuestion>> = { [K in keyof TQuestions as K extends typeof RESERVED_QUESTION_KEY ? never : K]: InferEvaluateAnswer<TQuestions[K]>; } & { meta: EvaluateResultMeta; }; /** * Options for the evaluate activity. The model is extracted from the * adapter's model property. * * @template TAdapter - The evaluate adapter type * @template TQuestions - The questions object passed to `decide` */ export interface EvaluateActivityOptions<TAdapter extends EvaluateAdapter<string, EvaluateProviderOptions<TAdapter>>, TQuestions extends Record<string, WireQuestion>> { /** The evaluate adapter to use (must be created with a model) */ adapter: TAdapter & { kind: typeof kind; }; /** Shared state every question judges. A JSON array is one state, not a batch. */ state: EvaluateState; /** * Questions built with `choice`, `score`, and `boolean`. * The key `meta` is reserved. */ questions: TQuestions; /** Provider-specific options */ modelOptions?: EvaluateProviderOptions<TAdapter>; /** Forwarded to the provider request for cancellation. */ abortSignal?: AbortSignal; /** * Observe-only middleware notified on start, usage, success, abort, and * error. Pass `otelMiddleware()` to emit OpenTelemetry spans, or implement * the `GenerationMiddleware` contract for a custom backend. */ middleware?: Array<GenerationMiddleware>; /** * Enable debug logging. Pass `true` to enable all categories, `false` to * silence everything including errors, or a `DebugConfig` object for granular * control and/or a custom `Logger`. */ debug?: DebugOption; } /** * Build a choice question. The model picks one key from `options`. * * Option keys become the union on `.value`. Use `null` when a key needs no * extra description. On the wire, `options` is sent as TypeSafe `criteria`. * * @param options.instructions What the model should decide. * @param options.options Map of option key to description, or `null`. * * @example * ```ts * const queue = choice({ * instructions: 'Which team should handle this ticket?', * options: { * billing: 'Payments, invoices, refunds', * tech: 'Bugs, outages, integrations', * sales: 'Pricing, upgrades, new accounts', * }, * }) * ``` */ export declare function choice<const TOptions extends Record<string, string | null>>(options: { instructions: EvaluateInstructions; options: TOptions; }): { type: "choice"; instructions: import('./adapter.js').EvaluateJsonValue; criteria: TOptions; }; /** * Build a score question. The model rates `state` on ordered `levels`. * * You must pass at least two levels. `.value` is the nearest level label. * The raw fraction stays on `.score`. On the wire, `levels` is sent as * TypeSafe `criteria`. * * @param options.instructions What the model should rate. * @param options.levels Ordered labels, lowest first. At least two. * * @example * ```ts * const urgency = score({ * instructions: 'How urgent is this ticket?', * levels: ['low', 'medium', 'high'], * }) * ``` */ export declare function score<const TLevels extends ReadonlyArray<string>>(options: { instructions: EvaluateInstructions; levels: TLevels; }): { type: "score"; instructions: import('./adapter.js').EvaluateJsonValue; criteria: TLevels; }; /** * Build a yes/no question. * * `.value` is `true` when P(true) is 0.5 or more. There is no `.confidence`. * On the wire, the type is TypeSafe `noul`. * * @param options.instructions The yes/no question to judge. * @param options.criteria Optional descriptions of yes and no. * * @example * ```ts * const refund = boolean({ * instructions: 'Is the customer asking for a refund?', * }) * ``` */ export declare function boolean(options: { instructions: EvaluateInstructions; criteria?: { true?: string; false?: string; }; }): { type: "noul"; instructions: import('./adapter.js').EvaluateJsonValue; criteria?: undefined; } | { type: "noul"; instructions: import('./adapter.js').EvaluateJsonValue; criteria: { true?: string; false?: string; }; }; /** * Ask typed questions about `state` and get answers your code can branch on. * * You have state (a ticket, a record, a log) and you need typed answers, not * prose. Pass questions built with `choice`, `score`, and `boolean`. Then * branch on `result.queue.value` in ordinary TypeScript. * * The question key `meta` is reserved. Throws if `questions` is empty or uses * that key. * * @param options.adapter Evaluate adapter created with a model. * @param options.state Shared state every question judges. * @param options.questions Questions built with `choice`, `score`, `boolean`. * @param options.modelOptions Provider-specific options. * @param options.abortSignal Cancels the in-flight request. * @param options.middleware Observe-only generation middleware. * @param options.debug Debug logging option. * * @example Route a support ticket * ```ts * import { decide, choice, score, boolean } from '@tanstack/ai' * import { typesafeDecider } from '@tanstack/ai-typesafe' * * const result = await decide({ * adapter: typesafeDecider('jev-latest'), * state: ticket, * questions: { * queue: choice({ * instructions: 'Which team should handle this ticket?', * options: { * billing: 'Payments, invoices, refunds', * tech: 'Bugs, outages, integrations', * sales: 'Pricing, upgrades, new accounts', * }, * }), * urgency: score({ * instructions: 'How urgent is this ticket?', * levels: ['low', 'medium', 'high'], * }), * refund: boolean({ * instructions: 'Is the customer asking for a refund?', * }), * }, * }) * * result.queue.value * result.meta.model * result.meta.usage * ``` */ export declare function decide<TAdapter extends EvaluateAdapter<string, EvaluateProviderOptions<TAdapter>>, TQuestions extends Record<string, WireQuestion>>(options: EvaluateActivityOptions<TAdapter, TQuestions>): Promise<{ [K in keyof TQuestions]: InferEvaluateAnswer<TQuestions[K]>; } & { meta: EvaluateResultMeta; }>; export type { EvaluateAdapter, EvaluateAdapterConfig, AnyEvaluateAdapter, EvaluateOptions, EvaluateAdapterResult, EvaluateState, EvaluateInstructions, EvaluateJsonValue, WireQuestion, WireAnswer, WireChoiceQuestion, WireScoreQuestion, WireNoulQuestion, WireChoiceAnswer, WireScoreAnswer, WireNoulAnswer, } from './adapter.js'; export { BaseEvaluateAdapter } from './adapter.js';