Skip to content

feat: Add utility method to auto deserialize pipeline inputs - #12093

Closed
sjrl wants to merge 7 commits into
mainfrom
auto-deserialization-pipeline
Closed

feat: Add utility method to auto deserialize pipeline inputs#12093
sjrl wants to merge 7 commits into
mainfrom
auto-deserialization-pipeline

Conversation

@sjrl

@sjrl sjrl commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Related Issues

  • fixes #issue-number

Proposed Changes:

Added the coerce_pipeline_inputs utility function (importable from haystack). It deserializes serialized Haystack objects in pipeline input data based on the pipeline's input socket types: for every provided value whose socket type involves a class exposing from_dict (such as ChatMessage or Document), plain dictionaries are converted into instances of that class. Socket types of the form T, list[T], and optionals/unions of those are supported, and both the nested ({"component_name": {"input_name": value}}) and flat ({"input_name": value}) input formats are accepted. This removes the need for API layers to guess which pipeline inputs contain serialized ChatMessage objects before calling Pipeline.run:

from haystack import coerce_pipeline_inputs

inputs = coerce_pipeline_inputs(pipeline, serialized_inputs)
result = pipeline.run(inputs)

How did you test it?

Notes for the reviewer

Checklist

  • I have read the contributors guidelines and the code of conduct.
  • I have updated the related issue with new insights and changes.
  • I have added unit tests and updated the docstrings.
  • I've used one of the conventional commit types for my PR title: fix:, feat:, build:, chore:, ci:, docs:, style:, refactor:, perf:, test: and added ! in case the PR includes breaking changes.
  • I have documented my code.
  • I have added a release note file, following the contributors guidelines.
  • I have run pre-commit hooks and fixed any issue.

@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
haystack-docs Ignored Ignored Preview Jul 23, 2026 9:25am

Request Review

@sjrl
sjrl requested review from mpangrazzi and tstadel July 21, 2026 08:03
@github-actions github-actions Bot added the type:documentation Improvements on the docs label Jul 21, 2026
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack
  __init__.py
  haystack/core
  serialization.py 445
  haystack/tools
  component_tool.py
Project Total  

This report was generated by python-coverage-comment-action

@sjrl sjrl self-assigned this Jul 21, 2026
@tstadel

tstadel commented Jul 21, 2026

Copy link
Copy Markdown
Member

@sjrl That's a great addition!
How about adding basic support for arbitrary python dataclasses and pydantic models as well?

@sjrl

sjrl commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

@sjrl That's a great addition! How about adding basic support for arbitrary python dataclasses and pydantic models as well?

That could be a consideration, but then its starting to feel more like this util function might make more sense to have in hayhooks than in Haystack. 🤔 Would you be fine with that?

@mpangrazzi mpangrazzi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I've left two minor comments

Comment thread haystack/core/serialization.py Outdated
Comment on lines +400 to +405
if _is_union_type(type_):
for arm in get_args(type_):
resolved = _resolve_coercible_class(arm)
if resolved is not None:
return resolved
return None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to always pick the first deserializable union member. Could we get the correct member from the payload instead (and raise if not found)? Otherwise an ExtractedAnswer may be converted to GeneratedAnswer (didn't test it)

:returns: The deserialized instance.
"""
if hasattr(target_class, "from_dict"):
return target_class.from_dict(value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be wrong, but Tool.from_dict() mutates nested fields in this dictionary, so passing value directly modifies the caller’s payload. Maybe a deepcopy(value) would fix this? (not sure it's valuable though)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm for now I'd leave it up to the caller to the deepcopy and if need be we can open an issue in Haystack about if designing from_dict to not mutate in place. Although I believe that was a design choice to often deserialize in place.

@sjrl

sjrl commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of deepset-ai/hayhooks#252

@sjrl sjrl closed this Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants