Repository navigation
Conversation
str() turned content=None (AG-UI assistant messages, e.g. tool-call-only turns) into the literal string 'None', and rendered multimodal UserMessage content as its pydantic repr. Both leaked into SingleTurnSample.response and metric inputs.
|
Thanks for the detailed write-up, and for flagging the overlap with #3011 in the references. As the author of the original AG-UI integration (#2395), I reproduced both defects you describe and validated this patch locally. I support merging it alongside #3011 — they fix distinct bugs in the same handler and combine cleanly. Validation (exact patch at Unit level:
Live end-to-end:
One test issue on the minimum pinned version: the repo pins Linked issue: happy to file one capturing both shapes (with the repros from your description) if the maintainers prefer the issue-first workflow. @anistark — you reviewed and merged the original integration; could you take a look when you have a chance, or point us to the current maintainer for — Mark |
|
Linked issue: #3060 (filed per the offer above, with fresh minimal repros on |
|
Thanks @contextablemark — especially for catching the 0.1.9 import failure and confirming the counts on both pins. Pushed Verified: on |
|
Thanks for the compatibility guard in
That resolves the minimum-version test failure I reported. The runtime normalization is unchanged, so my earlier validation and support for this fix still stand. #3060 tracks the underlying defects. For clarity, I’m the author of the original AG-UI integration, not a Ragas maintainer; I can provide validation and recommendations but cannot approve a merge on the project’s behalf. The project appears to have stalled on the maintenance side: the latest merge I could verify was February 24, 2026, and there have been no merges in the last 90 days, although contributors remain active. I don’t know whether maintenance has paused or moved to someone else. The compatibility fix addresses my outstanding request. Hopefully a current maintainer can review and merge this work. — Mark |
Issue Link / Problem Description
AGUIEventCollector._handle_messages_snapshotbuilds content withstr(getattr(msg, "content", ""))(src/ragas/integrations/ag_ui.py:620onmain). Two documented shapes ofag_ui.coremessage content are destroyed by that coercion:Nonebecomes the string"None".AssistantMessage.contentisOptional[str]with defaultNone(ag-ui-protocol 0.1.22), which is what a tool-call-only assistant turn carries.str(None)yields the four-character string"None", so the message content is recorded as"None"rather than empty. That value reachesSingleTurnSample.responsethroughbuild_sample→extract_response, so metrics get scored against the literal textNone.UserMessage.contentisUnion[str, List[InputContentPart]].str([TextInputContent(...)])produces a repr, soHumanMessage.contentbecomes[TextInputContent(type='text', text='...')]instead of the user's actual text.Reproduction on
main:Changes Made
src/ragas/integrations/ag_ui.py— added_normalize_content(), which mapsNoneto"", passesstrthrough unchanged, and flattens a multimodal content list to thetextof itsTextInputContentparts. The other input-part types (image/audio/video/document/binary) have notextfield and are skipped; anything else keeps the previousstr()behaviour as a fallback._handle_messages_snapshotnow calls it instead ofstr(...).tests/unit/integrations/test_ag_ui.py— two regression tests, one per shape. The multimodal test skips with a reason when the installedag-ui-protocolhas noTextInputContent(the repository's minimum pin, 0.1.9).The streaming path is untouched: it already builds content by joining deltas in
_handle_text_message_content.Testing
How to Test
Both tests fail on
mainand pass with the change:With the version guard in
68db694: onag-ui-protocol==0.1.9, which has noTextInputContent, the multimodal test is skipped and the file reports 44 passed, 1 skipped; on versions that provideTextInputContentit reports 45 passed.Lint/format (the
Makefileformattarget):Types:
pyright -p pyproject.toml srcreports no findings insrc/ragas/integrations/ag_ui.py. The 6 errors / 11 warnings it reports elsewhere (langsmith.py,tracing/langfuse.py,tracing/mlflow.py, plusreportMissingModuleSourcewarnings) are present onmainand unchanged by this PR.References
_handle_text_message_content(src/ragas/integrations/ag_ui.py:322) builds streaming content by joining deltas, so only the snapshot path needed fixing;build_sample(src/ragas/integrations/ag_ui.py:1265) is where the coerced value lands inSingleTurnSample.response.ag-ui-protocolAssistantMessage/UserMessagecontent types inag_ui.core._handle_messages_snapshotbut fixes a different defect (tool-callname/argumentsread from the nestedfunctionobject). The hunks are disjoint; whichever lands second will need a trivial rebase.Screenshots/Examples (if applicable)
Not applicable — no UI change.