Problem
_transform_output() is currently called inside each provider's _parse_content() method rather than at the base _predict() pipeline level. Every provider must independently remember to call self._transform_output() as the final step in _parse_content(). If any provider forgets, structured output parsing (JSON schema, Pydantic model extraction) silently breaks — no error, just raw text returned instead of a parsed object.
All 10 current text providers do it correctly, but this is a landmine for new provider implementations.
Current call chain (fragile):
```
ModalityClient._predict()
→ ProviderTextClient._parse_content(response_data, **parameters)
→ ProviderAPIMixin._parse_content(response_data) # extract raw structure
→ self._transform_output(text, **parameters) # each provider must remember this
```
Proposed call chain (safe):
```
ModalityClient._predict()
→ self._parse_content(response_data) # no **parameters needed
→ self._transform_output(raw_content, **parameters) # guaranteed at base level
```
Affected Files
src/celeste/client.py — move _transform_output call into _predict()
src/celeste/modalities/text/providers/*/client.py — remove _transform_output call from each provider's _parse_content() (10 providers)
- Remove
**parameters from _parse_content signature (no longer needed)
Impact
- Prevents silent failures when adding new providers
- Reduces boilerplate in every provider implementation
- Streaming path already does this correctly (
TextStream._parse_output calls _transform_output at the base level)
- Aligns non-streaming path with the streaming path's design
🤖 Generated with Claude Code
Problem
_transform_output()is currently called inside each provider's_parse_content()method rather than at the base_predict()pipeline level. Every provider must independently remember to callself._transform_output()as the final step in_parse_content(). If any provider forgets, structured output parsing (JSON schema, Pydantic model extraction) silently breaks — no error, just raw text returned instead of a parsed object.All 10 current text providers do it correctly, but this is a landmine for new provider implementations.
Current call chain (fragile):
```
ModalityClient._predict()
→ ProviderTextClient._parse_content(response_data, **parameters)
→ ProviderAPIMixin._parse_content(response_data) # extract raw structure
→ self._transform_output(text, **parameters) # each provider must remember this
```
Proposed call chain (safe):
```
ModalityClient._predict()
→ self._parse_content(response_data) # no **parameters needed
→ self._transform_output(raw_content, **parameters) # guaranteed at base level
```
Affected Files
src/celeste/client.py— move_transform_outputcall into_predict()src/celeste/modalities/text/providers/*/client.py— remove_transform_outputcall from each provider's_parse_content()(10 providers)**parametersfrom_parse_contentsignature (no longer needed)Impact
TextStream._parse_outputcalls_transform_outputat the base level)🤖 Generated with Claude Code