langchain.js
    Preparing search index...

    Function humanInTheLoopMiddleware

    • Creates a Human-in-the-Loop (HITL) middleware for tool approval and oversight.

      This middleware intercepts tool calls made by an AI agent and provides human oversight capabilities before execution. It enables selective approval workflows where certain tools require human intervention while others can execute automatically.

      A invocation result that has been interrupted by the middleware will have a __interrupt__ property that contains the interrupt request. You can loop over the request to determine which tools were interrupted, and how to handle them separately.

      import { type ToolApprovalRequest, type HumanInTheLoopMiddlewareHumanResponse } from "langchain";
      import { type Interrupt } from "langchain";

      const result = await agent.invoke(request);
      const interruptRequest = initialResult.__interrupt__?.[0] as Interrupt<
      ToolApprovalRequest[]
      >;
      const resume: HumanInTheLoopMiddlewareHumanResponse[] =
      interruptRequest.value.map((request) => {
      if (request.action === "calculator") {
      return { id: request.toolCallId, type: "accept" };
      } else if (request.action === "write_file") {
      return {
      id: request.toolCallId,
      type: "edit",
      args: { filename: "safe.txt", content: "Safe content" },
      };
      }

      throw new Error(`Unknown action: ${request.action}`);
      });

      // Resume with approval
      await agent.invoke(new Command({ resume }), config);
      • Selective Tool Approval: Configure which tools require human approval
      • Multiple Response Types: Accept, edit, ignore, or manually respond to tool calls
      • Asynchronous Workflow: Uses LangGraph's interrupt mechanism for non-blocking approval
      • Custom Approval Messages: Provide context-specific descriptions for approval requests

      When a tool requires approval, the human operator can respond with:

      • accept: Execute the tool with original arguments
      • edit: Modify the tool arguments before execution
      • ignore: Skip the tool and terminate the agent
      • response: Provide a manual response instead of executing the tool

      Parameters

      • options: any

        Configuration options for the middleware

      Returns AgentMiddleware<
          undefined,
          ZodObject<
              {
                  descriptionPrefix: ZodDefault<ZodString>;
                  interruptOn: ZodOptional<
                      ZodRecord<
                          ZodString,
                          ZodUnion<
                              [
                                  ZodBoolean,
                                  ZodObject<
                                      {
                                          allowAccept: ZodOptional<ZodBoolean>;
                                          allowEdit: ZodOptional<ZodBoolean>;
                                          allowRespond: ZodOptional<ZodBoolean>;
                                          description: ZodOptional<ZodString>;
                                      },
                                      "strip",
                                      ZodTypeAny,
                                      {
                                          allowAccept?: boolean;
                                          allowEdit?: boolean;
                                          allowRespond?: boolean;
                                          description?: string;
                                      },
                                      {
                                          allowAccept?: boolean;
                                          allowEdit?: boolean;
                                          allowRespond?: boolean;
                                          description?: string;
                                      },
                                  >,
                              ],
                          >,
                      >,
                  >;
              },
              "strip",
              ZodTypeAny,
              {
                  descriptionPrefix: string;
                  interruptOn?: Record<
                      string,
                      | boolean
                      | {
                          allowAccept?: boolean;
                          allowEdit?: boolean;
                          allowRespond?: boolean;
                          description?: string;
                      },
                  >;
              },
              {
                  descriptionPrefix?: string;
                  interruptOn?: Record<
                      string,
                      | boolean
                      | {
                          allowAccept?: boolean;
                          allowEdit?: boolean;
                          allowRespond?: boolean;
                          description?: string;
                      },
                  >;
              },
          >,
          any,
      >

      A middleware instance that can be passed to createAgent

      Basic usage with selective tool approval

      import { humanInTheLoopMiddleware } from "langchain";
      import { createAgent } from "langchain";

      const hitlMiddleware = humanInTheLoopMiddleware({
      interruptOn: {
      // Interrupt write_file tool and allow edits or accepts
      "write_file": {
      allowEdit: true,
      allowAccept: true,
      description: "⚠️ File write operation requires approval"
      },
      // Auto-approve read_file tool
      "read_file": false
      }
      });

      const agent = createAgent({
      model: "openai:gpt-4",
      tools: [writeFileTool, readFileTool],
      middleware: [hitlMiddleware]
      });

      Handling approval requests

      import { type HumanInTheLoopRequest, type Interrupt } from "langchain";
      import { Command } from "@langchain/langgraph";

      // Initial agent invocation
      const result = await agent.invoke({
      messages: [new HumanMessage("Write 'Hello' to output.txt")]
      }, config);

      // Check if agent is paused for approval
      if (result.__interrupt__) {
      const interruptRequest = initialResult.__interrupt__?.[0] as Interrupt<
      HumanInTheLoopRequest[]
      >;

      // Show tool call details to user
      console.log("Tool:", interruptRequest.value[0].actionRequest);
      console.log("Allowed actions:", interruptRequest.value[0].config);

      // Resume with approval
      await agent.invoke(
      new Command({ resume: [{ type: "accept" }] }),
      config
      );
      }

      Different response types

      // Accept the tool call as-is
      new Command({ resume: [{ type: "accept" }] })

      // Edit the tool arguments
      new Command({
      resume: [{
      type: "edit",
      args: { action: "write_file", args: { filename: "safe.txt", content: "Modified" } }
      }]
      })

      // Skip tool and terminate agent
      new Command({ resume: [{ type: "response" }] })

      // Provide manual response
      new Command({
      resume: [{
      type: "response",
      // this must be a string
      args: "File operation not allowed in demo mode"
      }]
      })

      Production use case with database operations

      const hitlMiddleware = humanInTheLoopMiddleware({
      interruptOn: {
      "execute_sql": {
      allowAccept: true,
      allowEdit: true,
      allowRespond: true,
      description: "🚨 SQL query requires DBA approval\nPlease review for safety and performance"
      },
      "read_schema": false // Reading metadata is safe
      "delete_records": {
      allowAccept: true,
      description: "⛔ DESTRUCTIVE OPERATION - Requires manager approval"
      }
      },
      messagePrefix: "Database operation pending approval"
      });
      • Tool calls are processed in the order they appear in the AI message
      • Auto-approved tools execute immediately without interruption
      • Multiple tools requiring approval are bundled into a single interrupt
      • The middleware operates in the afterModel phase, intercepting before tool execution
      • Requires a checkpointer to maintain state across interruptions
      • createAgent for agent creation
      • Command for resuming interrupted execution