Skip to content

feat(agents): execute approved tool calls even when others are rejected#10186

Open
pawel-twardziak wants to merge 8 commits intolangchain-ai:mainfrom
pawel-twardziak:feat/hitl-no-batch-rejection-when-some-actions-rejected
Open

feat(agents): execute approved tool calls even when others are rejected#10186
pawel-twardziak wants to merge 8 commits intolangchain-ai:mainfrom
pawel-twardziak:feat/hitl-no-batch-rejection-when-some-actions-rejected

Conversation

@pawel-twardziak
Copy link
Contributor

@pawel-twardziak pawel-twardziak commented Feb 27, 2026

humanInTheLoopMiddleware currently uses an all-or-nothing approach for mixed-decision batches: if any
tool call in a batch is rejected by the human operator, execution returns to the model and the
approved/edited calls are not executed in that round. This diverges from the Python SDK behavior where
rejected actions produce a ToolMessage with status: "error" while approved actions proceed to execution
immediately.

This PR adds an opt-in executeApprovedOnReject option that aligns JS behavior with Python.

Changes

libs/langchain/src/agents/middleware/hitl.ts

  • Adds executeApprovedOnReject: boolean (default false) to HumanInTheLoopMiddlewareConfig
  • Adds "tools" to canJumpTo so the middleware can jump directly to tool execution when applicable
  • When executeApprovedOnReject: true and the batch contains a mix of approved/rejected decisions:
    • Rejected tool calls produce an artificial ToolMessage with status: "error" and the rejection message as content
    • Approved/edited tool calls remain in the AI message's tool_calls and jumpTo is set to "tools"ToolNode automatically skips calls that already have a ToolMessage, so only the approved calls execute
    • If all calls in the batch are rejected, jumpTo falls back to "model" (same as legacy behavior)
  • executeApprovedOnReject: false (default) preserves the existing behavior exactly — no breaking changes

Behavior comparison

Scenario executeApprovedOnReject: false (default) executeApprovedOnReject: true
All approved Tools execute Tools execute
All rejected Returns to model Returns to model
Mixed (approve + reject) Returns to model; approved not executed yet Approved tools execute; rejected → ToolMessage(status="error")

Tests

Two new test cases added to libs/langchain/src/agents/middleware/tests/hitl.test.ts:

  1. Mixed batch — one approved, one rejected with executeApprovedOnReject: true: asserts the approved tool function is called once, the rejected function is never called, and the resulting ToolMessage for the rejected call has status: "error" with the rejection message as content
  2. All-rejected batch with executeApprovedOnReject: true: asserts neither tool is called and the graph returns to the model (same as legacy)

Related to #10176

@changeset-bot
Copy link

changeset-bot bot commented Feb 27, 2026

🦋 Changeset detected

Latest commit: aaf0902

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
langchain Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pawel-twardziak pawel-twardziak changed the title feat(agents): execute approved tool calls even when others are reject… feat(agents): execute approved tool calls even when others are rejected Feb 27, 2026
@pawel-twardziak
Copy link
Contributor Author

Christian Bromann (@christian-bromann) and Hunter Lovell (@hntrl) here is the python PR for this feature langchain-ai/langchain#32996

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant