Skip to content

Backport: fix(langchain): recognize Python AIMessageChunk type in RemoteGraph streams#15604

Merged
lgrammel merged 1 commit into
release-v6.0from
backport-pr-15196-to-release-v6.0
May 27, 2026
Merged

Backport: fix(langchain): recognize Python AIMessageChunk type in RemoteGraph streams#15604
lgrammel merged 1 commit into
release-v6.0from
backport-pr-15196-to-release-v6.0

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

This is an automated backport of #15196 to the release-v6.0 branch. FYI @cristiandrei1234

…treams (#15196)

## Background

`@ai-sdk/langchain`'s `toUIMessageStream` adapter handles plain JSON
message objects from LangGraph `RemoteGraph` streams. The type guard
`isAIMessageChunk` and the `values`-event `tool_calls` extraction in
`processLangGraphEvent` both match `obj.type === 'ai'`, which is the
discriminator used by TypeScript `langchain-core`.

Python `langchain-core` serializes streaming chunks with `type ===
'AIMessageChunk'` ([Python
source](https://github.com/langchain-ai/langchain/blob/master/libs/core/langchain_core/messages/ai.py))
instead of the TypeScript `type === 'ai'` ([TypeScript
source](https://github.com/langchain-ai/langchainjs/blob/main/libs/langchain-core/src/messages/ai.ts)).
Plain Python message objects fall through both gates.

User-visible symptom: when streaming from a Python LangGraph server
(`langgraph new --python`, LangSmith Cloud Python deployments,
RemoteGraph against a Python deployment), `start`, `start-step`,
`finish-step`, and `finish` arrive in the UI stream, but `text-start` /
`text-delta` / `text-end` and tool-call events never do. The model
output is silently lost.

## Summary

`packages/langchain/src/utils.ts`:

- `isAIMessageChunk`: also match `obj.type === 'AIMessageChunk'` for
plain message objects; JSDoc updated to document both discriminators.
- `processLangGraphEvent` `values` branch: also recognize `obj.type ===
'AIMessageChunk'` when extracting `tool_calls` from non-streamed
messages.

The change is intentionally narrow — no behavior change for TypeScript
callers, only widens the accepted discriminator for plain RemoteGraph
objects.

## Manual Verification

Reproduced against `@ai-sdk/langchain@2.0.162` (stable) and
`@ai-sdk/langchain@3.0.0-canary.131` (canary) using a standalone
async-iterable mock that emits `['messages', [chunk, metadata]]` events
with both shapes (`type: 'ai'` vs `type: 'AIMessageChunk'`):

- Before fix: TypeScript shape produced 2 `text-delta` UIMessageChunks,
Python shape produced 0.
- After fix (patched `dist/index.js` locally): both shapes produced
identical output (`text-start`, 2 `text-delta`, `text-end`).

Then verified at the source level: the three new regression tests fail
on unfixed `main`, all 190 langchain tests pass with the fix applied.

## Checklist

- [x] All commits are signed (PRs with unsigned commits cannot be
merged)
- [x] Tests have been added / updated (for bug fixes / features)
- [x] Documentation has been added / updated (for bug fixes / features)
— JSDoc on `isAIMessageChunk`
- [x] A _patch_ changeset for relevant packages has been added (for bug
fixes / features - run `pnpm changeset` in the project root)
- [x] I have reviewed this pull request (self-review)

## Future Work

`isToolMessageType` (same file) uses the equivalent `obj.type ===
'tool'` pattern. Python `langchain-core` also uses the `'tool'` literal
for `ToolMessage`, so it is not affected by this bug — but if future
Python versions emit class-name discriminators (`'ToolMessage'`), a
parallel guard would be needed. Out of scope here.

I deliberately did not add a runnable example under `examples/` (per
AGENTS.md "When to Deviate"): exercising the bug end-to-end requires a
Python LangGraph server, which is impractical for a TypeScript monorepo
example, and the new unit tests serve as a deterministic, in-process
reproduction. Happy to add one if maintainers prefer.

## Related Issues

Fixes #14341.

Co-authored-by: cristiandrei1234 <cristiandrei1234@users.noreply.github.com>
Co-authored-by: Lars Grammel <lars.grammel@gmail.com>
Copy link
Copy Markdown
Contributor

@vercel vercel Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

isToolMessageType fails to recognize ToolMessageChunk from Python RemoteGraph streams because it only checks for type === 'tool', missing the Python langchain-core type: "ToolMessageChunk" format.

Fix on Vercel

@gr2m gr2m closed this May 26, 2026
auto-merge was automatically disabled May 26, 2026 23:00

Pull request was closed

@gr2m gr2m reopened this May 26, 2026
@lgrammel lgrammel merged commit 63847a6 into release-v6.0 May 27, 2026
47 checks passed
@lgrammel lgrammel deleted the backport-pr-15196-to-release-v6.0 branch May 27, 2026 10:55
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