OptionalafterThe 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.
OptionalafterThe 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.
OptionalbeforeThe 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.
OptionalbeforeThe 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.
OptionalcontextThe schema of the middleware context. Middleware context is read-only and not persisted between multiple invocations. It can be either:
The name of the middleware.
OptionalstateThe schema of the middleware state. Middleware state is persisted between multiple invocations. It can be either:
OptionaltoolsAdditional tools registered by the middleware.
OptionalwrapWraps the model invocation with custom logic. This allows you to:
The model request containing model, messages, systemPrompt, tools, state, and runtime.
The function that invokes the model. Call this with a ModelRequest to get the response.
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);
}
}
OptionalwrapWraps tool execution with custom logic. This allows you to:
The handler receives a ToolCallRequest containing the tool call, state, and runtime, along with a handler function to execute the actual tool.
The function that executes the tool. Call this with a ToolCallRequest to get the result.
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;
}
}
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);
}
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;
}
Base middleware interface.