Skip to content

OCIModel + Gemini: structured output rejects Pydantic schemas with additionalProperties:false #281

@fede-kamel

Description

@fede-kamel

TL;DR

`OCIModel` against `google.gemini-2.5-flash` (and presumably other Gemini variants on OCI GenAI) rejects Pydantic-derived structured-output schemas with:

```
openai.BadRequestError: Error code: 400 - {'code': '400', 'message':
'Unsupported JSON Schema feature for Gemini: additionalProperties'}
```

Pydantic emits `additionalProperties: false` by default in its `model_json_schema()`. OpenAI / Anthropic accept it; Google's structured-output validator (via OCI GenAI) doesn't.

Result: any `create_deepagent(..., output_schema=SomePydanticModel)` invocation against Gemini fails at the first model call with a 400, before producing any output.

Repro

```python
from pydantic import BaseModel
from locus import create_deepagent
from locus.tools.decorator import tool

class Result(BaseModel):
answer: str
confidence: float = 1.0

@tool
def trivial() -> str:
return "ok"

agent = create_deepagent(
model="oci:google.gemini-2.5-flash",
tools=[trivial],
system_prompt="be helpful",
output_schema=Result, # ← this is the trigger
reflexion=False,
grounding=False,
)
agent.run_sync("hi")

openai.BadRequestError: Error code: 400 - {'code': '400',

'message': 'Unsupported JSON Schema feature for Gemini: additionalProperties'}

```

(Discovered during PR #279's live testing — the test had to drop `output_schema` to avoid hitting this.)

Why

Gemini's structured-output enforcement (via google.generativeai's response_schema field) doesn't support `additionalProperties` in JSON Schema. Pydantic generates schemas with `additionalProperties: false` by default to enforce strict typing — OpenAI's structured output mode honors and requires this; Gemini's doesn't.

The OCI GenAI `google.gemini-*` provider needs to either:

  1. Strip `additionalProperties` from the schema before sending to Gemini (lossy but pragmatic)
  2. Convert to Gemini's own schema dialect (responses.Schema with type/properties only)
  3. Refuse + raise clearly at agent-build time so callers know structured output isn't supported, instead of failing at the first inference call

Per LangChain's docs, the langchain-google-genai package does (1) — strips known-unsupported fields before serialization. Locus should do the same in the `OCIModel` Gemini code path.

Proposed fix

In `src/locus/models/providers/oci.py` (or wherever the structured-output schema gets emitted), add a vendor check:

```python
def _normalize_schema_for_vendor(schema: dict, vendor: str) -> dict:
if vendor.startswith("google"):
# Gemini's structured-output validator rejects:
# - additionalProperties
# - patternProperties
# - dependencies
return _strip_keys(schema, {"additionalProperties", "patternProperties", "dependencies"})
return schema
```

…called from the structured-output payload assembly path. Same fix has been applied in langchain-google-genai and the langchain-oci PR #148 work.

Acceptance criteria

  • `create_deepagent(output_schema=PydanticModel)` against `oci:google.gemini-*` does NOT raise 400 with "Unsupported JSON Schema feature: additionalProperties"
  • Unit test pinning the schema-munging: passes a Pydantic model, verifies the emitted schema for Gemini lacks `additionalProperties`
  • Live integration test against Gemini that exercises `output_schema=` end-to-end (gated by `RUN_LIVE_OCI=1` like the deepagent: max_tokens parameter is the run-level budget but reads like the per-completion cap — empty-output bug #278 live tests)
  • No regression to OpenAI / Anthropic / Cohere structured-output paths

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions