langchain
Version:
Typescript bindings for langchain
354 lines (351 loc) • 18.8 kB
TypeScript
import { JumpToTarget } from "../constants.js";
import { ClientTool, ServerTool } from "../tools.js";
import { AgentBuiltInState, Runtime } from "../runtime.js";
import { ModelRequest } from "../nodes/types.js";
import { AIMessage, ToolMessage } from "@langchain/core/messages";
import { AnnotationRoot, Command } from "@langchain/langgraph";
import { InteropZodToStateDefinition } from "@langchain/langgraph/zod";
import { InferInteropZodInput, InferInteropZodOutput, InteropZodDefault, InteropZodObject, InteropZodOptional } from "@langchain/core/utils/types";
import { ToolCall as ToolCall$1 } from "@langchain/core/messages/tool";
//#region src/agents/middleware/types.d.ts
type PromiseOrValue<T> = T | Promise<T>;
type AnyAnnotationRoot = AnnotationRoot<any>;
type NormalizedSchemaInput<TSchema extends InteropZodObject | undefined = any> = TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {};
/**
* Result type for middleware functions.
*/
type MiddlewareResult<TState> = TState | void;
/**
* Represents a tool call request for the wrapToolCall hook.
* Contains the tool call information along with the agent's current state and runtime.
*/
interface ToolCallRequest<TState extends Record<string, unknown> = Record<string, unknown>, TContext = unknown> {
/**
* The tool call to be executed
*/
toolCall: ToolCall$1;
/**
* The BaseTool instance being invoked.
* Provides access to tool metadata like name, description, schema, etc.
*/
tool: ClientTool | ServerTool;
/**
* The current agent state (includes both middleware state and built-in state).
*/
state: TState & AgentBuiltInState;
/**
* The runtime context containing metadata, signal, writer, interrupt, etc.
*/
runtime: Runtime<TContext>;
}
/**
* Handler function type for wrapping tool calls.
* Takes a tool call request and returns the tool result or a command.
*/
type ToolCallHandler<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (request: ToolCallRequest<NormalizedSchemaInput<TSchema> & AgentBuiltInState, TContext>) => PromiseOrValue<ToolMessage | Command>;
/**
* Wrapper function type for the wrapToolCall hook.
* Allows middleware to intercept and modify tool execution.
*/
type WrapToolCallHook<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (request: ToolCallRequest<NormalizedSchemaInput<TSchema> & AgentBuiltInState, TContext>, handler: ToolCallHandler<TSchema, TContext>) => PromiseOrValue<ToolMessage | Command>;
/**
* Handler function type for wrapping model calls.
* Takes a model request and returns the AI message response.
*
* @param request - The model request containing model, messages, systemPrompt, tools, state, and runtime
* @returns The AI message response from the model
*/
type WrapModelCallHandler<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (request: ModelRequest<NormalizedSchemaInput<TSchema> & AgentBuiltInState, TContext>) => PromiseOrValue<AIMessage>;
/**
* Wrapper function type for the wrapModelCall hook.
* Allows middleware to intercept and modify model execution.
* This enables you to:
* - Modify the request before calling the model (e.g., change system prompt, add/remove tools)
* - Handle errors and retry with different parameters
* - Post-process the response
* - Implement custom caching, logging, or other cross-cutting concerns
*
* @param request - The model request containing all parameters needed for the model call
* @param handler - The function that invokes the model. Call this with a ModelRequest to get the response
* @returns The AI message response from the model (or a modified version)
*/
type WrapModelCallHook<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (request: ModelRequest<NormalizedSchemaInput<TSchema> & AgentBuiltInState, TContext>, handler: WrapModelCallHandler<TSchema, TContext>) => PromiseOrValue<AIMessage>;
/**
* Handler function type for the beforeAgent hook.
* Called once at the start of agent invocation before any model calls or tool executions.
*
* @param state - The current agent state (includes both middleware state and built-in state)
* @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.
* @returns A middleware result containing partial state updates or undefined to pass through
*/
type BeforeAgentHandler<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (state: NormalizedSchemaInput<TSchema> & AgentBuiltInState, runtime: Runtime<TContext>) => PromiseOrValue<MiddlewareResult<Partial<NormalizedSchemaInput<TSchema>>>>;
/**
* Hook type for the beforeAgent lifecycle event.
* Can be either a handler function or an object with a handler and optional jump targets.
* This hook is called once at the start of the agent invocation.
*/
type BeforeAgentHook<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = BeforeAgentHandler<TSchema, TContext> | {
hook: BeforeAgentHandler<TSchema, TContext>;
canJumpTo?: JumpToTarget[];
};
/**
* Handler function type for the beforeModel hook.
* Called before the model is invoked and before the wrapModelCall hook.
*
* @param state - The current agent state (includes both middleware state and built-in state)
* @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.
* @returns A middleware result containing partial state updates or undefined to pass through
*/
type BeforeModelHandler<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (state: NormalizedSchemaInput<TSchema> & AgentBuiltInState, runtime: Runtime<TContext>) => PromiseOrValue<MiddlewareResult<Partial<NormalizedSchemaInput<TSchema>>>>;
/**
* Hook type for the beforeModel lifecycle event.
* Can be either a handler function or an object with a handler and optional jump targets.
* This hook is called before each model invocation.
*/
type BeforeModelHook<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = BeforeModelHandler<TSchema, TContext> | {
hook: BeforeModelHandler<TSchema, TContext>;
canJumpTo?: JumpToTarget[];
};
/**
* Handler function type for the afterModel hook.
* Called after the model is invoked and before any tools are called.
* Allows modifying the agent state after model invocation, e.g., to update tool call parameters.
*
* @param state - The current agent state (includes both middleware state and built-in state)
* @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.
* @returns A middleware result containing partial state updates or undefined to pass through
*/
type AfterModelHandler<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (state: NormalizedSchemaInput<TSchema> & AgentBuiltInState, runtime: Runtime<TContext>) => PromiseOrValue<MiddlewareResult<Partial<NormalizedSchemaInput<TSchema>>>>;
/**
* Hook type for the afterModel lifecycle event.
* Can be either a handler function or an object with a handler and optional jump targets.
* This hook is called after each model invocation.
*/
type AfterModelHook<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = AfterModelHandler<TSchema, TContext> | {
hook: AfterModelHandler<TSchema, TContext>;
canJumpTo?: JumpToTarget[];
};
/**
* Handler function type for the afterAgent hook.
* Called once at the end of agent invocation after all model calls and tool executions are complete.
*
* @param state - The current agent state (includes both middleware state and built-in state)
* @param runtime - The runtime context containing metadata, signal, writer, interrupt, etc.
* @returns A middleware result containing partial state updates or undefined to pass through
*/
type AfterAgentHandler<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = (state: NormalizedSchemaInput<TSchema> & AgentBuiltInState, runtime: Runtime<TContext>) => PromiseOrValue<MiddlewareResult<Partial<NormalizedSchemaInput<TSchema>>>>;
/**
* Hook type for the afterAgent lifecycle event.
* Can be either a handler function or an object with a handler and optional jump targets.
* This hook is called once at the end of the agent invocation.
*/
type AfterAgentHook<TSchema extends InteropZodObject | undefined = any, TContext = unknown> = AfterAgentHandler<TSchema, TContext> | {
hook: AfterAgentHandler<TSchema, TContext>;
canJumpTo?: JumpToTarget[];
};
/**
* Base middleware interface.
*/
interface AgentMiddleware<TSchema extends InteropZodObject | undefined = any, TContextSchema extends InteropZodObject | InteropZodDefault<InteropZodObject> | InteropZodOptional<InteropZodObject> | undefined = any, TFullContext = any> {
/**
* The name of the middleware.
*/
name: string;
/**
* The schema of the middleware state. Middleware state is persisted between multiple invocations. It can be either:
* - A Zod object
* - A Zod optional object
* - A Zod default object
* - Undefined
*/
stateSchema?: TSchema;
/**
* The schema of the middleware context. Middleware context is read-only and not persisted between multiple invocations. It can be either:
* - A Zod object
* - A Zod optional object
* - A Zod default object
* - Undefined
*/
contextSchema?: TContextSchema;
/**
* Additional tools registered by the middleware.
*/
tools?: (ClientTool | ServerTool)[];
/**
* Wraps tool execution with custom logic. This allows you to:
* - Modify tool call parameters before execution
* - Handle errors and retry with different parameters
* - Post-process tool results
* - Implement caching, logging, authentication, or other cross-cutting concerns
* - Return Command objects for advanced control flow
*
* The handler receives a ToolCallRequest containing the tool call, state, and runtime,
* along with a handler function to execute the actual tool.
*
* @param request - The tool call request containing toolCall, state, and runtime.
* @param handler - The function that executes the tool. Call this with a ToolCallRequest to get the result.
* @returns The tool result as a ToolMessage or a Command for advanced control flow.
*
* @example
* ```ts
* wrapToolCall: async (request, handler) => {
* console.log(`Calling tool: ${request.tool.name}`);
* console.log(`Tool description: ${request.tool.description}`);
*
* try {
* // Execute the tool
* const result = await handler(request);
* console.log(`Tool ${request.tool.name} succeeded`);
* return result;
* } catch (error) {
* console.error(`Tool ${request.tool.name} failed:`, error);
* // Could return a custom error message or retry
* throw error;
* }
* }
* ```
*
* @example Authentication
* ```ts
* wrapToolCall: async (request, handler) => {
* // Check if user is authorized for this tool
* if (!request.runtime.context.isAuthorized(request.tool.name)) {
* return new ToolMessage({
* content: "Unauthorized to call this tool",
* tool_call_id: request.toolCall.id,
* });
* }
* return handler(request);
* }
* ```
*
* @example Caching
* ```ts
* const cache = new Map();
* wrapToolCall: async (request, handler) => {
* const cacheKey = `${request.tool.name}:${JSON.stringify(request.toolCall.args)}`;
* if (cache.has(cacheKey)) {
* return cache.get(cacheKey);
* }
* const result = await handler(request);
* cache.set(cacheKey, result);
* return result;
* }
* ```
*/
wrapToolCall?: WrapToolCallHook<TSchema, TFullContext>;
/**
* Wraps the model invocation with custom logic. This allows you to:
* - Modify the request before calling the model
* - Handle errors and retry with different parameters
* - Post-process the response
* - Implement custom caching, logging, or other cross-cutting concerns
*
* @param request - The model request containing model, messages, systemPrompt, tools, state, and runtime.
* @param handler - The function that invokes the model. Call this with a ModelRequest to get the response.
* @returns The response from the model (or a modified version).
*
* @example
* ```ts
* wrapModelCall: async (request, handler) => {
* // Modify request before calling
* const modifiedRequest = { ...request, systemPrompt: "You are helpful" };
*
* try {
* // Call the model
* return await handler(modifiedRequest);
* } catch (error) {
* // Handle errors and retry with fallback
* const fallbackRequest = { ...request, model: fallbackModel };
* return await handler(fallbackRequest);
* }
* }
* ```
*/
wrapModelCall?: WrapModelCallHook<TSchema, TFullContext>;
/**
* The function to run before the agent execution starts. This function is called once at the start of the agent invocation.
* It allows to modify the state of the agent before any model calls or tool executions.
*
* @param state - The middleware state
* @param runtime - The middleware runtime
* @returns The modified middleware state or undefined to pass through
*/
beforeAgent?: BeforeAgentHook<TSchema, TFullContext>;
/**
* The function to run before the model call. This function is called before the model is invoked and before the `wrapModelCall` hook.
* It allows to modify the state of the agent.
*
* @param state - The middleware state
* @param runtime - The middleware runtime
* @returns The modified middleware state or undefined to pass through
*/
beforeModel?: BeforeModelHook<TSchema, TFullContext>;
/**
* The function to run after the model call. This function is called after the model is invoked and before any tools are called.
* It allows to modify the state of the agent after the model is invoked, e.g. to update tool call parameters.
*
* @param state - The middleware state
* @param runtime - The middleware runtime
* @returns The modified middleware state or undefined to pass through
*/
afterModel?: AfterModelHook<TSchema, TFullContext>;
/**
* The function to run after the agent execution completes. This function is called once at the end of the agent invocation.
* It allows to modify the final state of the agent after all model calls and tool executions are complete.
*
* @param state - The middleware state
* @param runtime - The middleware runtime
* @returns The modified middleware state or undefined to pass through
*/
afterAgent?: AfterAgentHook<TSchema, TFullContext>;
}
/**
* Helper type to filter out properties that start with underscore (private properties)
*/
type FilterPrivateProps<T> = { [K in keyof T as K extends `_${string}` ? never : K]: T[K] };
/**
* Helper type to infer the state schema type from a middleware
* This filters out private properties (those starting with underscore)
*/
type InferMiddlewareState<T extends AgentMiddleware> = T extends AgentMiddleware<infer S, any, any> ? S extends InteropZodObject ? FilterPrivateProps<InferInteropZodOutput<S>> : {} : {};
/**
* Helper type to infer the input state schema type from a middleware (all properties optional)
* This filters out private properties (those starting with underscore)
*/
type InferMiddlewareInputState<T extends AgentMiddleware> = T extends AgentMiddleware<infer S, any, any> ? S extends InteropZodObject ? FilterPrivateProps<InferInteropZodInput<S>> : {} : {};
/**
* Helper type to infer merged state from an array of middleware (just the middleware states)
*/
type InferMiddlewareStates<T = AgentMiddleware[]> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends AgentMiddleware ? Rest extends readonly AgentMiddleware[] ? InferMiddlewareState<First> & InferMiddlewareStates<Rest> : InferMiddlewareState<First> : {} : {};
/**
* Helper type to infer merged input state from an array of middleware (with optional defaults)
*/
type InferMiddlewareInputStates<T extends readonly AgentMiddleware[]> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends AgentMiddleware ? Rest extends readonly AgentMiddleware[] ? InferMiddlewareInputState<First> & InferMiddlewareInputStates<Rest> : InferMiddlewareInputState<First> : {} : {};
/**
* Helper type to infer merged state from an array of middleware (includes built-in state)
*/
/**
* Helper type to infer the input context schema type from a middleware (with optional defaults)
*/
type InferMiddlewareContextInput<T extends AgentMiddleware> = T extends AgentMiddleware<any, infer C, any> ? C extends InteropZodOptional<infer Inner> ? InferInteropZodInput<Inner> | undefined : C extends InteropZodObject ? InferInteropZodInput<C> : {} : {};
/**
* Helper type to infer merged context from an array of middleware
*/
/**
* Helper to merge two context types, preserving undefined unions
*/
type MergeContextTypes<A, B> = [A] extends [undefined] ? [B] extends [undefined] ? undefined : B | undefined : [B] extends [undefined] ? A | undefined : [A] extends [B] ? A : [B] extends [A] ? B : A & B;
/**
* Helper type to infer merged input context from an array of middleware (with optional defaults)
*/
type InferMiddlewareContextInputs<T extends readonly AgentMiddleware[]> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends AgentMiddleware ? Rest extends readonly AgentMiddleware[] ? MergeContextTypes<InferMiddlewareContextInput<First>, InferMiddlewareContextInputs<Rest>> : InferMiddlewareContextInput<First> : {} : {};
/**
* Helper type to extract input type from context schema (with optional defaults)
*/
type InferContextInput<ContextSchema extends AnyAnnotationRoot | InteropZodObject> = ContextSchema extends InteropZodObject ? InferInteropZodInput<ContextSchema> : ContextSchema extends AnyAnnotationRoot ? ToAnnotationRoot<ContextSchema>["State"] : {};
type ToAnnotationRoot<A extends AnyAnnotationRoot | InteropZodObject> = A extends AnyAnnotationRoot ? A : A extends InteropZodObject ? AnnotationRoot<InteropZodToStateDefinition<A>> : never;
type InferSchemaInput<A extends AnyAnnotationRoot | InteropZodObject | undefined> = A extends AnyAnnotationRoot | InteropZodObject ? ToAnnotationRoot<A>["State"] : {};
//#endregion
export { AfterAgentHook, AfterModelHook, AgentMiddleware, AnyAnnotationRoot, BeforeAgentHook, BeforeModelHook, InferContextInput, InferMiddlewareContextInputs, InferMiddlewareInputStates, InferMiddlewareStates, InferSchemaInput, ToAnnotationRoot, ToolCallHandler, ToolCallRequest, WrapModelCallHook, WrapToolCallHook };
//# sourceMappingURL=types.d.ts.map