Skip to content

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

Merged
lgrammel merged 2 commits into
vercel:mainfrom
cristiandrei1234:fix-langchain-python-aimessagechunk
May 26, 2026
Merged

fix(langchain): recognize Python AIMessageChunk type in RemoteGraph streams#15196
lgrammel merged 2 commits into
vercel:mainfrom
cristiandrei1234:fix-langchain-python-aimessagechunk

Conversation

@cristiandrei1234
Copy link
Copy Markdown
Contributor

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) instead of the TypeScript type === 'ai' (TypeScript source). 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

  • All commits are signed (PRs with unsigned commits cannot be merged)
  • Tests have been added / updated (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features) — JSDoc on isAIMessageChunk
  • A patch changeset for relevant packages has been added (for bug fixes / features - run pnpm changeset in the project root)
  • 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.

@lgrammel lgrammel closed this May 26, 2026
@lgrammel lgrammel reopened this May 26, 2026
@lgrammel lgrammel closed this May 26, 2026
@lgrammel lgrammel reopened this May 26, 2026
@lgrammel lgrammel added the backport Admins only: add this label to a pull request in order to backport it to the prior version label May 26, 2026
@lgrammel lgrammel merged commit 62ae6c7 into vercel:main May 26, 2026
50 of 51 checks passed
github-actions Bot added a commit that referenced this pull request May 26, 2026
…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>
@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 May 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

✅ Backport PR created: #15604

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Published in:

Package Version
ai 7.0.0-canary.153 github npm
@ai-sdk/alibaba 2.0.0-canary.55 github npm
@ai-sdk/amazon-bedrock 5.0.0-canary.70 github npm
@ai-sdk/angular 3.0.0-canary.153 github npm
@ai-sdk/anthropic 4.0.0-canary.60 github npm
@ai-sdk/anthropic-aws 1.0.0-canary.1 github npm
@ai-sdk/assemblyai 3.0.0-canary.46 github npm
@ai-sdk/azure 4.0.0-canary.64 github npm
@ai-sdk/baseten 2.0.0-canary.52 github npm
@ai-sdk/black-forest-labs 2.0.0-canary.46 github npm
@ai-sdk/bytedance 2.0.0-canary.46 github npm
@ai-sdk/cerebras 3.0.0-canary.52 github npm
@ai-sdk/cohere 4.0.0-canary.48 github npm
@ai-sdk/deepgram 3.0.0-canary.45 github npm
@ai-sdk/deepinfra 3.0.0-canary.52 github npm
@ai-sdk/deepseek 3.0.0-canary.49 github npm
@ai-sdk/elevenlabs 3.0.0-canary.45 github npm
@ai-sdk/fal 3.0.0-canary.45 github npm
@ai-sdk/fireworks 3.0.0-canary.52 github npm
@ai-sdk/gateway 4.0.0-canary.92 github npm
@ai-sdk/gladia 3.0.0-canary.45 github npm
@ai-sdk/google 4.0.0-canary.73 github npm
@ai-sdk/google-vertex 5.0.0-canary.95 github npm
@ai-sdk/groq 4.0.0-canary.48 github npm
@ai-sdk/huggingface 2.0.0-canary.52 github npm
@ai-sdk/hume 3.0.0-canary.45 github npm
@ai-sdk/klingai 4.0.0-canary.46 github npm
@ai-sdk/langchain 3.0.0-canary.153 github npm
@ai-sdk/llamaindex 3.0.0-canary.153 github npm
@ai-sdk/lmnt 3.0.0-canary.45 github npm
@ai-sdk/luma 3.0.0-canary.45 github npm
@ai-sdk/mcp 2.0.0-canary.54 github npm
@ai-sdk/mistral 4.0.0-canary.50 github npm
@ai-sdk/moonshotai 3.0.0-canary.52 github npm
@ai-sdk/open-responses 2.0.0-canary.48 github npm
@ai-sdk/openai 4.0.0-canary.64 github npm
@ai-sdk/openai-compatible 3.0.0-canary.52 github npm
@ai-sdk/otel 1.0.0-canary.99 github npm
@ai-sdk/perplexity 4.0.0-canary.48 github npm
@ai-sdk/prodia 2.0.0-canary.48 github npm
@ai-sdk/provider-utils 5.0.0-canary.44 github npm
@ai-sdk/quiverai 2.0.0-canary.1 github npm
@ai-sdk/react 4.0.0-canary.155 github npm
@ai-sdk/replicate 3.0.0-canary.46 github npm
@ai-sdk/revai 3.0.0-canary.46 github npm
@ai-sdk/rsc 3.0.0-canary.154 github npm
@ai-sdk/svelte 5.0.0-canary.153 github npm
@ai-sdk/togetherai 3.0.0-canary.52 github npm
@ai-sdk/valibot 3.0.0-canary.44 github npm
@ai-sdk/vercel 3.0.0-canary.52 github npm
@ai-sdk/voyage 2.0.0-canary.19 github npm
@ai-sdk/vue 4.0.0-canary.153 github npm
@ai-sdk/workflow 1.0.0-canary.70 github npm
@ai-sdk/xai 4.0.0-canary.68 github npm

lgrammel added a commit that referenced this pull request May 27, 2026
…oteGraph streams (#15604)

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

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: cristiandrei1234 <cristiandrei1234@users.noreply.github.com>
Co-authored-by: Lars Grammel <lars.grammel@gmail.com>
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.

LangChain toUIMessageStream doesn't handle RemoteGraph stream properly from Python server

2 participants