UNPKG

@langchain/langgraph

Version:
1 lines 19.5 kB
{"version":3,"file":"types.cjs","names":["StateSchema","isBaseChannel"],"sources":["../../src/graph/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n isInteropZodObject,\n type InteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { LangGraphRunnableConfig } from \"../pregel/runnable_types.js\";\nimport type { CommandInstance, Send } from \"../constants.js\";\nimport { END } from \"../constants.js\";\nimport type {\n AnnotationRoot,\n StateDefinition,\n StateType,\n UpdateType as AnnotationUpdateType,\n} from \"./annotation.js\";\nimport {\n AnyStateSchema,\n StateSchema,\n StateSchemaFieldsToStateDefinition,\n} from \"../state/schema.js\";\nimport type { InteropZodToStateDefinition } from \"./zod/meta.js\";\nimport { isBaseChannel } from \"../channels/base.js\";\n\n// Re-export END for use in ConditionalEdgeRouter return types\nexport { END };\n\n/**\n * Convert any supported schema type to a StateDefinition.\n *\n * @internal\n */\nexport type ToStateDefinition<T> =\n T extends StateSchema<infer TInit>\n ? StateSchemaFieldsToStateDefinition<TInit>\n : T extends AnnotationRoot<infer SD>\n ? SD\n : T extends InteropZodObject\n ? InteropZodToStateDefinition<T>\n : T extends StateDefinition\n ? T\n : never;\n\n/**\n * Type for schema types that can be used to initialize state.\n * Supports all valid schema types: StateDefinition, Zod objects, StateSchema, and AnnotationRoot.\n *\n * @internal\n */\nexport type StateDefinitionInit =\n | StateDefinition\n | InteropZodObject\n | AnyStateSchema\n | AnnotationRoot<any>;\n\n/**\n * Check if a value is a valid StateDefinitionInit type.\n * Supports: StateSchema, InteropZodObject (Zod), AnnotationRoot, StateDefinition\n *\n * @internal\n */\nexport function isStateDefinitionInit(\n value: unknown\n): value is StateDefinitionInit {\n if (value == null) return false;\n\n // StateSchema\n if (StateSchema.isInstance(value)) return true;\n\n // InteropZodObject (Zod v3/v4 object schemas)\n if (isInteropZodObject(value)) return true;\n\n // AnnotationRoot\n if (\n typeof value === \"object\" &&\n \"lc_graph_name\" in value &&\n (value as { lc_graph_name: unknown }).lc_graph_name === \"AnnotationRoot\"\n ) {\n return true;\n }\n\n // StateDefinition (raw channel map)\n if (\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n Object.keys(value).length > 0 &&\n Object.values(value).every(\n (v) => typeof v === \"function\" || isBaseChannel(v)\n )\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Valid types for context schema.\n * Context doesn't have channels/reducers, so StateSchema is NOT supported.\n * Supports StandardSchemaV1 (Zod, Valibot, etc.) and AnnotationRoot (backward compat).\n *\n * @internal\n */\nexport type ContextSchemaInit =\n | StandardSchemaV1\n | AnnotationRoot<StateDefinition>;\n\n/**\n * Initialization options for StateGraph.\n * Accepts any combination of schema types for state/input/output.\n *\n * Supports both `state` and `stateSchema` as aliases for backward compatibility.\n * If only `input` is provided (no state/stateSchema), `input` is used as the state schema.\n *\n * @template SD - State definition type\n * @template I - Input definition type (defaults to undefined)\n * @template O - Output definition type (defaults to undefined)\n * @template C - Context schema type (defaults to undefined)\n * @template N - Node name union type (defaults to string)\n * @template InterruptType - Interrupt type (defaults to unknown)\n * @template WriterType - Writer type (defaults to unknown)\n */\nexport type StateGraphInit<\n SD extends StateDefinitionInit = StateDefinitionInit,\n I extends StateDefinitionInit | undefined = undefined,\n O extends StateDefinitionInit | undefined = undefined,\n C extends StateDefinitionInit | undefined = undefined,\n N extends string = string,\n InterruptType = unknown,\n WriterType = unknown,\n> = {\n /** Primary key for state schema */\n state?: SD;\n\n /**\n * @deprecated Use `state` instead. Will be removed in a future version.\n */\n stateSchema?: SD;\n\n input?: I;\n output?: O;\n\n /** Context schema for runtime configuration validation. Does not support StateSchema. */\n context?: C;\n\n interrupt?: InterruptType;\n writer?: WriterType;\n nodes?: N[];\n};\n\n/**\n * Options for the second argument when passing a direct schema.\n * Excludes `state` and `stateSchema` since those come from the first arg.\n *\n * @internal\n */\nexport type StateGraphOptions<\n I extends StateDefinitionInit | undefined = undefined,\n O extends StateDefinitionInit | undefined = undefined,\n C extends StateDefinitionInit | undefined = undefined,\n N extends string = string,\n InterruptType = unknown,\n WriterType = unknown,\n> = Omit<\n StateGraphInit<StateDefinitionInit, I, O, C, N, InterruptType, WriterType>,\n \"state\" | \"stateSchema\"\n>;\n\n/**\n * Check if a value is a StateGraphInit object (has state, stateSchema, or input with valid schema).\n *\n * @internal\n */\nexport function isStateGraphInit(\n value: unknown\n): value is StateGraphInit<StateDefinitionInit> {\n if (typeof value !== \"object\" || value == null) return false;\n\n const obj = value as Record<string, unknown>;\n\n // Must have at least one of: state, stateSchema, or input\n const hasState = \"state\" in obj && isStateDefinitionInit(obj.state);\n const hasStateSchema =\n \"stateSchema\" in obj && isStateDefinitionInit(obj.stateSchema);\n const hasInput = \"input\" in obj && isStateDefinitionInit(obj.input);\n\n if (!hasState && !hasStateSchema && !hasInput) return false;\n\n // Validate input/output if provided\n if (\"input\" in obj && obj.input != null && !isStateDefinitionInit(obj.input))\n return false;\n if (\n \"output\" in obj &&\n obj.output != null &&\n !isStateDefinitionInit(obj.output)\n )\n return false;\n\n return true;\n}\n\n/**\n * Extract the State type from any supported schema type.\n *\n * Supports:\n * - StateSchema\n * - AnnotationRoot\n * - StateDefinition (internal channel definitions)\n * - InteropZodObject (Zod v3/v4 object schemas)\n *\n * @template Schema - The schema type to extract state from\n * @template Fallback - Type to return if schema doesn't match (default: never)\n */\nexport type ExtractStateType<Schema, Fallback = Schema> =\n Schema extends AnnotationRoot<infer SD>\n ? StateType<SD>\n : StateType<ToStateDefinition<Schema>> extends infer S\n ? [S] extends [never]\n ? Fallback\n : S\n : Fallback;\n\n/**\n * Extract the Update type from any supported schema type.\n *\n * The Update type represents what a node can return to update the state.\n * All fields are optional since nodes only need to return the fields they modify.\n *\n * Supports:\n * - StateSchema\n * - AnnotationRoot\n * - StateDefinition (internal channel definitions)\n * - InteropZodObject (Zod v3/v4 object schemas)\n *\n * @template Schema - The schema type to extract update type from\n * @template FallbackBase - Base type for fallback (will be partialized), defaults to Schema\n */\nexport type ExtractUpdateType<Schema, FallbackBase = Schema> =\n Schema extends AnnotationRoot<infer SD>\n ? AnnotationUpdateType<SD>\n : AnnotationUpdateType<ToStateDefinition<Schema>> extends infer U\n ? [U] extends [never]\n ? Partial<FallbackBase>\n : U\n : Partial<FallbackBase>;\n\n/**\n * Extract the input type from a type bag, using ExtractStateType on the InputSchema.\n * Falls back to Default if InputSchema is not provided.\n * @internal\n */\ntype ExtractBagInput<Bag, Default> = Bag extends {\n InputSchema: infer I;\n}\n ? ExtractStateType<I>\n : Default;\n\n/**\n * Extract the output type from a type bag, using ExtractUpdateType on the OutputSchema.\n * Falls back to Default if OutputSchema is not provided.\n * @internal\n */\ntype ExtractBagOutput<Bag, Default> = Bag extends {\n OutputSchema: infer O;\n}\n ? ExtractUpdateType<O>\n : Default;\n\n/**\n * Extract the context type from a type bag, using ExtractStateType on the ContextSchema.\n * Falls back to Default if ContextSchema is not provided.\n * Ensures result extends Record<string, unknown> for LangGraphRunnableConfig compatibility.\n * @internal\n */\ntype ExtractBagContext<\n Bag,\n Default extends Record<string, unknown>,\n> = Bag extends {\n ContextSchema: infer C;\n}\n ? ExtractStateType<C> extends infer Ctx\n ? Ctx extends Record<string, unknown>\n ? Ctx\n : Default\n : Default\n : Default;\n\n/**\n * Extract the Nodes type from a type bag.\n * Falls back to Default if Nodes is not provided.\n * @internal\n */\ntype ExtractBagNodes<Bag, Default extends string> = Bag extends {\n Nodes: infer N extends string;\n}\n ? N\n : Default;\n\n/**\n * Type bag for GraphNode that accepts schema types.\n * All fields are optional - unspecified fields use defaults.\n *\n * This enables separate input/output schemas for nodes, which is useful when\n * a node receives a subset of state fields and returns different fields.\n *\n * @example\n * ```typescript\n * const node: GraphNode<{\n * InputSchema: typeof NodeInputSchema;\n * OutputSchema: typeof NodeOutputSchema;\n * ContextSchema: typeof ContextSchema;\n * Nodes: \"agent\" | \"tool\";\n * }> = (state, runtime) => {\n * return { answer: `Response to: ${state.query}` };\n * };\n * ```\n */\nexport interface GraphNodeTypes<\n InputSchema = unknown,\n OutputSchema = unknown,\n ContextSchema = unknown,\n Nodes extends string = string,\n> {\n /** Schema for node input state (uses ExtractStateType) */\n InputSchema?: InputSchema;\n /** Schema for node output/update (uses ExtractUpdateType) */\n OutputSchema?: OutputSchema;\n /** Schema for runtime context (uses ExtractStateType) */\n ContextSchema?: ContextSchema;\n /** Union of valid node names for Command.goto */\n Nodes?: Nodes;\n}\n\n/**\n * Detect if T is a type bag (has InputSchema or OutputSchema) or a direct schema.\n * @internal\n */\ntype IsGraphNodeTypeBag<T> = T extends { InputSchema: unknown }\n ? true\n : T extends { OutputSchema: unknown }\n ? true\n : false;\n\n/**\n * Return value type for GraphNode functions.\n * Nodes can return an update object, a Command, or a Promise of either.\n *\n * @template Update - The update type (what fields can be returned)\n * @template Nodes - Union of valid node names for Command.goto\n */\nexport type GraphNodeReturnValue<Update, Nodes extends string = string> =\n | Update\n | CommandInstance<unknown, Update, Nodes>\n | Promise<Update | CommandInstance<unknown, Update, Nodes>>;\n\n/**\n * Strongly-typed utility for authoring graph nodes outside of the StateGraph builder,\n * supporting inference for both state (from Schema) and config context (from Context type).\n *\n * This type enables you to define graph node functions with full type safety—both\n * for the evolving state and for additional context that may be passed in at runtime.\n * Typing the context parameter allows for better code organization and precise editor support.\n *\n * Works with StateSchema, AnnotationRoot, and Zod object schemas for state, and\n * with a user-defined object shape for context.\n *\n * **Supports two patterns:**\n *\n * 1. **Single schema usage** - Single schema for both input and output:\n * `GraphNode<Schema, Context, Nodes>`\n *\n * 2. **Type bag pattern** - Separate schemas for input, output, context:\n * `GraphNode<{ InputSchema; OutputSchema; ContextSchema; Nodes }>`\n *\n * @template Schema - The state schema type (StateSchema, AnnotationRoot, InteropZodObject) OR a type bag\n * @template Context - The type of the context passed into this node (default: Record<string, unknown>)\n * @template Nodes - An optional union of valid node names for Command.goto, used for type-safe routing (default: string)\n *\n * @example Single schema usage\n * ```typescript\n * import { StateSchema, GraphNode } from \"@langchain/langgraph\";\n * import { z } from \"zod/v4\";\n *\n * const AgentState = new StateSchema({\n * messages: MessagesValue,\n * step: z.number().default(0),\n * });\n *\n * // Context shape for custom node logic (optional)\n * type MyContext = { userId: string };\n *\n * // Node receiving state and config\n * const processNode: GraphNode<typeof AgentState, MyContext> = (state, config) => {\n * const userId = config.configurable?.userId; // type-safe context access\n * return { step: state.step + 1 };\n * };\n *\n * // Node with type-safe graph routing\n * const routerNode: GraphNode<typeof AgentState, MyContext, \"agent\" | \"tool\"> = (state, config) => {\n * if (state.needsTool) {\n * return new Command({ goto: \"tool\", update: { step: state.step + 1 } });\n * }\n * return new Command({ goto: \"agent\" });\n * };\n *\n * // Use in graph\n * const graph = new StateGraph(AgentState)\n * .addNode(\"process\", processNode)\n * .addNode(\"router\", routerNode)\n * .compile();\n * ```\n *\n * @example Type bag pattern - separate input/output schemas\n * ```typescript\n * const InputSchema = new StateSchema({\n * messages: z.array(z.string()),\n * query: z.string(),\n * });\n *\n * const OutputSchema = new StateSchema({\n * answer: z.string(),\n * });\n *\n * const ContextSchema = z.object({ userId: z.string() });\n *\n * const node: GraphNode<{\n * InputSchema: typeof InputSchema;\n * OutputSchema: typeof OutputSchema;\n * ContextSchema: typeof ContextSchema;\n * Nodes: \"agent\" | \"tool\";\n * }> = (state, config) => {\n * // state is { messages: string[]; query: string }\n * // config.configurable is { userId: string } | undefined\n * return { answer: `Response to: ${state.query}` };\n * };\n * ```\n */\nexport type GraphNode<\n Schema,\n Context extends Record<string, any> = Record<string, any>,\n Nodes extends string = string,\n> =\n IsGraphNodeTypeBag<Schema> extends true\n ? // Type bag pattern - extract types from schemas\n (\n state: ExtractBagInput<Schema, unknown>,\n config: LangGraphRunnableConfig<\n ExtractBagContext<Schema, Record<string, unknown>>\n >\n ) => GraphNodeReturnValue<\n ExtractBagOutput<Schema, Partial<ExtractBagInput<Schema, unknown>>>,\n ExtractBagNodes<Schema, string>\n >\n : // Single schema pattern (backward compatible)\n (\n state: ExtractStateType<Schema>,\n config: LangGraphRunnableConfig<Context>\n ) => GraphNodeReturnValue<ExtractUpdateType<Schema>, Nodes>;\n\n/**\n * Type bag for ConditionalEdgeRouter that accepts schema types.\n * Unlike GraphNodeTypes, conditional edges don't have separate input/output -\n * they just read state and return routing decisions.\n *\n * @example\n * ```typescript\n * const router: ConditionalEdgeRouter<{\n * Schema: typeof StateSchema;\n * ContextSchema: typeof ContextSchema;\n * Nodes: \"agent\" | \"tool\";\n * }> = (state, config) => {\n * return state.done ? END : \"agent\";\n * };\n * ```\n */\nexport interface ConditionalEdgeRouterTypes<\n InputSchema = unknown,\n ContextSchema = unknown,\n Nodes extends string = string,\n> {\n /** Schema for router state (uses ExtractStateType) */\n InputSchema?: InputSchema;\n /** Schema for runtime context (uses ExtractStateType) */\n ContextSchema?: ContextSchema;\n /** Union of valid node names that can be routed to */\n Nodes?: Nodes;\n}\n\n/**\n * Detect if T is a ConditionalEdgeRouterTypes bag.\n * @internal\n */\ntype IsConditionalEdgeRouterTypeBag<T> = T extends { InputSchema: unknown }\n ? true\n : T extends { ContextSchema: unknown }\n ? true\n : false;\n\n/**\n * Return type for conditional edge routing functions.\n */\ntype ConditionalEdgeRouterReturnValue<Nodes extends string, State> =\n | Nodes\n | typeof END\n | Send<Nodes, State>\n | Array<Nodes | Send<Nodes, State>>;\n\n/**\n * Type for conditional edge routing functions.\n *\n * Use this to type functions passed to `addConditionalEdges` for\n * full type safety on state, runtime context, and return values.\n *\n * **Supports two patterns:**\n *\n * 1. **Single schema pattern** - Single schema:\n * `ConditionalEdgeRouter<Schema, Context, Nodes>`\n *\n * 2. **Type bag pattern** - Separate schemas for state, context:\n * `ConditionalEdgeRouter<{ Schema; ContextSchema; Nodes }>`\n *\n * @template Schema - The state schema type OR a type bag\n * @template Context - The runtime context type available to node logic\n * @template Nodes - Union of valid node names that can be routed to\n *\n * @example Single schema pattern\n * ```typescript\n * type MyContext = { userId: string };\n * const router: ConditionalEdgeRouter<typeof AgentState, MyContext, \"agent\" | \"tool\"> =\n * (state, config) => {\n * const userId = config.context?.userId;\n * if (state.done) return END;\n * return state.needsTool ? \"tool\" : \"agent\";\n * };\n *\n * graph.addConditionalEdges(\"router\", router, [\"agent\", \"tool\"]);\n * ```\n *\n * @example Type bag pattern\n * ```typescript\n * const router: ConditionalEdgeRouter<{\n * Schema: typeof StateSchema;\n * ContextSchema: typeof ContextSchema;\n * Nodes: \"agent\" | \"tool\";\n * }> = (state, config) => {\n * if (state.done) return END;\n * return \"agent\";\n * };\n * ```\n */\nexport type ConditionalEdgeRouter<\n Schema,\n Context extends Record<string, any> = Record<string, any>,\n Nodes extends string = string,\n> =\n IsConditionalEdgeRouterTypeBag<Schema> extends true\n ? // Type bag pattern - extract types from schemas\n (\n state: ExtractBagInput<Schema, unknown>,\n config: LangGraphRunnableConfig<\n ExtractBagContext<Schema, Record<string, unknown>>\n >\n ) =>\n | ConditionalEdgeRouterReturnValue<\n ExtractBagNodes<Schema, string>,\n ExtractBagInput<Schema, unknown>\n >\n | Promise<\n ConditionalEdgeRouterReturnValue<\n ExtractBagNodes<Schema, string>,\n ExtractBagInput<Schema, unknown>\n >\n >\n : // Single schema pattern (backward compatible)\n (\n state: ExtractStateType<Schema>,\n config: LangGraphRunnableConfig<Context>\n ) =>\n | ConditionalEdgeRouterReturnValue<Nodes, ExtractStateType<Schema>>\n | Promise<\n ConditionalEdgeRouterReturnValue<Nodes, ExtractStateType<Schema>>\n >;\n"],"mappings":";;;;;;;;;;;AA4DA,SAAgB,sBACd,OAC8B;AAC9B,KAAI,SAAS,KAAM,QAAO;AAG1B,KAAIA,eAAAA,YAAY,WAAW,MAAM,CAAE,QAAO;AAG1C,MAAA,GAAA,4BAAA,oBAAuB,MAAM,CAAE,QAAO;AAGtC,KACE,OAAO,UAAU,YACjB,mBAAmB,SAClB,MAAqC,kBAAkB,iBAExD,QAAO;AAIT,KACE,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,MAAM,IACrB,OAAO,KAAK,MAAM,CAAC,SAAS,KAC5B,OAAO,OAAO,MAAM,CAAC,OAClB,MAAM,OAAO,MAAM,cAAcC,aAAAA,cAAc,EAAE,CACnD,CAED,QAAO;AAGT,QAAO;;;;;;;AAgFT,SAAgB,iBACd,OAC8C;AAC9C,KAAI,OAAO,UAAU,YAAY,SAAS,KAAM,QAAO;CAEvD,MAAM,MAAM;CAGZ,MAAM,WAAW,WAAW,OAAO,sBAAsB,IAAI,MAAM;CACnE,MAAM,iBACJ,iBAAiB,OAAO,sBAAsB,IAAI,YAAY;CAChE,MAAM,WAAW,WAAW,OAAO,sBAAsB,IAAI,MAAM;AAEnE,KAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,SAAU,QAAO;AAGtD,KAAI,WAAW,OAAO,IAAI,SAAS,QAAQ,CAAC,sBAAsB,IAAI,MAAM,CAC1E,QAAO;AACT,KACE,YAAY,OACZ,IAAI,UAAU,QACd,CAAC,sBAAsB,IAAI,OAAO,CAElC,QAAO;AAET,QAAO"}