@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
420 lines (418 loc) • 16.4 kB
TypeScript
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