Skip to content

feat(models): Add OCI Generative AI provider for Google Gemini on OCI#5285

Open
fede-kamel wants to merge 2 commits intogoogle:mainfrom
fede-kamel:feat/oci-generative-ai
Open

feat(models): Add OCI Generative AI provider for Google Gemini on OCI#5285
fede-kamel wants to merge 2 commits intogoogle:mainfrom
fede-kamel:feat/oci-generative-ai

Conversation

@fede-kamel
Copy link
Copy Markdown

@fede-kamel fede-kamel commented Apr 11, 2026

Closes #5069

What this PR does

Adds OCIGenAILlm — a first-class ADK model provider for Google Gemini models hosted on Oracle Cloud Infrastructure (OCI) Generative AI. Gemini 2.5 Flash, Gemini 2.5 Pro, and Gemini 2.5 Flash Lite are available as first-party models through OCI's inference endpoints — this is a native Google × OCI model partnership, not a third-party wrapper.

from google.adk.models.oci_genai_llm import OCIGenAILlm
from google.adk.agents import LlmAgent

agent = LlmAgent(
    model=OCIGenAILlm(
        model="google.gemini-2.5-flash",
        compartment_id="ocid1.compartment.oc1...",
    ),
    instruction="You are a helpful assistant.",
)

Why this belongs in adk-python, not a community package

1. This is a model provider primitive, not a tool or connector

The community repo and integrations catalog host tools and connectors — BigQuery, Chroma, MongoDB, ElevenLabs, Slack, etc. All 60+ entries in that catalog are tool integrations. There is zero precedent for a model provider (BaseLlm subclass) living in the community repo — the community repo itself only contains memory/ and sessions/ modules, no model providers.

Every existing model provider in ADK — Gemini, Gemma, Claude, LiteLlm, ApigeeLlm — lives in src/google/adk/models/ in this repo. This PR follows that exact pattern.

2. Model providers cannot be external without degrading the SDK

LLMRegistry, BaseLlm, and the model dispatch layer are core SDK primitives. A model provider sitting in a standalone package creates:

  • Version drift — core changes to BaseLlm, LlmRequest, LlmResponse, or LLMRegistry can silently break an external provider with no CI coverage
  • Broken type inference — external packages lose Pydantic model validation and IDE type narrowing that works seamlessly for in-tree providers
  • Second-class developer experiencepip install google-adk[oci] (an optional extra, like [extensions] for Claude) is the established pattern; requiring a separate package for one cloud provider while others are built-in is an inconsistency that confuses users

3. OCI is an official Google model distribution channel

OCI Generative AI hosts Google's own Gemini models through a direct partnership. This is the same class of integration as Vertex AI or Apigee AI Gateway — a Google-authorized inference endpoint, not a community hobby project. AWS Bedrock and Azure are absent from the SDK because no one has contributed them yet, not because multi-cloud model providers belong in a tools catalog.

4. The implementation follows established precedent exactly

Aspect AnthropicLlm (Claude) OCIGenAILlm (this PR)
Subclasses BaseLlm Yes Yes
Registered in LLMRegistry Yes Yes
Optional dependency guard try/except in __init__.py Same pattern
Install extra pip install google-adk[extensions] pip install google-adk[oci]
Uses native SDK anthropic package oci package
No LangChain dependency Correct Correct
Streaming + non-streaming Yes Yes

Design

  • Subclasses BaseLlm, registered in LLMRegistry for google.gemini-* and other OCI model patterns
  • Uses the OCI Python SDK directly — no LangChain dependency
  • Optional install: pip install google-adk[oci] (safe to import without oci installed)
  • Non-streaming: _call_oci() runs the synchronous OCI SDK call in asyncio.to_thread
  • Streaming: _call_oci_stream() collects OCI's OpenAI-compatible SSE events in a thread, then yields partial=True chunks followed by a partial=False final response with aggregated content and usage metadata
  • Auth: API_KEY (default), INSTANCE_PRINCIPAL, RESOURCE_PRINCIPAL

Files changed

File Description
src/google/adk/models/oci_genai_llm.py New OCIGenAILlm implementation
src/google/adk/models/__init__.py Optional registration in LLMRegistry
pyproject.toml New [oci] optional dependency extra
tests/unittests/models/test_oci_genai_llm.py 37 unit tests (fully mocked)
tests/integration/models/test_oci_genai_llm.py 10 integration tests (skipped without OCI_COMPARTMENT_ID)

Test results (rebased on current main)

  • 37/37 OCI unit tests passed — fully mocked, no OCI account needed
  • 641/641 total model unit tests passed — zero regressions across the entire tests/unittests/models/ suite
  • Integration tests verified against live OCI endpoint (google.gemini-2.5-flash, us-chicago-1): text generation, streaming, tool calls, system instructions, multi-turn, concurrent calls
  • import google.adk succeeds without oci installed (optional dependency guard)

Request to maintainers

Issue #5069 is open, labeled models + needs review, and a maintainer (@sanketpatil06) confirmed it is "under review by our team." I am asking that this PR be reviewed on its technical merits and that the routing question (core vs. community) be evaluated against the evidence above — specifically the zero precedent for external model providers, the SDK degradation risks, and the partnership-level nature of OCI Gemini hosting.

Happy to address any code review feedback directly.

@adk-bot adk-bot added the models [Component] Issues related to model support label Apr 11, 2026
@fede-kamel fede-kamel force-pushed the feat/oci-generative-ai branch 2 times, most recently from 3d70b80 to 8f40e5c Compare April 11, 2026 19:49
@rohityan rohityan self-assigned this Apr 13, 2026
@rohityan rohityan added the request clarification [Status] The maintainer need clarification or more information from the author label Apr 13, 2026
@rohityan
Copy link
Copy Markdown
Collaborator

Hi @fede-kamel , Thank you for your contribution! It appears you haven't yet signed the Contributor License Agreement (CLA). Please visit https://cla.developers.google.com/ to complete the signing process. Once the CLA is signed, we'll be able to proceed with the review of your PR. Thank you!

@fede-kamel
Copy link
Copy Markdown
Author

image image @rohityan

@fede-kamel fede-kamel force-pushed the feat/oci-generative-ai branch from bdd53d3 to 6650f8d Compare April 13, 2026 21:05
@fede-kamel fede-kamel force-pushed the feat/oci-generative-ai branch from 49d7bd5 to eaf3c5a Compare April 24, 2026 16:56
@fede-kamel
Copy link
Copy Markdown
Author

Friendly ping — this PR has been open for ~10 days without a review. Happy to address feedback or rebase further if needed. Let me know if there's anything I can clarify. Thanks!

@fede-kamel fede-kamel force-pushed the feat/oci-generative-ai branch from eaf3c5a to 1bd8b7f Compare April 27, 2026 13:21
@fede-kamel
Copy link
Copy Markdown
Author

Hi @sanketpatil06 — following up here since issue #5069 (which this PR resolves) is still open and you mentioned the team would keep me posted.

Quick status:

  • PR has been open ~16 days with no review yet.
  • Just rebased onto latest main — conflicts resolved, all checks passing, branch is now MERGEABLE.
  • 37 unit tests + 18 live integration tests against OCI Generative AI all passing.

Would really appreciate getting a reviewer assigned. Happy to address any feedback. Thanks!

@fede-kamel fede-kamel force-pushed the feat/oci-generative-ai branch 3 times, most recently from 3c32dd1 to 8d0953f Compare May 5, 2026 23:57
@fede-kamel
Copy link
Copy Markdown
Author

@ankursharmas @sasha-gitg — bumping for review.

Status: Rebased cleanly on main (3a1eadce). The provider is now feature-complete vs the gap list and verified against live OCI Generative AI in us-chicago-1 (Gemini 2.5 Flash). Force-pushed.

What changed since the initial PR

feature status
Lazy-provider integration (_LAZY_PROVIDERS in models/__init__.py) ✅ moved to the new scheme
Streaming SSE iteration (response.data.events() not for x in response.data) ✅ fixed real bug uncovered by live testing
Streaming chunk schema (OCI is message.content[].text + camelCase usage, not OpenAI-shaped) ✅ rewrote parser to match /20231130/
Sampling params: temperature, top_p, top_k, frequency_penalty, presence_penalty, seed, stop_sequences ✅ passthrough
max_output_tokens per-request override
Multimodal: inline_data + file_data → OCI ImageContent / AudioContent / VideoContent / DocumentContent
Structured output: response_schemaJsonSchemaResponseFormat; response_mime_type=application/jsonJsonObjectResponseFormat
Reasoning tokens (Gemini 2.5 emits completionTokensDetails.reasoningTokens) → usage_metadata.thoughts_token_count ✅ both streaming + non-streaming
Both serving modes: OnDemandServingMode (default) + DedicatedServingMode (via endpoint_id field or OCI_ENDPOINT_ID env)

Unit tests — 51 passed (mocked)

test_supported_models_gemini                                   PASSED
test_supported_models_llama                                    PASSED
test_supported_models_gemma                                    PASSED
test_supported_models_registry                                 PASSED
test_content_to_oci_message_user_text                          PASSED
test_content_to_oci_message_assistant_text                     PASSED
test_content_to_oci_message_multi_part_text                    PASSED
test_content_to_oci_message_function_call                      PASSED
test_content_to_oci_message_function_response                  PASSED
test_oci_response_to_llm_response_text                         PASSED
test_oci_response_to_llm_response_tool_call                    PASSED
test_oci_response_to_llm_response_empty_text                   PASSED
test_function_declaration_to_oci_tool_no_parameters            PASSED
test_function_declaration_to_oci_tool_with_parameters          PASSED
test_function_declaration_to_oci_tool_json_schema              PASSED
test_generate_content_async_text                               PASSED
test_generate_content_async_yields_llm_response                PASSED
test_generate_content_async_with_tools                         PASSED
test_streaming_yields_partial_then_final                       PASSED
test_streaming_final_has_usage_metadata                        PASSED
test_streaming_tool_call                                       PASSED
test_streaming_empty_chunks                                    PASSED
test_nonstreaming_uses_call_oci_not_call_oci_stream            PASSED
test_streaming_uses_call_oci_stream_not_call_oci               PASSED
test_call_oci_stream_iterates_sse_via_events_method            PASSED  ← regression guard
test_concurrent_async_calls                                    PASSED
test_concurrent_streaming_calls                                PASSED
test_missing_compartment_id_raises                             PASSED
test_compartment_id_from_env                                   PASSED
test_service_endpoint_default                                  PASSED
test_service_endpoint_from_env                                 PASSED
test_service_endpoint_explicit_overrides_env                   PASSED
test_build_client_api_key                                      PASSED
test_build_client_instance_principal                           PASSED
test_build_client_resource_principal                           PASSED
test_call_oci_passes_model_and_compartment                     PASSED
test_call_oci_passes_system_instruction                        PASSED
test_call_oci_passes_tools                                     PASSED
test_call_oci_uses_on_demand_serving_mode_by_default           PASSED
test_call_oci_uses_dedicated_serving_mode_when_endpoint_id_set PASSED
test_call_oci_uses_dedicated_serving_mode_from_env_var         PASSED
test_explicit_endpoint_id_overrides_env_var                    PASSED
test_call_oci_passes_sampling_params                           PASSED
test_call_oci_omits_unset_sampling_params                      PASSED
test_inline_image_becomes_image_content_with_data_url          PASSED
test_file_data_audio_becomes_audio_content                     PASSED
test_inline_pdf_becomes_document_content                       PASSED
test_response_schema_emits_json_schema_response_format         PASSED
test_response_mime_type_only_emits_json_object_format          PASSED
test_nonstreaming_surfaces_reasoning_tokens                    PASSED
test_streaming_surfaces_reasoning_tokens                       PASSED
============================== 51 passed in 1.19s ==============================

Live integration tests against real OCI Generative AI — 30 passed

OCI_COMPARTMENT_ID=<tenancy> OCI_REGION=us-chicago-1 pytest tests/integration/models/test_oci_genai_llm.py -k gemini
Endpoint: https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/chat
Model: google.gemini-2.5-flash. Each test runs against both GOOGLE_AI and VERTEX parametrized backends → 30 calls.

test_gemini_generate_content_text                       [GOOGLE_AI]  PASSED
test_gemini_generate_content_text                       [VERTEX]     PASSED
test_gemini_generate_content_usage_metadata             [GOOGLE_AI]  PASSED
test_gemini_generate_content_usage_metadata             [VERTEX]     PASSED
test_gemini_generate_content_with_system_instruction    [GOOGLE_AI]  PASSED
test_gemini_generate_content_with_system_instruction    [VERTEX]     PASSED
test_gemini_generate_content_tool_call                  [GOOGLE_AI]  PASSED
test_gemini_generate_content_tool_call                  [VERTEX]     PASSED
test_gemini_generate_content_streaming_text             [GOOGLE_AI]  PASSED
test_gemini_generate_content_streaming_text             [VERTEX]     PASSED
test_gemini_generate_content_streaming_usage_metadata   [GOOGLE_AI]  PASSED
test_gemini_generate_content_streaming_usage_metadata   [VERTEX]     PASSED
test_gemini_generate_content_streaming_tool_call        [GOOGLE_AI]  PASSED
test_gemini_generate_content_streaming_tool_call        [VERTEX]     PASSED
test_gemini_generate_content_concurrent                 [GOOGLE_AI]  PASSED
test_gemini_generate_content_concurrent                 [VERTEX]     PASSED
test_gemini_multi_turn                                  [GOOGLE_AI]  PASSED
test_gemini_multi_turn                                  [VERTEX]     PASSED
test_gemini_max_output_tokens_caps_response             [GOOGLE_AI]  PASSED
test_gemini_max_output_tokens_caps_response             [VERTEX]     PASSED
test_gemini_low_temperature_deterministic_with_seed     [GOOGLE_AI]  PASSED
test_gemini_low_temperature_deterministic_with_seed     [VERTEX]     PASSED
test_gemini_stop_sequences_terminate_output             [GOOGLE_AI]  PASSED
test_gemini_stop_sequences_terminate_output             [VERTEX]     PASSED
test_gemini_inline_image_input                          [GOOGLE_AI]  PASSED
test_gemini_inline_image_input                          [VERTEX]     PASSED
test_gemini_response_schema_returns_valid_json          [GOOGLE_AI]  PASSED
test_gemini_response_schema_returns_valid_json          [VERTEX]     PASSED
test_gemini_reasoning_tokens_reported                   [GOOGLE_AI]  PASSED
test_gemini_reasoning_tokens_reported                   [VERTEX]     PASSED
=============== 30 passed, 12 deselected in 34.76s ===============

The 12 deselected are cross-provider (OCI_LLAMA_MODEL, OCI_MISTRAL_MODEL, OCI_GROK_MODEL, OCI_NVIDIA_MODEL) and dedicated-mode (OCI_DEDICATED_ENDPOINT_ID) tests, gated on additional env vars to keep cost opt-in.

API correctness

This targets OCI Generative AI Inference /20231130/ (the only public version; "v1"). Gemini on OCI is on-demand only per Oracle's docs. Request shape is GenericChatRequest (api_format=GENERIC), confirmed compatible with all six model families registered (google.gemini-*, google.gemma-*, meta.llama-*, xai.grok-*, mistralai.*, nvidia.*).

Happy to split this into a smaller initial PR (just text + tools, deferring multimodal/structured output to a follow-up) if that's preferable for review velocity. Otherwise everything's tested end-to-end and ready to look at.

Adds first-class support for Google Gemini models hosted on Oracle Cloud
Infrastructure (OCI) Generative AI service — a native Google × OCI model
partnership that makes Gemini available directly through OCI's inference
endpoints.

Key design points:
- Subclasses BaseLlm following the anthropic_llm.py pattern
- Uses the OCI Python SDK directly (no LangChain dependency)
- Optional dependency: pip install google-adk[oci]
- Supports API_KEY, INSTANCE_PRINCIPAL, and RESOURCE_PRINCIPAL auth
- Both non-streaming (_call_oci) and streaming (_call_oci_stream) paths
  share setup code via _build_chat_details(); streaming collects OCI's
  OpenAI-compatible SSE events in a thread pool (asyncio.to_thread) and
  yields partial then final LlmResponse
- Registers google.gemini-* (and other OCI-hosted) model patterns in
  LLMRegistry via optional try/except in models/__init__.py
- 37 unit tests (fully mocked, no OCI account needed)
- 10 integration tests (skipped when OCI_COMPARTMENT_ID is unset)

Supported models: google.gemini-*, google.gemma-*, meta.llama-*,
  mistralai.*, xai.grok-*, nvidia.*
@fede-kamel fede-kamel force-pushed the feat/oci-generative-ai branch from 8d0953f to d6eb806 Compare May 6, 2026 15:54
Add reasoning_effort: Optional[str] = None as a constructor field. When
set, it's passed as `reasoning_effort` on the OCI GenericChatRequest —
honoured by GPT-5 family, Gemini 2.5, Grok reasoning variants, and
Cohere Command-A-Reasoning; ignored by non-reasoning models.

This is the single biggest cost knob for reasoning-capable models on
OCI: setting "LOW" typically cuts reasoning-token spend 5-10× vs the
default. The other GenericChatRequest fields (verbosity,
parallel_tool_calls, logit_bias, n, metadata, etc.) are not exposed —
they either duplicate existing controls or are too niche to justify
maintenance surface. We only ship what's a missing primitive.

Verified live against OCI us-chicago-1: openai.gpt-5.5 + reasoning
models all accept the field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

models [Component] Issues related to model support request clarification [Status] The maintainer need clarification or more information from the author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(models): Add OCI Generative AI provider for Google Gemini on OCI

3 participants