fix: preserve message tags when restoring from dictionaries
Summary
MessageBase.from_dict() drops tags even though Message.__init__() accepts them and to_dict() serializes them. Forward the stored tags when reconstructing a message, including through the chat-resume path. Dictionaries without the field continue to produce tags=None.
This is a source finding on current main. No matching existing issue was found; no issue has been published.
Validation
- Added round-trip coverage for a non-empty tag list, an empty list and
None, plus a compatibility assertion for a legacy dictionary withouttags. - Unmodified implementation with the regression tests: 2 failed, 51 passed in
backend/tests/test_message.py; both failures reproduce dropped tags. - Patched implementation: 70 passed across
backend/tests/test_message.pyandbackend/tests/test_modes.py. PYTHONPATH=backend python -m pytest backend/tests/test_message.py backend/tests/test_modes.py -q --tb=short --allow-hosts=127.0.0.1,::1; remote sockets are blocked, with loopback allowed for the Windows asyncio loop. The verification harness asserts the loaded source path for both baseline and patched runs.python scripts/lint.py backend/chainlit/message.py backend/tests/test_message.pyandpython scripts/format.py --check backend/chainlit/message.py backend/tests/test_message.pypass using Ruff 0.13.3.git diff --checkpasses. No new dependencies.
Validation limits
- Windows / Python 3.11.0, within the supported package range; the development target is Python 3.13. The source backend is loaded directly in an isolated environment to avoid the frontend build hook.
- A prior complete
scripts/type_check.py --no-incrementalcomparison reported the same 38 diagnostics in 16 files on unmodified main and the patch (109 files checked), including missing optional integration dependencies. This is not a passing whole-backend type check. - The targeted test run reports 11 warnings, including existing dependency deprecation, asyncio marker and AsyncMock warnings.
- A prior source hello-app launch failed because frontend assets were not built. Browser workflows, frontend lint/format, the full backend suite and Cypress E2E remain unverified.
AI assistance
Codex assisted with investigation, the one-line fix and regression tests. Verification results and limitations are listed above.
Summary by cubic
Fixes MessageBase.from_dict() dropping tags when reconstructing messages, even though Message.__init__() accepts them and to_dict() serializes them. The stored tags are now forwarded when restoring, including through the chat-resume path, while dictionaries without the field still produce tags=None.
Adds regression tests covering round-trip preservation for a non-empty tag list, an empty list, and None, plus a compatibility assertion for legacy dictionaries without the tags field.