UNPKG

langchain

Version:
71 lines (70 loc) • 2.45 kB
import { MiddlewareError, StructuredOutputParsingError } from "../errors.js"; import { createMiddleware } from "../middleware.js"; import { AIMessage } from "@langchain/core/messages"; import { ModelRefusalError } from "@langchain/core/errors"; // src/agents/middleware/modelRefusal.ts function throwIfRefused(message) { if (!message) return; for (const block of message.contentBlocks) if (block.type === "refusal") throw ModelRefusalError.fromRefusal(block, message); } /** * The `StructuredOutputParsingError` behind `error`, if any. * * Middleware listed after this one wraps errors in `MiddlewareError`, so the * parsing error can sit further down the `cause` chain. */ function parsingError(error) { let current = error; while (MiddlewareError.isInstance(current)) current = current.cause; return current instanceof StructuredOutputParsingError ? current : void 0; } /** * Middleware that throws {@link ModelRefusalError} when the model refuses. * * Providers report a refusal, such as a safety-policy refusal, as a successful * response, so without this middleware the agent run ends as if it succeeded. * The middleware checks each model response for a `refusal` content block, * including refusals that fail to parse under a structured `responseFormat`. * It does not detect refusals the model writes as ordinary text. * * List it after {@link modelFallbackMiddleware} so the fallback catches the * error and retries the request on the next model. `modelRetryMiddleware` does * not retry refusals. * * @example * ```ts * import { * createAgent, * modelFallbackMiddleware, * modelRefusalMiddleware, * } from "langchain"; * * const agent = createAgent({ * model: "anthropic:claude-sonnet-5-5", * tools: [], * middleware: [ * modelFallbackMiddleware("openai:gpt-6.1-sol"), * modelRefusalMiddleware(), * ], * }); * ``` */ function modelRefusalMiddleware() { return createMiddleware({ name: "modelRefusalMiddleware", wrapModelCall: async (request, handler) => { let response; try { response = await handler(request); } catch (error) { throwIfRefused(parsingError(error)?.aiMessage); throw error; } const messages = AIMessage.isInstance(response) ? [response] : response.messages ?? []; for (const message of messages) if (AIMessage.isInstance(message)) throwIfRefused(message); return response; } }); } export { modelRefusalMiddleware }; //# sourceMappingURL=modelRefusal.js.map