feat(models): native response_format pass-through for OpenAI / OCIOpenAIModel#39
Merged
Merged
Conversation
…nAIModel Closes #36. When `Agent(output_schema=Pydantic)` is configured AND the provider ships native OpenAI-style `response_format={"type":"json_schema",...}`, the agent loop now passes the schema through directly. Anthropic / Ollama / OCI native-SDK transport keep the prompted-JSON fallback — their providers report `supports_structured_output = False`. Before: every structured-output run paid prompted-JSON cost (schema duplicated in the system prompt, post-hoc parse + retry on parse failure) even on providers that support native pass-through. The existing `build_response_format()` was only used in the post-loop repair flow at `agent.py:1743`. After: native providers (`OpenAIModel`, `OCIOpenAIModel` via inheritance) get the schema in the request directly. The provider returns a guaranteed-parseable instance. No retry, lower token cost, stronger correctness guarantee. Capability flag: - `OpenAIModel.supports_structured_output → True` - `OCIOpenAIModel` inherits from `OpenAIModel` → True - `AnthropicModel.supports_structured_output → False` (explicit) - `OllamaModel.supports_structured_output → False` (explicit) - `OCIModel` (Cohere R-series via SDK transport) → False (explicit) Six unit tests in `tests/unit/test_native_structured_output.py` verify each provider's capability and assert `build_response_format()` returns the OpenAI-native shape. All 3,210 pre-existing unit tests still pass. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #36.
Problem
When `Agent(output_schema=Pydantic)` is configured, the agent loop always falls back to prompted-JSON + post-hoc parsing — even on OpenAI / OCI-OpenAI-compat where `response_format={"type":"json_schema",...}` is supported natively.
The native pass-through path existed in the codebase but was only used in the post-loop repair flow at `agent.py:1743`, never in the main loop at `agent.py:1632`. `build_response_format()` (`src/locus/core/structured.py:257-288`) already returns the right shape; it just wasn't being called.
Fix
Add a `supports_structured_output` capability property on each provider model:
In `agent.py`, the main-loop `complete()` call now gates on the capability:
```python
if self.config.output_schema is not None and getattr(
self._model, "supports_structured_output", False
):
response_format = build_response_format(
self.config.output_schema,
strict=self.config.output_schema_strict,
)
```
When set, `response_format=` is passed to `model.complete(...)` in the same kwargs path the existing repair flow already uses.
Outcome
Tests
Six new tests in `tests/unit/test_native_structured_output.py`:
All 3,210 pre-existing unit tests still pass; pre-commit clean; `mkdocs build --strict` clean.
Test plan