ag-ui-protocol / ag-ui-protocol/ag-ui
[Bug]: agui_messages_to_langchain crashes with uncaught JSONDecodeError on malformed tool_call.arguments, permanently wedging the conversation
- Langage dominant
- Python
- Étoiles
- 15.9k
- Forks
- 1.4k
- Merge moyen
- 1 j 17 h
- PR mergées (30 j)
- 163
Description
## Describe the Bug
`agui_messages_to_langchain` (`integrations/langgraph/python/ag_ui_langgraph/utils.py`) does a bare `json.loads(tc.function.arguments)` with no error handling when converting an incoming `AssistantMessage`'s `tool_calls`:
```python
"args": json.loads(tc.function.arguments) if hasattr(tc, "function") and tc.function.arguments else {},
```
If `tc.function.arguments` is a non-empty but invalid JSON string, this raises an uncaught `JSONDecodeError`. Since `messages` is the client's full conversation history, replayed on **every** future run in that thread (not just the one that produced the bad arguments), a single corrupted tool call permanently wedges the entire conversation: every subsequent run crashes identically until the thread is abandoned.
We hit this in production via a related, separate bug: #1016 describes `ag_ui_langgraph`'s own event streaming mismatching `TOOL_CALL_ARGS` deltas to the wrong `tool_call_id` during parallel tool calls. When that happens, a client accumulating those deltas locally (e.g. CopilotKit's frontend) ends up with a corrupted `arguments` string for one or more tool calls — which then crashes here, forever, once it's part of the replayed history.
This issue is about the **crash**, not the corruption itself (#1016 is the likely root cause of *how* the string gets corrupted in the first place, but is a much larger streaming fix). Regardless of *why* a client sends malformed `arguments` — a streaming race, a stopped run, a buggy client — this function shouldn't take down every future turn in the conversation because of it.
## Steps to Reproduce
1. Install `ag-ui-langgraph`
2. Call `agui_messages_to_langchain` with an `AssistantMessage` whose `tool_calls[0].function.arguments` is invalid JSON, e.g. `'{"path": "a.txt" "content": "x"}'` (a real shape we saw in production — looks like two argument fragments concatenated without a separator)
3. Observe the uncaught `JSONDecodeError`
Minimal repro:
```python
from ag_ui.core import AssistantMessage, ToolCall, FunctionCall
from ag_ui_langgraph.utils import agui_messages_to_langchain
msg = AssistantMessage(
id="a1", role="assistant", content="",
tool_calls=[ToolCall(id="tc1", type="function",
function=FunctionCall(name="write_file", arguments='{"path": "a.txt" "content": "x"}'))],
)
agui_messages_to_langchain([msg]) # raises json.decoder.JSONDecodeError
```
## Expected Behavior
A tool call with malformed `arguments` shouldn't crash the whole conversion — it already falls back to `{}` for an *empty* arguments string on the same line; a non-empty-but-invalid one should get the same fallback (with a `logger.warning` so the underlying corruption stays visible/debuggable), not an uncaught exception.
## Environment
AG-UI package(s) & version(s): `ag-ui-langgraph` (reproduced against `main` @ `7c3bd253`, and against the published `0.0.42`)
Runtime: Python 3.12
## Logs & Errors
Real production traceback (via a downstream service using `ag-ui-langgraph==0.0.42`), repeating identically on every subsequent run in the same conversation thread:
```
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 1 column 26 (char 25)
File ".../ag_ui_langgraph/utils.py", line 379, in agui_messages_to_langchain
"args": json.loads(tc.function.arguments) if hasattr(tc, "function") and tc.function.arguments else {},
```
## Additional Context
I have a fix ready (wraps the `json.loads` call, falls back to `{}` + logs a warning on `JSONDecodeError`, matching the file's existing logging conventions) plus a regression test in `tests/test_message_conversion.py`, verified against the full suite (792 passed) and the exact CI command (`python -m unittest discover tests -v`, 780 passed). Opening a PR against this issue.
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.