Repository navigation
Conversation
This was referenced Oct 6, 2026
sun04222
added a commit
to sun04222/agno
that referenced
this pull request
Oct 23, 2026
to_dict serializes citations as a plain dict, but from_dict had no citations branch, so a round-tripped event kept a dict and event.citations.urls raised AttributeError. RunOutput.from_dict already validates it; do the same for run events.
BlueX888
force-pushed
the
fix/prep-event-from-dict-citations-left-as-dict
branch
from
October 25, 2026 16:13
29957b0 to
09d5925
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
BaseRunOutputEvent.to_dictwritescitationsas a plain dict (self.citations.model_dump(exclude_none=True),libs/agno/agno/run/base.py:185-189), butfrom_dict(libs/agno/agno/run/base.py:249) had nocitationsbranch, so the value was passed straight into the event. A round-tripped event therefore carried adict, and typed access such asevent.citations.urlsraisedAttributeError: 'dict' object has no attribute 'urls'.citationswas the only entry of_HAND_SERIALIZED_FIELDS(base.py:88) thatto_dictwrites andfrom_dictdoes not rebuild; the neighbouring hand-serialized fields (image,additional_input) both have their branch.RunOutput.from_dict(libs/agno/agno/run/agent.py:889-890) andTeamRunOutput.from_dict(run/team.py:1037-1038) already callCitations.model_validate, so the same payload round-tripped fine on the run output and broke on the event.Reachable through
run_output_event_from_dict(run/agent.py:609), which parses AgentOS client SSE events (agno/client/os.py:650,:736,:927,:1049,:1235,:1336) and the event list inside a stored run (run/agent.py:877,run/team.py:979).Fixes #10272
Changes
libs/agno/agno/run/base.py: popcitationsinBaseRunOutputEvent.from_dictand rebuild it withCitations.model_validate, matching the adjacentimage/images/audiobranches andRunOutput.from_dict. No import change:Citationsis already imported in the module and used by theto_dictbranch above.BaseAgentRunEvent,BaseTeamRunEventandBaseWorkflowRunOutputEventall inherit thisfrom_dict, so agent, team and workflow events are covered.libs/agno/tests/unit/run/test_run_events.py: newtest_run_content_event_includes_citationsround-trips aRunContentEventthroughto_dict/from_dictand throughrun_output_event_from_dict(json.loads(event.to_json())), asserting the restoredcitationsis aCitationsand reading.urls[0].Type of change
Testing
Dev venv from
./scripts/dev_setup.sh(agno + agnoctl editable), base commita71c4d0.Reproduction before the fix (source reverted to
origin/main, new test kept) —pytest libs/agno/tests/unit/run/test_run_events.py::test_run_content_event_includes_citations:The same payload through
RunOutput.from_dictreturns aCitationson the unpatched tree, which is the asymmetry this fixes.After the fix:
pytest libs/agno/tests/unit/run/test_run_events.py→ 17 passedpytest libs/agno/tests/unit/run→ 234 passed, 1 warningpytest libs/agno/tests/unit -q --continue-on-collection-errors→ 15298 passed, 229 failed, 497 skipped, 397 errors. The same command on the same tree with only the source change reverted gives 230 failed / 15297 passed, and diffing the two FAILED lists leaves exactly one difference: this new test. The remaining failures and errors are pre-existing ona71c4d0in this environment (optional deps not installed: surrealdb, weaviate, pymongo, redis, anthropic, numpy, bs4, Google client libraries, ...); I did not triage them individually../scripts/format.sh→ clean for all targets (ruff format + import sort). Note: it also reformattedlibs/agno/tests/unit/vectordb/test_elasticsearch.py, a pre-existing formatting drift onmainunrelated to this change, which I reverted.ruff format --checkon the two changed files: clean../scripts/validate.sh→ruff checkclean,mypy — Success: no issues found in 1055 source files, agnoctl clean, cookbook pattern check 0 violations.Checklist
./scripts/format.shand./scripts/validate.sh)Duplicate and AI-Generated PR Check
Additional Notes
AI disclosure: this change was generated with Claude Code and reviewed, tested and verified by me before submission, as required by
CONTRIBUTING.md(Pull Request Guidelines, item 5). Every command and output quoted above was run in a local checkout; the issue #10272 body carries the same disclosure.The adjacent base64/media field handling in
BaseRunOutputEvent.from_dictis tracked separately (#10205) and is not touched here.Collision check before writing the fix: no open PR in the repository modifies
libs/agno/agno/run/base.py, and no existing issue or PR coverscitationsin the event round-trip.