OutputAdapter silently coerces string output to another type when output_type is a Union including str.
Describe the bug
OutputAdapter.run() skips ast.literal_eval coercion when output_type is exactly str, but not when output_type is a Union that includes str (e.g. str | None, Optional[str]). A rendered value like "42" declared with output_type=str | None is silently coerced to the int 42 instead of being preserved as the string "42".
Affected code
haystack/components/converters/output_adapter.py, inside run():
with contextlib.suppress(Exception):
if not self._unsafe and self.output_type is not str:
output_result = ast.literal_eval(output_result)To Reproduce
from haystack.components.converters import OutputAdapter
adapter = OutputAdapter(template="{{ reply }}", output_type=str | None)
result = adapter.run(reply="42")
# Expected: {"output": "42"}
# Actual: {"output": 42} (coerced to int)Context
This is the same class of bug just found and fixed in ConditionalRouter (see #12617, PR #12620), which has the identical output_type is not str pattern. I confirmed via GitHub search that no existing open issue or PR currently covers this specific OutputAdapter case before filing.
Proposed fix
Add a helper checking whether str is output_type itself or a member of a Union output_type, matching the same fix pattern used for ConditionalRouter. I have a fix and passing regression test ready.
Environment Haystack main branch, Python 3.12.4
Source: deepset-ai/haystack