Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions libs/langchain/src/agents/middleware/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,18 @@ export interface ToolCallRequest<
*/
toolCall: ToolCall;
/**
* The BaseTool instance being invoked.
* The BaseTool instance being invoked, or undefined if the tool is not
* registered with the ToolNode.
*
* Provides access to tool metadata like name, description, schema, etc.
*
* When tool is undefined, this indicates an unregistered tool (e.g., schema-less
* tools like Anthropic's text editor). Middleware can handle these by checking
* the tool name and returning a result without calling the handler. If the
* handler is called with an unregistered tool, validation will occur and return
* an error message.
*/
tool: ClientTool | ServerTool;
tool: ClientTool | ServerTool | undefined;
/**
* The current agent state (includes both middleware state and built-in state).
*/
Expand Down
24 changes: 17 additions & 7 deletions libs/langchain/src/agents/nodes/ToolNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,20 @@ export class ToolNode<
const baseHandler = async (
request: ToolCallRequest
): Promise<ToolMessage | Command> => {
const { toolCall } = request;
const tool = this.tools.find((tool) => tool.name === toolCall.name);
const { toolCall, tool } = request;

/**
* Validate tool exists when we actually need to execute it.
* This validation is deferred to allow wrapToolCall middleware to
* short-circuit requests for unregistered tools.
*/
if (tool === undefined) {
throw new Error(`Tool "${toolCall.name}" not found.`);
return new ToolMessage({
name: toolCall.name,
content: `Error: ${toolCall.name} is not a valid tool, try one of the registered tools.`,
tool_call_id: toolCall.id!,
status: "error",
});
}

try {
Expand Down Expand Up @@ -354,12 +364,12 @@ export class ToolNode<
};

/**
* Find the tool instance to include in the request
* Find the tool instance to include in the request.
* Note: tool may be undefined for unregistered tools (e.g., schema-less tools
* like Anthropic's text editor). Validation is deferred to allow wrapToolCall
* middleware to intercept and handle unregistered tools.
*/
const tool = this.tools.find((t) => t.name === call.name);
if (!tool) {
throw new Error(`Tool "${call.name}" not found.`);
}

const request = {
toolCall: call,
Expand Down
Loading
Loading