feat(llm): add OCI Generative AI provider - #5186
Xiaowen-Yang wants to merge 2 commits into
Conversation
Co-authored-by: openhands <openhands@all-hands.dev>
|
🚦 CI is currently failing on this PR's latest commit. Please fix the failing checks before OpenHands reviews it - this is re-checked automatically once you push a new commit. (A maintainer can also request This is an automated check - no AI was used to generate this comment. |
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Scope
This change belongs in this repository: it adds an LLM provider route plus the Agent Server provider-discovery entry, which is exactly what software-agent-sdk owns. Linked issue #5188 is open with enhancement, ready-for-dev, priority:normal, and the acceptance criteria match the diff. No repository move or product decision is needed.
What I verified
- Head is still
1f8bab5(matches the requested SHA). - Ran the focused tests in the workspace on this head:
uv run pytest -q tests/sdk/llm/test_oci_genai_provider.py tests/agent_server/test_llm_router.py-> 28 passed. Broader regression set (test_llm.py,test_llm_profile_store.py,test_profiles_router.py,test_settings.py) -> 385 passed. - Endpoint derivation,
openai-projectheader precedence over caller-supplied headers, region/OCID validation, andto_persisted/from_persistedround-trip all behave as the tests claim.
Findings
1. model_copy(update={"model": ...}) bypasses the OCI normalization and leaves derived routing stale (material).
The OCI routing (base_url = None, api_mode = "responses") is applied only in the _coerce_inputs before-validator. model_copy does not re-run validators, and the new code only rebuilds LiteLLM metadata, so a copied LLM keeps the source's api_mode/base_url while _litellm_call_kwargs/_provider_headers already switch to the OCI transport. Changing the model via model_copy is an established pattern in this repo (existing test test_llm_model_copy_refreshes_provider_for_model_update), so this path is reachable:
LLM(model="openai/gpt-5-mini").model_copy(update={"model": "oci_genai/xai.grok-4.6"})raises a bareAssertionErrorfrom the newassert self.oci_region is not Nonein_litellm_call_kwargs.- With
oci_region/oci_project_idsupplied, the copy builds the correctapi_baseand header but keepsapi_mode = "auto", souses_responses_api()returnsFalseand the call is dispatched through the chat-completions path instead of the Responses API. A pre-existing non-Nonebase_urlwould also be retained and route the request to the wrong host. - The inverse leaks too:
oci_llm.model_copy(update={"model": "anthropic/claude-sonnet-4-5"})keepsapi_mode = "responses", pinning a non-OCI model to the Responses API.
Because OCI's derived api_mode/base_url are stashed on the model rather than recomputed from model + oci_region, model_copy needs to re-derive them (or _litellm_call_kwargs/_provider_headers should not assume the copy went through _coerce_inputs).
2. CI is not green for this head.
The required workflows on 1f8bab5 (Run tests, Agent Server, Pre-commit checks, TypeScript client CI, etc.) are all action_required — they have not completed successfully for this commit — and the bot posted a CI-failing notice on this commit. The only currently-green checks are PR Description Check and PR Artifacts. Local focused runs pass, but there is no completed CI signal on the head, so this needs a maintainer look regardless of finding 1.
Note
Live credentialed OCI verification is explicitly not covered by this PR (author states no OCI credentials were available); the tests exercise only mocked responses. That is reasonable for a new provider, but the OCI-specific routing is exactly where finding 1 lives, so the model_copy path deserves a test.
🔄 CHANGES REQUESTED
Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Scope
In-repo. This adds an LLM provider route plus the Agent Server provider-discovery entry — exactly the surface software-agent-sdk owns (SDK/Agent Server → OpenAPI → clients → Agent Canvas). Linked issue #5188 is open with enhancement, ready-for-dev, priority:low, and its acceptance criteria match the diff. No repository move or product/architecture decision is needed.
Prior finding is resolved
The earlier model_copy(update={"model": ...}) gap is fixed on this head. I re-verified each case directly against the workspace:
- non-OCI →
oci_genaiwith region/project:api_modebecomesresponses, stalebase_urlis dropped (None),uses_responses_api()isTrue, and_litellm_call_kwargs()returns the regional OCIapi_base. - non-OCI →
oci_genaiwithoutoci_region: raises the intendedValueError("oci_region is required for OCI Generative AI")instead of the previous bareAssertionError. oci_genai→ non-OCI:api_moderesets toautoanduses_responses_api()isFalse(previously it stayed pinned to the Responses API).- OCI → different region / project: re-derived
api_baseandopenai-projectheader are correct.
Verification performed
- Head still
e2bb49d9(matches the requested SHA); PR open, not draft, basemain. uv run pytest -q tests/sdk/llm/test_oci_genai_provider.py tests/agent_server/test_llm_router.py→ 31 passed.uv run pytest -q tests/sdk/llm/test_llm.py tests/sdk/llm/test_llm_profile_store.py tests/agent_server/test_profiles_router.py tests/sdk/test_settings.py tests/sdk/llm/test_model_list.py→ 395 passed.- Reviewed the endpoint derivation,
openai-projectheader precedence (provider header wins over caller-supplied), region/OCID validation (dot-free region regex prevents host injection), and theto_persisted/from_persistedround-trip. All behave as the tests claim.
CI status (informational, not blocking)
All twelve pull_request workflows on this head are action_required with zero jobs — they have not executed yet, because this is a fork PR awaiting first-time-contributor workflow approval. The only completed checks are PR Description Check and PR Artifacts (both success). Nothing here is a failing run; it just means a maintainer needs to approve the workflow runs before the standard suite reports. The PR has not modified any release/version fields and adds no dependencies, so the guide's non-approve conditions (version bump, too-new dependency) do not apply, and this is not an eval-risk change (new provider only; existing models and the agent loop are unaffected).
Live credentialed OCI verification is explicitly out of scope per the description (no OCI credentials available); tests exercise mocked Responses output and function-tool output. A maintainer with OCI access should still run the listed live procedure before merge.
✅ APPROVED
|
Thank you for the substantial OCI Generative AI provider implementation. After review, we are closing this PR because adding new AI providers is generally out of scope unless the provider is broadly popular and commonly used by OpenHands users. We are not recommending OCI as a built-in provider at this time. This decision is about project scope, not the quality of the implementation. An AI agent (OpenHands) posted this comment on behalf of the user. |
HUMAN:
I reviewed the OCI Generative AI provider implementation and the automated test results. I did not run a live OCI request because I do not have the required OCI credentials.
AGENT:
Why
OCI Generative AI provides an OpenAI-compatible Responses API, but OpenHands
currently has no first-class configuration path for its regional endpoint,
Generative AI project OCID, or API-key authentication.
Users must manually construct the endpoint, add the
openai-projectheader,and configure Responses API capabilities. This is error-prone and makes OCI
deployments difficult to configure reliably.
This PR adds the SDK and Agent Server support needed for a guided OCI Generative
AI profile. The dependent Agent Canvas UI is implemented in
OpenHands/OpenHands#17543, and the user-facing setup documentation is provided
in OpenHands/docs#813.
Summary
oci_genai/<model-id>as a first-class LLM provider route with validatedOCI region and Generative AI project OCID fields.
/openai/v1endpoint, select the Responses API, and addthe required
openai-projectheader automatically.validation, serialization, and encrypted-secret tests.
Issue Number
Fixes: #5188
Related to OpenHands/OpenHands#17512.
How to Test
Automated Verification Performed
Set up the development environment:
Result: completed successfully.
Run the targeted OCI and provider-discovery tests:
Result:
Run the broader LLM profile and Agent Server regression tests:
Result:
Run the repository checks on all changed files:
Result:
Validate the generated Agent Server OpenAPI schema:
Result:
Live OCI Verification
A credentialed live request was not run because no OCI Generative AI API key,
project OCID, and region-enabled model were available in the development
environment.
The automated tests exercise both normal Responses API output and function-tool
output through mocked provider responses, but they do not make a billable OCI
request. Credentialed validation by a maintainer with OCI access would be
appreciated. The live verification procedure is:
model="oci_genai/<exact-model-id>"oci_region="<region>"oci_project_id="<project-ocid>"result.
OpenHands/docs#813 includes the same credential-gated live test plan for users.
Video/Screenshots
Not applicable to this SDK and Agent Server PR because it does not change a GUI.
OpenHands/OpenHands#17543 contains the user-facing provider selector, OCI
configuration fields, and a screenshot of the rendered form. CLI test results
and reproduction steps are included above.
Design Doc
Not included. The implementation is limited to provider-specific configuration
normalization and transport routing:
Type
Notes
oci_genai/is intentionally separate from LiteLLM's nativeoci/provider.The native route targets OCI IAM-style authentication, while this initial
integration uses OCI Generative AI API keys and the OpenAI-compatible
Responses API.
principals is outside the scope of this PR and can be added in a follow-up.
openai-projectheader takes precedence over conflictingcaller-supplied headers.
Jev-Fast-Audit
⚡ Jev fast audit · estimates · 0.52s · commit 1f8bab5
Strongest signal: No primary concern selected.
Evidence: No primary concern to locate.
Coverage: complete supplied coverage; 14/14 hunks, 5/5 files.
All estimates and evidence