UNPKG

@langchain/langgraph-sdk

Version:

Client library for interacting with the LangGraph API

420 lines (418 loc) • 16.4 kB
import { Checkpoint, Config, Metadata, ThreadState } from "../schema.js"; import { AIMessage, DefaultToolCall } from "../types.messages.js"; import { CheckpointsStreamEvent, CustomStreamEvent, DebugStreamEvent, EventsStreamEvent, MetadataStreamEvent, StreamMode, TasksStreamEvent, UpdatesStreamEvent } from "../types.stream.js"; import { Command, DisconnectMode, Durability, MultitaskStrategy, OnCompletionBehavior } from "../types.js"; import { Client, ClientConfig } from "../client.js"; import { BagTemplate } from "../types.template.js"; //#region src/ui/types.d.ts /** * Minimal interface matching the structure of AgentTypeConfig from @langchain/langgraph. * This allows type inference from ReactAgent without requiring the langchain dependency. */ interface AgentTypeConfigLike { Response: unknown; State: unknown; Context: unknown; Middleware: unknown; Tools: unknown; } /** * Check if a type is agent-like (has `~agentTypes` phantom property). * This property is present on `ReactAgent` instances created with `createAgent`. */ type IsAgentLike<T> = T extends { "~agentTypes": AgentTypeConfigLike; } ? true : false; /** * Extract the AgentTypeConfig from an agent-like type. * * @example * ```ts * const agent = createAgent({ ... }); * type Config = ExtractAgentConfig<typeof agent>; * // Config is the AgentTypeConfig with Response, State, Context, Middleware, Tools * ``` */ type ExtractAgentConfig<T> = T extends { "~agentTypes": infer Config; } ? Config extends AgentTypeConfigLike ? Config : never : never; /** * Helper type to infer schema input type, supporting both Zod v3 and v4. * - Zod v4 uses `_zod.input` property * - Zod v3 uses `_input` property */ type InferSchemaInput<S> = S extends { _zod: { input: infer Args; }; } ? Args : S extends { _input: infer Args; } ? Args : never; /** * Helper type to extract the input type from a DynamicStructuredTool's _call method. * This is more reliable than trying to infer from the schema directly because * DynamicStructuredTool has the input type baked into its _call signature. */ type InferToolInput<T> = T extends { _call: (arg: infer Args, ...rest: any[]) => any; } ? Args : T extends { schema: infer S; } ? InferSchemaInput<S> : never; /** * Extract a tool call type from a single tool. * Works with tools created via `tool()` from `@langchain/core/tools`. * * This extracts the literal name type from DynamicStructuredTool's NameT parameter * and the args type from the _call method or schema's input property. */ type ToolCallFromAgentTool<T> = T extends { name: infer N; } ? N extends string ? InferToolInput<T> extends infer Args ? Args extends never ? never : Args extends Record<string, any> ? { name: N; args: Args; id?: string; type?: "tool_call"; } : never : never : never : never; /** * Extract tool calls type from an agent's tools. * Converts the tools array to a discriminated union of tool calls. * * This handles both tuple types (e.g., `readonly [Tool1, Tool2]`) and * array-of-union types (e.g., `readonly (Tool1 | Tool2)[]`) which is how * `createAgent` captures tool types. * * @example * ```ts * const agent = createAgent({ tools: [getWeather, search], ... }); * type ToolCalls = InferAgentToolCalls<typeof agent>; * // ToolCalls is: * // | { name: "get_weather"; args: { location: string }; id?: string } * // | { name: "search"; args: { query: string }; id?: string } * ``` */ type InferAgentToolCalls<T> = ExtractAgentConfig<T>["Tools"] extends readonly (infer Tool)[] ? ToolCallFromAgentTool<Tool> extends never ? DefaultToolCall : ToolCallFromAgentTool<Tool> : DefaultToolCall; /** * Extract the tool call type parameter from an AIMessage in a message union. * Returns `never` if the message is not an AIMessage or uses DefaultToolCall. * * The key distinction: custom tool calls have literal `name` types (e.g., "get_weather"), * while DefaultToolCall has `name: string`. We check if `string extends TC["name"]` - * if true, it's DefaultToolCall; if false, it's a custom type with literal names. */ type ExtractToolCallFromMessageUnion<M> = M extends AIMessage<infer TC> ? TC extends { name: infer N; } ? string extends N ? never : TC : never : never; /** * Extract the tool call type from a StateType's messages property. * This is the primary way to specify tool call types when using useStream. * * @example * ```ts * // Define state with typed messages * type MyToolCalls = * | { name: "get_weather"; args: { location: string }; id?: string } * | { name: "search"; args: { query: string }; id?: string }; * * interface MyState { * messages: Message<MyToolCalls>[]; * } * * // ExtractToolCallsFromState<MyState> = MyToolCalls * ``` */ type ExtractToolCallsFromState<StateType extends Record<string, unknown>> = StateType extends { messages: infer Messages; } ? Messages extends readonly (infer M)[] ? ExtractToolCallFromMessageUnion<M> : Messages extends (infer M)[] ? ExtractToolCallFromMessageUnion<M> : never : never; type MessageMetadata<StateType extends Record<string, unknown>> = { /** * The ID of the message used. */ messageId: string; /** * The first thread state the message was seen in. */ firstSeenState: ThreadState<StateType> | undefined; /** * The branch of the message. */ branch: string | undefined; /** * The list of branches this message is part of. * This is useful for displaying branching controls. */ branchOptions: string[] | undefined; /** * Metadata sent alongside the message during run streaming. * @remarks This metadata only exists temporarily in browser memory during streaming and is not persisted after completion. */ streamMetadata: Record<string, unknown> | undefined; }; type GetUpdateType<Bag extends BagTemplate, StateType extends Record<string, unknown>> = Bag extends { UpdateType: unknown; } ? Bag["UpdateType"] : Partial<StateType>; type GetConfigurableType<Bag extends BagTemplate> = Bag extends { ConfigurableType: Record<string, unknown>; } ? Bag["ConfigurableType"] : Record<string, unknown>; type GetInterruptType<Bag extends BagTemplate> = Bag extends { InterruptType: unknown; } ? Bag["InterruptType"] : unknown; type GetCustomEventType<Bag extends BagTemplate> = Bag extends { CustomEventType: unknown; } ? Bag["CustomEventType"] : unknown; /** * Extract the tool call type from a StateType's messages property. * This is the canonical way to get typed tool calls in useStream. * * Tool call types are now extracted from the messages property of StateType, * rather than being specified separately in the Bag. * * @example * ```ts * // Define state with typed messages * type MyToolCalls = * | { name: "get_weather"; args: { location: string }; id?: string } * | { name: "search"; args: { query: string }; id?: string }; * * interface MyState { * messages: Message<MyToolCalls>[]; * } * * // GetToolCallsType<MyState> = MyToolCalls * ``` */ type GetToolCallsType<StateType extends Record<string, unknown>> = ExtractToolCallsFromState<StateType> extends never ? DefaultToolCall : ExtractToolCallsFromState<StateType>; interface RunCallbackMeta { run_id: string; thread_id: string; } interface UseStreamThread<StateType extends Record<string, unknown>> { data: ThreadState<StateType>[] | null | undefined; error: unknown; isLoading: boolean; mutate: (mutateId?: string) => Promise<ThreadState<StateType>[] | null | undefined>; } interface UseStreamOptions<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> { /** * The ID of the assistant to use. */ assistantId: string; /** * Client used to send requests. */ client?: Client; /** * The URL of the API to use. */ apiUrl?: ClientConfig["apiUrl"]; /** * The API key to use. */ apiKey?: ClientConfig["apiKey"]; /** * Custom call options, such as custom fetch implementation. */ callerOptions?: ClientConfig["callerOptions"]; /** * Default headers to send with requests. */ defaultHeaders?: ClientConfig["defaultHeaders"]; /** * Specify the key within the state that contains messages. * Defaults to "messages". * * @default "messages" */ messagesKey?: string; /** * Callback that is called when an error occurs. */ onError?: (error: unknown, run: RunCallbackMeta | undefined) => void; /** * Callback that is called when the stream is finished. */ onFinish?: (state: ThreadState<StateType>, run: RunCallbackMeta | undefined) => void; /** * Callback that is called when a new stream is created. */ onCreated?: (run: RunCallbackMeta) => void; /** * Callback that is called when an update event is received. */ onUpdateEvent?: (data: UpdatesStreamEvent<GetUpdateType<Bag, StateType>>["data"], options: { namespace: string[] | undefined; mutate: (update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)) => void; }) => void; /** * Callback that is called when a custom event is received. */ onCustomEvent?: (data: CustomStreamEvent<GetCustomEventType<Bag>>["data"], options: { namespace: string[] | undefined; mutate: (update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)) => void; }) => void; /** * Callback that is called when a metadata event is received. */ onMetadataEvent?: (data: MetadataStreamEvent["data"]) => void; /** * Callback that is called when a LangChain event is received. * @see https://langchain-ai.github.io/langgraph/cloud/how-tos/stream_events/#stream-graph-in-events-mode for more details. */ onLangChainEvent?: (data: EventsStreamEvent["data"]) => void; /** * Callback that is called when a debug event is received. * @internal This API is experimental and subject to change. */ onDebugEvent?: (data: DebugStreamEvent["data"], options: { namespace: string[] | undefined; }) => void; /** * Callback that is called when a checkpoints event is received. */ onCheckpointEvent?: (data: CheckpointsStreamEvent<StateType>["data"], options: { namespace: string[] | undefined; }) => void; /** * Callback that is called when a tasks event is received. */ onTaskEvent?: (data: TasksStreamEvent<StateType, GetUpdateType<Bag, StateType>>["data"], options: { namespace: string[] | undefined; }) => void; /** * Callback that is called when the stream is stopped by the user. * Provides a mutate function to update the stream state immediately * without requiring a server roundtrip. * * @example * ```typescript * onStop: ({ mutate }) => { * mutate((prev) => ({ * ...prev, * ui: prev.ui?.map(component => * component.props.isLoading * ? { ...component, props: { ...component.props, stopped: true, isLoading: false }} * : component * ) * })); * } * ``` */ onStop?: (options: { mutate: (update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)) => void; }) => void; /** * The ID of the thread to fetch history and current values from. */ threadId?: string | null; /** * Callback that is called when the thread ID is updated (ie when a new thread is created). */ onThreadId?: (threadId: string) => void; /** Will reconnect the stream on mount */ reconnectOnMount?: boolean | (() => RunMetadataStorage); /** * Initial values to display immediately when loading a thread. * Useful for displaying cached thread data while official history loads. * These values will be replaced when official thread data is fetched. * * Note: UI components from initialValues will render immediately if they're * predefined in LoadExternalComponent's components prop, providing instant * cached UI display without server fetches. */ initialValues?: StateType | null; /** * Whether to fetch the history of the thread. * If true, the history will be fetched from the server. Defaults to 10 entries. * If false, only the last state will be fetched from the server. * @default true */ fetchStateHistory?: boolean | { limit: number; }; /** * Manage the thread state externally. */ thread?: UseStreamThread<StateType>; /** * Throttle the stream. * If a number is provided, the stream will be throttled to the given number of milliseconds. * If `true`, updates are batched in a single macrotask. * If `false`, updates are not throttled or batched. * @default true */ throttle?: number | boolean; } interface RunMetadataStorage { getItem(key: `lg:stream:${string}`): string | null; setItem(key: `lg:stream:${string}`, value: string): void; removeItem(key: `lg:stream:${string}`): void; } type ConfigWithConfigurable<ConfigurableType extends Record<string, unknown>> = Config & { configurable?: ConfigurableType; }; interface SubmitOptions<StateType extends Record<string, unknown> = Record<string, unknown>, ContextType extends Record<string, unknown> = Record<string, unknown>> { config?: ConfigWithConfigurable<ContextType>; context?: ContextType; checkpoint?: Omit<Checkpoint, "thread_id"> | null; command?: Command; interruptBefore?: "*" | string[]; interruptAfter?: "*" | string[]; metadata?: Metadata; multitaskStrategy?: MultitaskStrategy; onCompletion?: OnCompletionBehavior; onDisconnect?: DisconnectMode; feedbackKeys?: string[]; streamMode?: Array<StreamMode>; runId?: string; optimisticValues?: Partial<StateType> | ((prev: StateType) => Partial<StateType>); /** * Whether or not to stream the nodes of any subgraphs called * by the assistant. * @default false */ streamSubgraphs?: boolean; /** * Mark the stream as resumable. All events emitted during the run will be temporarily persisted * in order to be re-emitted if the stream is re-joined. * @default false */ streamResumable?: boolean; /** * Whether to checkpoint during the run (or only at the end/interruption). * - `"async"`: Save checkpoint asynchronously while the next step executes (default). * - `"sync"`: Save checkpoint synchronously before the next step starts. * - `"exit"`: Save checkpoint only when the graph exits. * @default "async" */ durability?: Durability; /** * The ID to use when creating a new thread. When provided, this ID will be used * for thread creation when threadId is `null` or `undefined`. * This enables optimistic UI updates where you know the thread ID * before the thread is actually created. */ threadId?: string; } /** * Transport used to stream the thread. * Only applicable for custom endpoints using `toLangGraphEventStream` or `toLangGraphEventStreamResponse`. */ interface UseStreamTransport<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> { stream: (payload: { input: GetUpdateType<Bag, StateType> | null | undefined; context: GetConfigurableType<Bag> | undefined; command: Command | undefined; config: ConfigWithConfigurable<GetConfigurableType<Bag>> | undefined; signal: AbortSignal; }) => Promise<AsyncGenerator<{ id?: string; event: string; data: unknown; }>>; } type UseStreamCustomOptions<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> = Pick<UseStreamOptions<StateType, Bag>, "messagesKey" | "threadId" | "onThreadId" | "onError" | "onCreated" | "onUpdateEvent" | "onCustomEvent" | "onMetadataEvent" | "onLangChainEvent" | "onDebugEvent" | "onCheckpointEvent" | "onTaskEvent" | "onStop" | "initialValues" | "throttle"> & { transport: UseStreamTransport<StateType, Bag>; }; type CustomSubmitOptions<StateType extends Record<string, unknown> = Record<string, unknown>, ConfigurableType extends Record<string, unknown> = Record<string, unknown>> = Pick<SubmitOptions<StateType, ConfigurableType>, "optimisticValues" | "context" | "command" | "config">; //#endregion export { AgentTypeConfigLike, CustomSubmitOptions, ExtractAgentConfig, GetConfigurableType, GetInterruptType, GetToolCallsType, GetUpdateType, InferAgentToolCalls, IsAgentLike, MessageMetadata, RunCallbackMeta, SubmitOptions, UseStreamCustomOptions, UseStreamOptions, UseStreamThread, UseStreamTransport }; //# sourceMappingURL=types.d.ts.map