fix(integrations): carry ToolMessage.error onto the tool-result flag in four more adapters - #2317
Conversation
…in four more adapters The same one-line omission fixed for LangGraph in ag-ui-protocol#2263 is present in several other first-party adapters: AG-UI's ToolMessage.error is not read when an incoming tool result is converted into the target framework's tool-result shape, so a client-reported tool failure is handed to the model as a success. Per the standard agreed on ag-ui-protocol#2306, set the framework's error flag from bool(error) (flag only; text is not folded because every target here has a dedicated flag): langchain/typescript ToolMessage status (verbatim ag-ui-protocol#2263); aws-strands/python Bedrock toolResult status (was pinned to success); vercel-ai-sdk/typescript AI SDK v4 tool-result isError; mastra/typescript AI SDK v4 tool-result isError. Both vercel-ai-sdk and mastra resolve AI SDK v4, whose ToolResultPart already carries isError; no version gate is needed. Also fix aws-strands _build_snapshot_messages, an AG-UI to AG-UI rebuild of the client's own messages: it dropped the client's error and encrypted_value on the snapshot echo. Copy both through. A test is added next to each adapter's conversion tests. Fixes ag-ui-protocol#2306
Python Preview PackagesVersion
Install with uvAdd the TestPyPI index to your [[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
explicit = trueThen install the packages you need: # Core SDK
uv add 'ag-ui-protocol==0.0.0.dev1785911101' --index testpypi
# Integrations (each already depends on the matching ag-ui-protocol preview)
uv add 'ag-ui-langgraph==0.0.0.dev1785911101' --index testpypi
uv add 'ag-ui-crewai==0.0.0.dev1785911101' --index testpypi
# NOTE: ag-ui-agent-spec depends on pyagentspec (git-only, not on PyPI).
# You will need to install pyagentspec separately from its git repo.
uv add 'ag-ui-agent-spec==0.0.0.dev1785911101' --index testpypi
uv add 'ag_ui_adk==0.0.0.dev1785911101' --index testpypi
uv add 'ag_ui_strands==0.0.0.dev1785911101' --index testpypiInstall with pippip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
ag-ui-protocol==0.0.0.dev1785911101
Commit: a31af59 |
@ag-ui/a2a-middleware
@ag-ui/a2ui-middleware
@ag-ui/event-throttle-middleware
@ag-ui/mcp-apps-middleware
@ag-ui/mcp-middleware
@ag-ui/a2a
@ag-ui/adk
@ag-ui/ag2
@ag-ui/agno
@ag-ui/aws-strands
@ag-ui/claude-agent-sdk
@ag-ui/claude-managed-agents
@ag-ui/crewai
@ag-ui/langchain
@ag-ui/langgraph
@ag-ui/llamaindex
@ag-ui/mastra
@ag-ui/pydantic-ai
@ag-ui/vercel-ai-sdk
@ag-ui/watsonx
@ag-ui/a2ui-toolkit
create-ag-ui-app
@ag-ui/client
@ag-ui/core
@ag-ui/encoder
@ag-ui/proto
commit: |
BenTaylorDev
left a comment
There was a problem hiding this comment.
Approving. CI is green across all 42 checks on 8cf5b879, and this holds up on review.
What I verified beyond reading the diff:
- Consistent with the merged #2316 and #2263. Every site derives the flag from
bool(error)/!!message.error, with no sentinel — correct, since the sentinel belongs only to the reverse direction. The five adapters now hold one rule. - The AI SDK version claims check out.
integrations/vercel-ai-sdk/typescriptresolvesai@4.3.19, whoseToolResultPartcarriesisError?: boolean. For mastra I went a level deeper, since that was the flagged uncertainty on #2306:@mastra/core@1.0.4exportsCoreMessage = AiCoreMessagefrom its bundled_types/@internal_ai-sdk-v4, and that bundledToolResultPartdoes declareisError?: boolean. - It survives
main's churn.aws-strands/.../agent.pytook 7 commits since this branch's base, including #2343's parallel tool-call rework in the same area. Merged against currentmainin a scratch worktree: no conflict, the post-merge delta is exactly this PR's 8 files, and the aws-strands suite passes at 199 — 195 baseline plus the 4 new tests, collection checked explicitly. - No interaction with the reconcile work.
session_reconcile.pynever writesstatus, so nothing downstream clobbers the flag this PR stamps. - Completeness on the sites in scope.
messages.ts:49is the only AG-UI → LangChain tool conversion; the othertoolCallIdhits across the three TS adapters are outbound streaming rather than conversion. In aws-strands,client_proxy_tool.py:58anda2ui_tool.py:640do hardcode"success", but those are placeholder and envelope results that genuinely are always successful.
One follow-up, filed as #2361 rather than held against this PR: the aws-strands fix reaches the replay_history branch only. _build_strands_history has a single caller gated on session_manager is None (agent.py:1040), so when a session_manager_provider is configured the model reads persisted toolResult blocks created by the proxy with status: "success", and _correct_message rewrites only content. A failed frontend tool is still reported as a success on that path. That's outside what #2306 scoped, and the default configuration (replay_history_into_strands=True, no session manager) takes the branch you fixed — so this is a widening job, not a defect here.
Nice work getting all four adapters onto one rule in a single pass, and for checking the AI SDK version question rather than assuming copy-paste.
Fixes #2306.
Problem
The one-line omission fixed for LangGraph in #2263 is present in several other first-party adapters: AG-UI's
ToolMessage.erroris not read when an incoming tool result is converted into the target framework's tool-result shape, so a client-reported tool failure is handed to the model as a success.Fix
Per the standard agreed on #2306: set the framework's error flag from
bool(error). Flag only — the text is not folded into content, because every target here has a dedicated flag (that carve-out only applies to transports with no flag, e.g.claude-managed-agents).langchain/typescriptmessages.tsstatus: message.error ? "error" : "success"(verbatim #2263)aws-strands/pythonagent.py_build_strands_historytoolResultstatus was pinned to"success"→ derive fromerrorvercel-ai-sdk/typescriptindex.tsisError: !!message.errormastra/typescriptutils.tsisError: !!message.errorAI SDK version
Both
vercel-ai-sdkandmastraresolve AI SDK v4, whoseToolResultPartalready carriesisError— no version gate needed.mastrabuilds the v4CoreMessagetype (theas CoreMessagecast atutils.ts:212is what currently hides the missing field fromtsc), so its behavior is pinned with a test rather than relying on a type read.Bonus: aws-strands snapshot echo
_build_snapshot_messagesis an AG-UI → AG-UI rebuild of the client's own messages (it seedsMessagesSnapshotEvent). It dropped the client's ownerrorandencrypted_valueon the echo. Both are now copied through. This one has no framework mapping and no invent-the-text question — it is a plain field copy.Scope
Flag only, one PR for all four adapters plus the snapshot fix, matching the group decision on #2306. The
docs/concepts/tools.mdxexample is being handled separately.Tests
A test is added next to each adapter's conversion tests, matching #2263's shape.
mastra: full package suite green, 304 tests (2 existing tool-result assertions updated for the always-presentisError).langchain/typescript: newmessages.test.ts, 13 tests green.vercel-ai-sdk/typescript: newmessages.test.ts, 8 tests green.aws-strands/python: newtest_tool_error_status.py,pytest tests/green — 180 passed, 2 skipped.