UNPKG

@ai-sdk/rsc

Version:

[React Server Components](https://react.dev/reference/rsc/server-components) for the [AI SDK](https://ai-sdk.dev/docs):

383 lines (371 loc) 14.7 kB
import { LanguageModelV2 } from '@ai-sdk/provider'; import { ProviderOptions, InferSchema } from '@ai-sdk/provider-utils'; import { ReactNode } from 'react'; import * as z3 from 'zod/v3'; import * as z4 from 'zod/v4'; import { Schema, CallSettings, Prompt, ToolChoice, FinishReason, LanguageModelUsage, CallWarning } from 'ai'; type JSONValue = string | number | boolean | JSONObject | JSONArray; interface JSONObject { [x: string]: JSONValue; } interface JSONArray extends Array<JSONValue> { } type AIAction<T = any, R = any> = (...args: T[]) => Promise<R>; type AIActions<T = any, R = any> = Record<string, AIAction<T, R>>; type ServerWrappedAction<T = unknown> = (aiState: T, ...args: unknown[]) => Promise<[Promise<T>, unknown]>; type ServerWrappedActions<T = unknown> = Record<string, ServerWrappedAction<T>>; type InternalAIProviderProps<AIState = any, UIState = any> = { children: React.ReactNode; initialUIState: UIState; initialAIState: AIState; initialAIStatePatch: undefined | Promise<AIState>; wrappedActions: ServerWrappedActions<AIState>; wrappedSyncUIState?: ServerWrappedAction<AIState>; }; type AIProviderProps<AIState = any, UIState = any, Actions = any> = { children: React.ReactNode; initialAIState?: AIState; initialUIState?: UIState; /** $ActionTypes is only added for type inference and is never used at runtime **/ $ActionTypes?: Actions; }; type AIProvider<AIState = any, UIState = any, Actions = any> = (props: AIProviderProps<AIState, UIState, Actions>) => Promise<React.ReactElement>; type InferAIState<T, Fallback> = T extends AIProvider<infer AIState, any, any> ? AIState : Fallback; type InferUIState<T, Fallback> = T extends AIProvider<any, infer UIState, any> ? UIState : Fallback; type InferActions<T, Fallback> = T extends AIProvider<any, any, infer Actions> ? Actions : Fallback; type InternalAIStateStorageOptions = { onSetAIState?: OnSetAIState<any>; }; type OnSetAIState<S> = ({ key, state, done, }: { key: string | number | symbol | undefined; state: S; done: boolean; }) => void | Promise<void>; type OnGetUIState<S> = AIAction<void, S | undefined>; type ValueOrUpdater<T> = T | ((current: T) => T); type MutableAIState<AIState> = { get: () => AIState; update: (newState: ValueOrUpdater<AIState>) => void; done: ((newState: AIState) => void) | (() => void); }; /** * Get the current AI state. * If `key` is provided, it will return the value of the specified key in the * AI state, if it's an object. If it's not an object, it will throw an error. * * @example const state = getAIState() // Get the entire AI state * @example const field = getAIState('key') // Get the value of the key */ declare function getAIState<AI extends AIProvider = any>(): Readonly<InferAIState<AI, any>>; declare function getAIState<AI extends AIProvider = any>(key: keyof InferAIState<AI, any>): Readonly<InferAIState<AI, any>[typeof key]>; /** * Get the mutable AI state. Note that you must call `.done()` when finishing * updating the AI state. * * @example * ```tsx * const state = getMutableAIState() * state.update({ ...state.get(), key: 'value' }) * state.update((currentState) => ({ ...currentState, key: 'value' })) * state.done() * ``` * * @example * ```tsx * const state = getMutableAIState() * state.done({ ...state.get(), key: 'value' }) // Done with a new state * ``` */ declare function getMutableAIState<AI extends AIProvider = any>(): MutableAIState<InferAIState<AI, any>>; declare function getMutableAIState<AI extends AIProvider = any>(key: keyof InferAIState<AI, any>): MutableAIState<InferAIState<AI, any>[typeof key]>; declare function createAI<AIState = any, UIState = any, Actions extends AIActions = {}>({ actions, initialAIState, initialUIState, onSetAIState, onGetUIState, }: { actions: Actions; initialAIState?: AIState; initialUIState?: UIState; /** * This function is called whenever the AI state is updated by an Action. * You can use this to persist the AI state to a database, or to send it to a * logging service. */ onSetAIState?: OnSetAIState<AIState>; /** * This function is used to retrieve the UI state based on the AI state. * For example, to render the initial UI state based on a given AI state, or * to sync the UI state when the application is already loaded. * * If returning `undefined`, the client side UI state will not be updated. * * This function must be annotated with the `"use server"` directive. * * @example * ```tsx * onGetUIState: async () => { * 'use server'; * * const currentAIState = getAIState(); * const externalAIState = await loadAIStateFromDatabase(); * * if (currentAIState === externalAIState) return undefined; * * // Update current AI state and return the new UI state * const state = getMutableAIState() * state.done(externalAIState) * * return <div>...</div>; * } * ``` */ onGetUIState?: OnGetUIState<UIState>; }): AIProvider<AIState, UIState, Actions>; type Streamable = ReactNode | Promise<ReactNode>; type Renderer<T extends Array<any>> = (...args: T) => Streamable | Generator<Streamable, Streamable, void> | AsyncGenerator<Streamable, Streamable, void>; type RenderTool<INPUT_SCHEMA extends z4.core.$ZodType | z3.Schema | Schema = any> = { description?: string; inputSchema: INPUT_SCHEMA; generate?: Renderer<[ InferSchema<INPUT_SCHEMA>, { toolName: string; toolCallId: string; } ]>; }; type RenderText = Renderer<[ { /** * The full text content from the model so far. */ content: string; /** * The new appended text content from the model since the last `text` call. */ delta: string; /** * Whether the model is done generating text. * If `true`, the `content` will be the final output and this call will be the last. */ done: boolean; } ]>; type RenderResult = { value: ReactNode; } & Awaited<ReturnType<LanguageModelV2['doStream']>>; /** * `streamUI` is a helper function to create a streamable UI from LLMs. */ declare function streamUI<TOOLS extends { [name: string]: z4.core.$ZodType | z3.Schema | Schema; } = {}>({ model, tools, toolChoice, system, prompt, messages, maxRetries, abortSignal, headers, initial, text, providerOptions, onFinish, ...settings }: CallSettings & Prompt & { /** * The language model to use. */ model: LanguageModelV2; /** * The tools that the model can call. The model needs to support calling tools. */ tools?: { [name in keyof TOOLS]: RenderTool<TOOLS[name]>; }; /** * The tool choice strategy. Default: 'auto'. */ toolChoice?: ToolChoice<TOOLS>; text?: RenderText; initial?: ReactNode; /** Additional provider-specific options. They are passed through to the provider from the AI SDK and enable provider-specific functionality that can be fully encapsulated in the provider. */ providerOptions?: ProviderOptions; /** * Callback that is called when the LLM response and the final object validation are finished. */ onFinish?: (event: { /** * The reason why the generation finished. */ finishReason: FinishReason; /** * The token usage of the generated response. */ usage: LanguageModelUsage; /** * The final ui node that was generated. */ value: ReactNode; /** * Warnings from the model provider (e.g. unsupported settings) */ warnings?: CallWarning[]; /** * Optional response data. */ response?: { /** * Response headers. */ headers?: Record<string, string>; }; }) => Promise<void> | void; }): Promise<RenderResult>; type StreamableUIWrapper = { /** * The value of the streamable UI. This can be returned from a Server Action and received by the client. */ readonly value: React.ReactNode; /** * This method updates the current UI node. It takes a new UI node and replaces the old one. */ update(value: React.ReactNode): StreamableUIWrapper; /** * This method is used to append a new UI node to the end of the old one. * Once appended a new UI node, the previous UI node cannot be updated anymore. * * @example * ```jsx * const ui = createStreamableUI(<div>hello</div>) * ui.append(<div>world</div>) * * // The UI node will be: * // <> * // <div>hello</div> * // <div>world</div> * // </> * ``` */ append(value: React.ReactNode): StreamableUIWrapper; /** * This method is used to signal that there is an error in the UI stream. * It will be thrown on the client side and caught by the nearest error boundary component. */ error(error: any): StreamableUIWrapper; /** * This method marks the UI node as finalized. You can either call it without any parameters or with a new UI node as the final state. * Once called, the UI node cannot be updated or appended anymore. * * This method is always **required** to be called, otherwise the response will be stuck in a loading state. */ done(...args: [React.ReactNode] | []): StreamableUIWrapper; }; /** * Create a piece of changeable UI that can be streamed to the client. * On the client side, it can be rendered as a normal React node. */ declare function createStreamableUI(initialValue?: React.ReactNode): StreamableUIWrapper; declare const __internal_curr: unique symbol; declare const __internal_error: unique symbol; /** * StreamableValue is a value that can be streamed over the network via AI Actions. * To read the streamed values, use the `readStreamableValue` or `useStreamableValue` APIs. */ type StreamableValue<T = any, E = any> = { [__internal_curr]?: T; [__internal_error]?: E; }; /** * Create a wrapped, changeable value that can be streamed to the client. * On the client side, the value can be accessed via the readStreamableValue() API. */ declare function createStreamableValue<T = any, E = any>(initialValue?: T | ReadableStream<T>): StreamableValueWrapper<T, E>; type StreamableValueWrapper<T, E> = { /** * The value of the streamable. This can be returned from a Server Action and * received by the client. To read the streamed values, use the * `readStreamableValue` or `useStreamableValue` APIs. */ readonly value: StreamableValue<T, E>; /** * This method updates the current value with a new one. */ update(value: T): StreamableValueWrapper<T, E>; /** * This method is used to append a delta string to the current value. It * requires the current value of the streamable to be a string. * * @example * ```jsx * const streamable = createStreamableValue('hello'); * streamable.append(' world'); * * // The value will be 'hello world' * ``` */ append(value: T): StreamableValueWrapper<T, E>; /** * This method is used to signal that there is an error in the value stream. * It will be thrown on the client side when consumed via * `readStreamableValue` or `useStreamableValue`. */ error(error: any): StreamableValueWrapper<T, E>; /** * This method marks the value as finalized. You can either call it without * any parameters or with a new value as the final state. * Once called, the value cannot be updated or appended anymore. * * This method is always **required** to be called, otherwise the response * will be stuck in a loading state. */ done(...args: [T] | []): StreamableValueWrapper<T, E>; }; /** * `readStreamableValue` takes a streamable value created via the `createStreamableValue().value` API, * and returns an async iterator. * * ```js * // Inside your AI action: * * async function action() { * 'use server' * const streamable = createStreamableValue(); * * streamable.update(1); * streamable.update(2); * streamable.done(3); * // ... * return streamable.value; * } * ``` * * And to read the value: * * ```js * const streamableValue = await action() * for await (const v of readStreamableValue(streamableValue)) { * console.log(v) * } * ``` * * This logs out 1, 2, 3 on console. */ declare function readStreamableValue<T = unknown>(streamableValue: StreamableValue<T>): AsyncIterable<T | undefined>; /** * `useStreamableValue` is a React hook that takes a streamable value created via the `createStreamableValue().value` API, * and returns the current value, error, and pending state. * * This is useful for consuming streamable values received from a component's props. For example: * * ```js * function MyComponent({ streamableValue }) { * const [data, error, pending] = useStreamableValue(streamableValue); * * if (pending) return <div>Loading...</div>; * if (error) return <div>Error: {error.message}</div>; * * return <div>Data: {data}</div>; * } * ``` */ declare function useStreamableValue<T = unknown, Error = unknown>(streamableValue?: StreamableValue<T>): [data: T | undefined, error: Error | undefined, pending: boolean]; declare function useUIState<AI extends AIProvider = any>(): [InferUIState<AI, any>, (v: InferUIState<AI, any> | ((v_: InferUIState<AI, any>) => InferUIState<AI, any>)) => void]; declare function useAIState<AI extends AIProvider = any>(): [ InferAIState<AI, any>, (newState: ValueOrUpdater<InferAIState<AI, any>>) => void ]; declare function useAIState<AI extends AIProvider = any>(key: keyof InferAIState<AI, any>): [ InferAIState<AI, any>[typeof key], (newState: ValueOrUpdater<InferAIState<AI, any>[typeof key]>) => void ]; declare function useActions<AI extends AIProvider = any>(): InferActions<AI, any>; declare function useSyncUIState(): () => Promise<void>; export { AIAction, AIActions, AIProvider, AIProviderProps, InferAIState, InferActions, InferUIState, InternalAIProviderProps, InternalAIStateStorageOptions, JSONValue, MutableAIState, OnGetUIState, OnSetAIState, ServerWrappedAction, ServerWrappedActions, StreamableValue, ValueOrUpdater, createAI, createStreamableUI, createStreamableValue, getAIState, getMutableAIState, readStreamableValue, streamUI, useAIState, useActions, useStreamableValue, useSyncUIState, useUIState };