// How do you stop a LangChain agent from retrying? // Teaching excerpts; see the explanation and boundaries on the episode page. // Use the native tool-call limiter import { createAgent, tool, toolCallLimitMiddleware, ToolCallLimitExceededError as LimitError } from 'langchain'; import { z } from 'zod'; export function makeSupportAgent(model, read) { const lookup = tool(({ ticket }) => read(ticket), { name: 'lookup', description: 'Read the status of my support ticket', schema: z.object({ ticket: z.string() }), }); return createAgent({ model, tools: [lookup], middleware: [toolCallLimitMiddleware({ runLimit: 3, exitBehavior: 'error', })], }); } // Return an incomplete result at the application boundary // LimitError is imported above. export async function runSupport(agent, request) { try { const result = await agent.invoke(request); return { status: 'answered', message: result.messages.at(-1).content }; } catch (error) { if (!(error instanceof LimitError)) throw error; return { status: 'incomplete', reason: 'tool_limit' }; } } // Predict the result before running the fixture // Sequential failure fixture { status: "incomplete", reason: "tool_limit" } // Successful first lookup fixture { status: "answered", message: "Ticket 42 is open" }