Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion haystack/components/generators/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,13 @@ def _convert_streaming_chunks_to_chat_message(chunks: list[StreamingChunk]) -> C


def _serialize_object(obj: Any) -> Any:
"""Convert an object to a serializable dict recursively"""
"""
Convert an object to a serializable dict recursively.

Used to serialize `logprobs` and `usage` from OpenAI SDK response objects, so it skips any
attribute starting with "_" (SDK-internal fields). `base_serialization._serialize_value_with_schema`
doesn't skip those, so don't swap this out for it.
"""
if hasattr(obj, "model_dump"):
return obj.model_dump()
if hasattr(obj, "__dict__"):
Expand Down
10 changes: 9 additions & 1 deletion haystack/core/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ def default_to_dict(obj: Any, **init_parameters: Any) -> dict[str, Any]:
Objects in `init_parameters` that have a `to_dict()` method are automatically
serialized by calling that method.

This is the format used for saved pipeline files (`Pipeline.dump`/`Pipeline.load`). Don't merge
it with `base_serialization._serialize_value_with_schema` — that one uses a different envelope
for a different job (arbitrary runtime values, not Components) and changing either would break
saved files.

An example usage:

```python
Expand Down Expand Up @@ -257,7 +262,10 @@ def default_from_dict(cls: type[T], data: dict[str, Any]) -> T:
"""
Utility function to deserialize a dictionary to an object.

This is mostly necessary for components but can be used by any object.
This is mostly necessary for components but can be used by any object. Reverses the
`{"type": ..., "init_parameters": ...}` envelope produced by `default_to_dict` — see that
function's docstring for why this envelope is not interchangeable with
`haystack.utils.base_serialization._serialize_value_with_schema`'s.

The function will raise a `DeserializationError` if the `type` field in `data` is
missing or it doesn't match the type of `cls`.
Expand Down
4 changes: 4 additions & 0 deletions haystack/tracing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def _serializable_value(value: Any, use_placeholders: bool = True) -> Any:
"""
Serializes a value into a format suitable for tracing.

One-way only: this is never deserialized, so it's allowed to lose data (e.g. replace large
objects with a placeholder). Don't swap it for `base_serialization`'s schema serializer, which
is built to round-trip exactly.

:param value:
The value to serialize.
:param use_placeholders:
Expand Down
4 changes: 4 additions & 0 deletions haystack/utils/base_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ def _serialize_value_with_schema(payload: Any) -> dict[str, Any]: # noqa: PLR09
- Lists, tuples, and sets. Lists with mixed types are not supported.
- Primitive types (str, int, float, bool, None)

This is for runtime values (Agent/State data, pipeline inputs/outputs at a breakpoint), not
Component definitions — see `default_to_dict` in `core/serialization.py` for that other format.
Don't merge the two; they're not interchangeable.

:param payload: The value to serialize (can be any type)
:returns: The serialized dict representation of the given value. Contains two keys:
- "serialization_schema": Contains type information for each field.
Expand Down
Loading