Skip to content

fix: handle FastAPI serialization for Message objects#800

Closed
OiPunk wants to merge 1 commit intoQwenLM:mainfrom
OiPunk:codex/qwen-agent-347-message-serialization
Closed

fix: handle FastAPI serialization for Message objects#800
OiPunk wants to merge 1 commit intoQwenLM:mainfrom
OiPunk:codex/qwen-agent-347-message-serialization

Conversation

@OiPunk
Copy link

@OiPunk OiPunk commented Mar 4, 2026

Summary

  • Fixes fastapi直接返回Message对象,序列化报错,BUG #347: BaseModelCompatibleDict.model_dump() override was being bypassed by FastAPI's serialization pipeline
  • Added @model_serializer(mode='wrap') to BaseModelCompatibleDict that filters out None values at the Pydantic serialization level
  • This ensures consistent exclude_none=True behavior whether serialized via direct model_dump(), Pydantic's TypeAdapter, or FastAPI's jsonable_encoder

Problem

The overridden model_dump method only sets exclude_none=True when the caller doesn't pass the parameter. However:

  1. FastAPI's jsonable_encoder calls model_dump(exclude_none=False) explicitly, overriding the intended default
  2. Pydantic's TypeAdapter (used by FastAPI for response_model validation) bypasses model_dump() entirely

This causes None-valued fields (name, function_call, extra, etc.) to appear as null in API responses.

Solution

Add a @model_serializer(mode='wrap') that operates at the Pydantic core serialization level, ensuring None values are filtered regardless of the call path. The existing model_dump/model_dump_json overrides are preserved for backward compatibility.

Test plan

  • Message.model_dump() excludes None fields
  • Message.model_dump_json() excludes None fields
  • ContentItem.get_type_and_value() still works (depends on single-item dict)
  • TypeAdapter(Message).dump_python() excludes None fields
  • TypeAdapter(Message).dump_json() contains no null values
  • FastAPI endpoints return clean JSON without null fields
  • Dict-like access (__getitem__, __setitem__, get) still works
  • Added unit tests in tests/llm/test_schema.py

…objects

The overridden `model_dump` method in `BaseModelCompatibleDict` only works
when called directly. FastAPI uses Pydantic's `TypeAdapter` and
`jsonable_encoder` for response serialization, both of which bypass the
custom `model_dump` override and pass `exclude_none=False` explicitly.

This causes None-valued fields (e.g. `name`, `function_call`, `extra`) to
appear as `null` in API responses, conflicting with the intended behaviour
of always excluding None values.

Add a `@model_serializer(mode='wrap')` decorator that filters out None
values at the Pydantic serialization level, ensuring consistent behaviour
regardless of the call path (direct `model_dump()`, `TypeAdapter`, or
FastAPI's `jsonable_encoder`).

Closes QwenLM#347
@OiPunk
Copy link
Author

OiPunk commented Mar 6, 2026

Closing — shifting focus to AI Agent core projects. Thank you for your time!

@OiPunk OiPunk closed this Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fastapi直接返回Message对象,序列化报错,BUG

1 participant