Skip to content

[v6.0] fix(langchain): register key mapping for tool calls emitted via messages mode for HITL interrupt matching#16790

Merged
gr2m merged 1 commit into
release-v6.0from
backport-v6.0/fix-15793
Jul 6, 2026
Merged

[v6.0] fix(langchain): register key mapping for tool calls emitted via messages mode for HITL interrupt matching#16790
gr2m merged 1 commit into
release-v6.0from
backport-v6.0/fix-15793

Conversation

@gr2m

@gr2m gr2m commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Backport of #15793 to release-v6.0 (clean cherry-pick). Registers emittedToolCallsByKey for tool calls already emitted via messages mode, fixing LangGraph HITL interrupt matching (orphaned approval IDs, duplicate events).

Part of the v6.0 backport tracking issue #16767.

…ges mode for HITL interrupt matching (#15793)

## Background

When using `@ai-sdk/langchain` with `streamMode: ["messages", "values"]`
for LangGraph HITL (Human-in-the-Loop) workflows, the `__interrupt__`
handler fails to match tool calls that were already emitted via the
`messages` stream mode.

In `processLangGraphEvent`, tool calls emitted through `messages` events
are added to `emittedToolCalls` (Set) but **not** to
`emittedToolCallsByKey` (Map). When the subsequent `values` event
arrives with the same tool call, the values mode tool call loop skips it
because `emittedToolCalls.has(toolCall.id)` is already true — but this
also skips the `emittedToolCallsByKey.set()` registration. When the
`__interrupt__` handler then tries
`emittedToolCallsByKey.get(toolCallKey)`, it fails and falls back to
generating a new ID like `hitl-delete_file-1234567890`.

This causes:
1. `tool-approval-request` gets a mismatched `toolCallId` (orphaned from
the original tool call card in the UI)
2. Duplicate `tool-input-start` / `tool-input-available` events are
emitted for the same tool call

## Summary

Added an `else if` branch in the values mode tool call loop to register
the key mapping for tool calls that were already emitted via messages
mode:

```typescript
} else if (toolCall.id && emittedToolCalls.has(toolCall.id)) {
  // Register key mapping for tool calls already emitted via messages mode
  // so that __interrupt__ handling can match them by key
  const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;
  emittedToolCallsByKey.set(toolCallKey, toolCall.id);
}
```

This is consistent with the existing key mapping pattern at L1292
(values finalization block).

**Changes:**
- `packages/langchain/src/utils.ts`: 5-line else-if branch addition
- `packages/langchain/src/adapter.test.ts`: 2 new test cases for the
dual streamMode scenario
- Updated existing HITL snapshot to reflect correct tool call ID
matching

## Manual Verification

Verified in a production application using `createReactAgent` +
`interrupt()` + `streamMode: ["messages", "values"]`:
- Before fix: `tool-approval-request` gets fallback ID → orphaned
approval card in UI
- After fix: `tool-approval-request` correctly references the original
`toolCallId` → approval card connects to the existing tool call card

The existing HITL fixture test (`LANGGRAPH_RESPONSE_1`) also
demonstrates the fix — the snapshot previously contained the fallback ID
`hitl-delete_file-1234567890`, now correctly shows the original
`call_LOd3dMxgYxmNLWZVWXra9xWQ`.

## Related Issues

* Fixes #12797
* Builds on and superseeds #12798

Co-authored-by: domuk-k
[dannyworks102@gmail.com](mailto:dannyworks102@gmail.com)

(cherry picked from commit 6e23bf2)
@gr2m gr2m added the backport Admins only: add this label to a pull request in order to backport it to the prior version label Jul 6, 2026
@gr2m gr2m merged commit ea6eb0a into release-v6.0 Jul 6, 2026
52 checks passed
@gr2m gr2m deleted the backport-v6.0/fix-15793 branch July 6, 2026 20:06
github-actions Bot added a commit that referenced this pull request Jul 6, 2026
@github-actions github-actions Bot removed the backport Admins only: add this label to a pull request in order to backport it to the prior version label Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

⚠️ Backport to release-v5.0 created but has conflicts: #16818

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants