Skip to content

feat: add OCI Generative AI provider — basic text completion#4959

Open
fede-kamel wants to merge 6 commits into
crewAIInc:mainfrom
fede-kamel:feat/oci-provider-core
Open

feat: add OCI Generative AI provider — basic text completion#4959
fede-kamel wants to merge 6 commits into
crewAIInc:mainfrom
fede-kamel:feat/oci-provider-core

Conversation

@fede-kamel

@fede-kamel fede-kamel commented Mar 19, 2026

Copy link
Copy Markdown

Summary

  • Add native OCI Generative AI text completion provider (OCICompletion) supporting generic (Meta, Google, OpenAI, xAI) and Cohere model families
  • Shared OCI auth utilities (utilities/oci.py) for API key, security token, instance principal, and resource principal auth
  • OCI registered as optional dependency (crewai[oci])
  • 15 unit tests (mocked SDK) + 2 parametrized integration tests (tested live against meta.llama-3.3-70b-instruct, cohere.command-r-plus-08-2024, google.gemini-2.5-flash, openai.gpt-5.2-chat-latest)

This is PR 1 of a series — follow-up PRs will add streaming, tool calling, structured output, multimodal, and embeddings support.

Supersedes #4885 (closed per reviewer feedback to split by scope).
Tracking issue: #4944

What's included

File Lines What
utilities/oci.py 72 Shared get_oci_module() + create_oci_client_kwargs()
llms/providers/oci/completion.py 505 OCICompletion(BaseLLM) — init, message building, basic call/acall
llm.py +13 Provider registration (routing, pattern matching, import)
pyproject.toml +3 oci optional dependency
Tests 491 conftest + 15 unit + 2 integration (parametrized across models)

What's NOT included (deferred to follow-up PRs)

  • Streaming (iter_stream, astream)
  • Tool calling / function calling
  • Structured output (response_model)
  • Multimodal (vision, documents, audio, video)
  • OCI embeddings provider
  • OCI tools (will be a standalone PyPI package per community tools guidelines)

Test plan

  • 15 unit tests pass (mocked OCI SDK, no credentials needed)
  • Integration tests pass against 4 model families via OCI GenAI API:
    • meta.llama-3.3-70b-instruct
    • cohere.command-r-plus-08-2024
    • google.gemini-2.5-flash
    • openai.gpt-5.2-chat-latest
  • Both sync (call) and async (acall) paths verified

Note

Medium Risk
Introduces a new native LLM provider and OCI authentication paths; risk is mainly around request/response translation and credential/config handling for a new external SDK.

Overview
Adds native Oracle Cloud Infrastructure (OCI) Generative AI support for basic chat/text completion via a new OCICompletion provider, including model-family request shaping (generic vs Cohere) and sync/async call paths with token-usage tracking.

Registers oci as a supported native provider in LLM routing (prefix handling + model pattern matching) and adds a shared utilities/oci.py helper for lazy SDK import plus multiple OCI auth modes. Includes an optional dependency crewai[oci] and a new test suite with mocked-SDK unit tests plus opt-in live integration tests.

Reviewed by Cursor Bugbot for commit d7e6ffd. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added Oracle Cloud Infrastructure (OCI) Generative AI as a native LLM provider for CrewAI (sync/async support, model routing, request/response handling).
    • Added OCI utility to configure clients and authentication modes.
  • Chores

    • Added optional dependency group for OCI SDK (requires oci>=2.168.0).
  • Tests

    • Added unit tests, fixtures, and live integration tests for OCI provider.

Review Change Stack

Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py Outdated
@fede-kamel

Copy link
Copy Markdown
Author

@greysonlalonde Hey! Following up on your feedback from #4885 — I split the original PR into smaller, scoped pieces. This is the first one: just the basic text completion provider for OCI GenAI (no streaming, no tools, no structured output, no multimodal, no embeddings).

I couldn't trim this one further — it's the minimal foundation (provider class + shared auth + registration) plus tests. The source code is ~600 lines and the rest is test fixtures/tests. Each follow-up PR will layer on one capability at a time.

Also, per the community tools guide you shared — the OCI tools (InvokeAgent, KnowledgeBase, ObjectStorage) will go into a standalone PyPI package (crewai-oci-tools), not into the crewAI repo.

Would appreciate a review whenever you get a chance. Thanks!

Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py Outdated
Comment thread lib/crewai/src/crewai/llm.py Outdated
Comment thread lib/crewai/src/crewai/llm.py Outdated
Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py Outdated
Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py Outdated
Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py Outdated
Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py
Comment thread lib/crewai/src/crewai/llms/providers/oci/completion.py Outdated
@fede-kamel fede-kamel force-pushed the feat/oci-provider-core branch from 105d7dd to e6b52b5 Compare March 29, 2026 16:13
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add native function calling for generic and Cohere model families:
- _format_tools converts CrewAI tool specs to OCI SDK format
- _extract_tool_calls normalizes responses back to CrewAI shape
- _handle_tool_calls executes tools and recurses until model finishes
- Cohere tool message handling with trailing tool results
- Tool choice control (auto/none/required/function)
- Passthrough parameter filtering via SDK introspection
- Streaming tool call accumulation from SSE fragments
- supports_function_calling() returns True

Tested live against meta.llama-3.3-70b-instruct with
raw tool call return and recursive tool execution.

Depends on: crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add native function calling for generic and Cohere model families:
- _format_tools converts CrewAI tool specs to OCI SDK format
- _extract_tool_calls normalizes responses back to CrewAI shape
- _handle_tool_calls executes tools and recurses until model finishes
- Cohere tool message handling with trailing tool results
- Tool choice control (auto/none/required/function)
- Passthrough parameter filtering via SDK introspection
- Streaming tool call accumulation from SSE fragments
- supports_function_calling() returns True

Tested live against meta.llama-3.3-70b-instruct with
raw tool call return and recursive tool execution.

Depends on: crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add response_model (Pydantic) support for structured output:
- _build_response_format converts Pydantic schema to OCI
  JsonSchemaResponseFormat (generic) or CohereResponseJsonFormat
- _parse_structured_response validates and returns typed models
- response_model threaded through call, _call_impl, _stream_call_impl,
  and _handle_tool_calls for full coverage
- Handles JSON in markdown fences via base class _validate_structured_output

Tested live against meta.llama-3.3-70b-instruct and
google.gemini-2.5-flash.

Depends on: crewAIInc#4962 (tool calling), crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add native function calling for generic and Cohere model families:
- _format_tools converts CrewAI tool specs to OCI SDK format
- _extract_tool_calls normalizes responses back to CrewAI shape
- _handle_tool_calls executes tools and recurses until model finishes
- Cohere tool message handling with trailing tool results
- Tool choice control (auto/none/required/function)
- Passthrough parameter filtering via SDK introspection
- Streaming tool call accumulation from SSE fragments
- supports_function_calling() returns True

Tested live against meta.llama-3.3-70b-instruct with
raw tool call return and recursive tool execution.

Depends on: crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add response_model (Pydantic) support for structured output:
- _build_response_format converts Pydantic schema to OCI
  JsonSchemaResponseFormat (generic) or CohereResponseJsonFormat
- _parse_structured_response validates and returns typed models
- response_model threaded through call, _call_impl, _stream_call_impl,
  and _handle_tool_calls for full coverage
- Handles JSON in markdown fences via base class _validate_structured_output

Tested live against meta.llama-3.3-70b-instruct and
google.gemini-2.5-flash.

Depends on: crewAIInc#4962 (tool calling), crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request Mar 29, 2026
Add multimodal content handling for generic model families:
- vision.py: model lists, data URI helpers, image encoding utilities
- _build_generic_content handles image_url, document_url, video_url,
  audio_url content types mapped to OCI SDK content objects
- _message_has_multimodal_content detects non-text payloads
- Cohere models reject multimodal with clear error message
- supports_multimodal() returns True

Depends on: crewAIInc#4963, crewAIInc#4962, crewAIInc#4961, crewAIInc#4959
Tracking issue: crewAIInc#4944
@fede-kamel fede-kamel force-pushed the feat/oci-provider-core branch from 0cfe8ca to d15e5d4 Compare May 6, 2026 15:26
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
- OCICompletion(BaseLLM): sync call() and async acall() for generic
  (Meta, Google, OpenAI, xAI) and Cohere model families
- Shared OCI auth utilities (utilities/oci.py): API key, security token,
  instance principal, and resource principal auth
- Provider routing in llm.py: oci/ prefix and OCI model-id patterns
- oci registered as optional dependency (crewai[oci])
- Configurable timeout via DEFAULT_OCI_TIMEOUT constant
- Cohere and generic request/response paths fully separated

Tracking issue: crewAIInc#4944
Part 1 of series: crewAIInc#4959crewAIInc#4961crewAIInc#4962crewAIInc#4963crewAIInc#4964crewAIInc#4966crewAIInc#4982
@fede-kamel

Copy link
Copy Markdown
Author

@greysonlalonde @lorenzejay — bump for review.

Status

  • ✅ Rebased onto main (was 51 behind, clean rebase)
  • ✅ Real bug fix included: param-name routing now matches _is_openai_gpt5_family() instead of broad openai.*
  • ✅ Live-tested end-to-end across all 7 model families OCI offers in us-chicago-1 via the v1 (/20231130/Chat) API

Bug fixed in the latest commit (d15e5d49)

_build_chat_request previously routed any openai.* model to max_completion_tokens, while _is_openai_gpt5_family() (used elsewhere in the same method for temperature and stop) only matches openai.gpt-5*. That mismatch meant openai.gpt-4o and openai.gpt-4.1 got the wrong field — the predicate is now consistent across all three call sites.

Live E2E verification — 7/7 pass

$ uv run --no-sync python <e2e probe>
model                                          budget  result
------------------------------------------------------------------------------
  ✅ openai.gpt-5.5                              256   'ok'   (max_completion_tokens)
  ✅ openai.gpt-5                                256   'ok'   (max_completion_tokens)
  ✅ openai.gpt-4o                                64   'Ok.'  (max_tokens)
  ✅ openai.gpt-4.1                               64   'ok'   (max_tokens)
  ✅ meta.llama-3.3-70b-instruct                  64   'ok'   (GENERIC)
  ✅ meta.llama-4-scout-17b-16e-instruct          64   'ok'   (GENERIC)
  ✅ cohere.command-latest                        64   'ok'   (COHERE / CohereChatRequest)

This includes openai.gpt-5.5 — the April 2026 GPT-5.5 release on OCI — which is functional through the crewAI provider.

Unit tests — 16/16 pass

$ uv run --no-sync pytest lib/crewai/tests/llms/oci/ -q
ss................                                                       [100%]
16 passed, 2 skipped in 3.54s

Two new tests cover the routing both ways:

  • test_oci_gpt5_family_uses_max_completion_tokens — GPT-5.5 → max_completion_tokens
  • test_oci_openai_gpt4o_keeps_max_tokens — GPT-4o → max_tokens (regression guard)

API correctness

The provider hits OCI's /20231130/ v1 API directly (the only public version — Oracle uses date-stamped versions, no v1/v2 split). GenericChatRequest (api_format=GENERIC) covers Llama / Gemini / Grok / Mistral / Nvidia / OpenAI families; CohereChatRequest (api_format=COHERE) covers Cohere. Both serving modes (on-demand + dedicated via OCID) are supported.

This is the foundation PR of the 7-PR series (#4961 streaming, #4962 tools, #4963 structured output, #4964 multimodal, #4966 embeddings, #4982 async). Ready when you are. 🙏

fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add native function calling for generic and Cohere model families:
- _format_tools converts CrewAI tool specs to OCI SDK format
- _extract_tool_calls normalizes responses back to CrewAI shape
- _handle_tool_calls executes tools and recurses until model finishes
- Cohere tool message handling with trailing tool results
- Tool choice control (auto/none/required/function)
- Passthrough parameter filtering via SDK introspection
- Streaming tool call accumulation from SSE fragments
- supports_function_calling() returns True

Tested live against meta.llama-3.3-70b-instruct with
raw tool call return and recursive tool execution.

Depends on: crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add native function calling for generic and Cohere model families:
- _format_tools converts CrewAI tool specs to OCI SDK format
- _extract_tool_calls normalizes responses back to CrewAI shape
- _handle_tool_calls executes tools and recurses until model finishes
- Cohere tool message handling with trailing tool results
- Tool choice control (auto/none/required/function)
- Passthrough parameter filtering via SDK introspection
- Streaming tool call accumulation from SSE fragments
- supports_function_calling() returns True

Tested live against meta.llama-3.3-70b-instruct with
raw tool call return and recursive tool execution.

Depends on: crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add response_model (Pydantic) support for structured output:
- _build_response_format converts Pydantic schema to OCI
  JsonSchemaResponseFormat (generic) or CohereResponseJsonFormat
- _parse_structured_response validates and returns typed models
- response_model threaded through call, _call_impl, _stream_call_impl,
  and _handle_tool_calls for full coverage
- Handles JSON in markdown fences via base class _validate_structured_output

Tested live against meta.llama-3.3-70b-instruct and
google.gemini-2.5-flash.

Depends on: crewAIInc#4962 (tool calling), crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add multimodal content handling for generic model families:
- vision.py: model lists, data URI helpers, image encoding utilities
- _build_generic_content handles image_url, document_url, video_url,
  audio_url content types mapped to OCI SDK content objects
- _message_has_multimodal_content detects non-text payloads
- Cohere models reject multimodal with clear error message
- supports_multimodal() returns True

Depends on: crewAIInc#4963, crewAIInc#4962, crewAIInc#4961, crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add streaming text completion via OCI SSE events:
- stream=True in call() routes to _stream_call_impl with chunk events
- iter_stream() yields raw text chunks (sync generator)
- astream() wraps iter_stream via thread+queue for async callers
- _stream_chat_events holds client lock for full stream duration
- SSE event parsing handles both string and mapping payloads

Tested live against meta.llama-3.3-70b-instruct,
cohere.command-r-plus-08-2024, google.gemini-2.5-flash,
and openai.gpt-5.2-chat-latest.

Depends on: crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add native function calling for generic and Cohere model families:
- _format_tools converts CrewAI tool specs to OCI SDK format
- _extract_tool_calls normalizes responses back to CrewAI shape
- _handle_tool_calls executes tools and recurses until model finishes
- Cohere tool message handling with trailing tool results
- Tool choice control (auto/none/required/function)
- Passthrough parameter filtering via SDK introspection
- Streaming tool call accumulation from SSE fragments
- supports_function_calling() returns True

Tested live against meta.llama-3.3-70b-instruct with
raw tool call return and recursive tool execution.

Depends on: crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add response_model (Pydantic) support for structured output:
- _build_response_format converts Pydantic schema to OCI
  JsonSchemaResponseFormat (generic) or CohereResponseJsonFormat
- _parse_structured_response validates and returns typed models
- response_model threaded through call, _call_impl, _stream_call_impl,
  and _handle_tool_calls for full coverage
- Handles JSON in markdown fences via base class _validate_structured_output

Tested live against meta.llama-3.3-70b-instruct and
google.gemini-2.5-flash.

Depends on: crewAIInc#4962 (tool calling), crewAIInc#4961 (streaming), crewAIInc#4959 (basic text)
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add multimodal content handling for generic model families:
- vision.py: model lists, data URI helpers, image encoding utilities
- _build_generic_content handles image_url, document_url, video_url,
  audio_url content types mapped to OCI SDK content objects
- _message_has_multimodal_content detects non-text payloads
- Cohere models reject multimodal with clear error message
- supports_multimodal() returns True

Depends on: crewAIInc#4963, crewAIInc#4962, crewAIInc#4961, crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Replace asyncio.to_thread wrappers with true async I/O using aiohttp
for acall() and astream(). The OCI SDK is sync-only, so we bypass it
for HTTP and use its signer for request authentication directly.

- oci_async.py: OCIAsyncClient with aiohttp, OCI request signing,
  native SSE parsing, connection pooling
- acall(): true async chat completion (no thread pool)
- astream(): true async SSE streaming (no thread+queue bridge)
- Graceful fallback to asyncio.to_thread when aiohttp unavailable
  or client is mocked (unit tests)
- aiohttp + certifi added to crewai[oci] optional deps

Temporary measure until OCI SDK ships native async support.

Tested live: acall, astream, and concurrent acall against
meta.llama-3.3-70b-instruct with API_KEY auth.

Depends on: crewAIInc#4966, crewAIInc#4964, crewAIInc#4963, crewAIInc#4962, crewAIInc#4961, crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
Add OCI embedding support integrated with CrewAI's RAG pipeline:
- OCIEmbeddingFunction: ChromaDB-compatible embedding callable with
  batching, config serialization, image embedding support
- OCIProvider: Pydantic-based provider with alias validation for
  env vars and config keys
- Factory registration in embeddings/factory.py + types.py
- Supports text and image embeddings, output dimensions,
  custom endpoints, all 4 OCI auth modes

Tested live against cohere.embed-english-v3.0 with API_KEY auth.

Depends on: crewAIInc#4964, crewAIInc#4963, crewAIInc#4962, crewAIInc#4961, crewAIInc#4959
Tracking issue: crewAIInc#4944
fede-kamel added a commit to fede-kamel/crewAI that referenced this pull request May 6, 2026
- OCICompletion(BaseLLM): sync call() and async acall() for generic
  (Meta, Google, OpenAI, xAI) and Cohere model families
- Shared OCI auth utilities (utilities/oci.py): API key, security token,
  instance principal, and resource principal auth
- Provider routing in llm.py: oci/ prefix and OCI model-id patterns
- oci registered as optional dependency (crewai[oci])
- Configurable timeout via DEFAULT_OCI_TIMEOUT constant
- Cohere and generic request/response paths fully separated

Tracking issue: crewAIInc#4944
Part 1 of series: crewAIInc#4959crewAIInc#4961crewAIInc#4962crewAIInc#4963crewAIInc#4964crewAIInc#4966crewAIInc#4982
@fede-kamel fede-kamel force-pushed the feat/oci-provider-core branch from 3fda605 to 986bb3c Compare May 6, 2026 18:45
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1135650e-33ae-4696-90b6-b7ac4fb0cb86

📥 Commits

Reviewing files that changed from the base of the PR and between 3645af6 and 27be9a5.

📒 Files selected for processing (1)
  • lib/crewai/src/crewai/llms/providers/oci/completion.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai/src/crewai/llms/providers/oci/completion.py

📝 Walkthrough

Walkthrough

This PR adds OCI Generative AI as a native LLM provider: optional dependency, LLM routing updates, OCICompletion implementation with request/response handling and model-specific quirks, OCI client utilities for multiple auth modes, and unit + live integration tests.

Changes

OCI Generative AI Provider

Layer / File(s) Summary
OCI Provider Registration and Routing
lib/crewai/pyproject.toml, lib/crewai/src/crewai/llm.py, lib/crewai/src/crewai/llms/providers/oci/__init__.py
Adds oci>=2.168.0 optional dependency, registers "oci" in supported providers, maps oci/ model prefixes to provider "oci", adds pattern-matching for OCI model identifiers, and returns OCICompletion from native provider resolution.
OCI Client Configuration and Authentication
lib/crewai/src/crewai/utilities/oci.py
Lazy-loads the optional OCI SDK and provides create_oci_client_kwargs() to assemble client kwargs and signers for API_KEY, SECURITY_TOKEN, INSTANCE_PRINCIPAL, and RESOURCE_PRINCIPAL auth flows.
OCICompletion Implementation
lib/crewai/src/crewai/llms/providers/oci/completion.py
Implements OCICompletion: constructor, provider/serving-mode inference, message coercion/normalization, Cohere vs generic request shaping, conditional generation params (temperature, max_tokens vs max_completion_tokens, top_p/top_k, reasoning_effort, stop handling), response parsing (text, finish reason, usage), thread-safe client calls, lifecycle events, token tracking, and sync/async APIs.
Test Fixtures and Configuration
lib/crewai/tests/llms/oci/conftest.py
Adds pytest fixtures and helpers: fake OCI SDK module, response factory functions, patch fixture for _get_oci_module, unit defaults, and live-test helpers that source models and config from environment variables.
Unit Tests: Routing, Initialization, and Request Building
lib/crewai/tests/llms/oci/test_oci.py
Adds tests covering OCI routing, provider-family inference, initialization params, endpoint construction from region env var, chat call behavior for generic and Cohere responses, message normalization, model-family request quirks (GPT-5 uses max_completion_tokens, GPT-4o retains max_tokens, GPT-5 omits unsupported temperature/stop), and acall() delegation.
Integration Tests: Live OCI Completion
lib/crewai/tests/llms/oci/test_oci_integration_basic.py
Adds two live integration tests (sync and async) that instantiate OCICompletion and perform a basic chat completion asserted to return non-empty text; tests are driven by environment-provided OCI config and models.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A provider hopped in with OCI dreams,
Messages flow through LLM streams,
Tokens counted, responses parsed,
Async calls handled with threading's art,
Tests ensure the chat will gleam!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding an OCI Generative AI provider with basic text completion support, which aligns with the substantial implementation across multiple files (provider class, auth utilities, routing, and tests).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/crewai/tests/llms/oci/conftest.py`:
- Around line 170-175: The current pattern uses if os.getenv("VAR"):
config["key"] = os.getenv("VAR", "default") which makes the default unreachable;
change to capture the env value once and use it (e.g., value =
os.getenv("OCI_AUTH_TYPE"); if value: config["auth_type"] = value) for each of
OCI_AUTH_TYPE, OCI_AUTH_PROFILE, and OCI_AUTH_FILE_LOCATION (referencing config
and os.getenv) so you don't call os.getenv twice and eliminate the dead default
arguments.

In `@lib/crewai/tests/llms/oci/test_oci_integration_basic.py`:
- Line 7: Update the run instruction that points to
tests/llms/oci/test_oci_integration_basic.py so it uses the correct repository
path (lib/crewai/tests/llms/oci/test_oci_integration_basic.py); change the
command line shown (uv run pytest ...) to reference the full correct path or to
run pytest from repo root (e.g., uv run pytest
lib/crewai/tests/llms/oci/test_oci_integration_basic.py -v) so contributors can
execute the test as written.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d79e554b-3f40-4adc-a0bb-6de0c6eff7e9

📥 Commits

Reviewing files that changed from the base of the PR and between a95d267 and 3645af6.

📒 Files selected for processing (9)
  • lib/crewai/pyproject.toml
  • lib/crewai/src/crewai/llm.py
  • lib/crewai/src/crewai/llms/providers/oci/__init__.py
  • lib/crewai/src/crewai/llms/providers/oci/completion.py
  • lib/crewai/src/crewai/utilities/oci.py
  • lib/crewai/tests/llms/oci/__init__.py
  • lib/crewai/tests/llms/oci/conftest.py
  • lib/crewai/tests/llms/oci/test_oci.py
  • lib/crewai/tests/llms/oci/test_oci_integration_basic.py

Comment thread lib/crewai/tests/llms/oci/conftest.py Outdated
Comment on lines +170 to +175
if os.getenv("OCI_AUTH_TYPE"):
config["auth_type"] = os.getenv("OCI_AUTH_TYPE", "API_KEY")
if os.getenv("OCI_AUTH_PROFILE"):
config["auth_profile"] = os.getenv("OCI_AUTH_PROFILE", "DEFAULT")
if os.getenv("OCI_AUTH_FILE_LOCATION"):
config["auth_file_location"] = os.getenv("OCI_AUTH_FILE_LOCATION", "~/.oci/config")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove redundant os.getenv() calls; defaults are unreachable dead code.

The pattern if os.getenv(X): followed by os.getenv(X, default) means the default parameter can never be used—you've already verified the variable is truthy. The defaults "API_KEY", "DEFAULT", and "~/.oci/config" on lines 171, 173, and 175 are dead code.

♻️ Simplify by removing the redundant second call
-    if os.getenv("OCI_AUTH_TYPE"):
-        config["auth_type"] = os.getenv("OCI_AUTH_TYPE", "API_KEY")
-    if os.getenv("OCI_AUTH_PROFILE"):
-        config["auth_profile"] = os.getenv("OCI_AUTH_PROFILE", "DEFAULT")
-    if os.getenv("OCI_AUTH_FILE_LOCATION"):
-        config["auth_file_location"] = os.getenv("OCI_AUTH_FILE_LOCATION", "~/.oci/config")
+    if auth_type := os.getenv("OCI_AUTH_TYPE"):
+        config["auth_type"] = auth_type
+    if auth_profile := os.getenv("OCI_AUTH_PROFILE"):
+        config["auth_profile"] = auth_profile
+    if auth_file := os.getenv("OCI_AUTH_FILE_LOCATION"):
+        config["auth_file_location"] = auth_file
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/tests/llms/oci/conftest.py` around lines 170 - 175, The current
pattern uses if os.getenv("VAR"): config["key"] = os.getenv("VAR", "default")
which makes the default unreachable; change to capture the env value once and
use it (e.g., value = os.getenv("OCI_AUTH_TYPE"); if value: config["auth_type"]
= value) for each of OCI_AUTH_TYPE, OCI_AUTH_PROFILE, and OCI_AUTH_FILE_LOCATION
(referencing config and os.getenv) so you don't call os.getenv twice and
eliminate the dead default arguments.

OCI_AUTH_TYPE=API_KEY OCI_AUTH_PROFILE=API_KEY_AUTH \
OCI_COMPARTMENT_ID=<compartment> OCI_REGION=us-chicago-1 \
OCI_TEST_MODELS="meta.llama-3.3-70b-instruct,cohere.command-r-plus-08-2024,google.gemini-2.5-flash" \
uv run pytest tests/llms/oci/test_oci_integration_basic.py -v

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the pytest path in the run instructions.

Line 7 points to tests/llms/oci/test_oci_integration_basic.py, but this file lives under lib/crewai/tests/..., so the command is likely wrong for contributors copying it verbatim.

Suggested diff
-    uv run pytest tests/llms/oci/test_oci_integration_basic.py -v
+    uv run pytest lib/crewai/tests/llms/oci/test_oci_integration_basic.py -v
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uv run pytest tests/llms/oci/test_oci_integration_basic.py -v
uv run pytest lib/crewai/tests/llms/oci/test_oci_integration_basic.py -v
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/tests/llms/oci/test_oci_integration_basic.py` at line 7, Update
the run instruction that points to tests/llms/oci/test_oci_integration_basic.py
so it uses the correct repository path
(lib/crewai/tests/llms/oci/test_oci_integration_basic.py); change the command
line shown (uv run pytest ...) to reference the full correct path or to run
pytest from repo root (e.g., uv run pytest
lib/crewai/tests/llms/oci/test_oci_integration_basic.py -v) so contributors can
execute the test as written.

@fede-kamel

Copy link
Copy Markdown
Author

Hi @greysonlalonde @lorenzejay — gentle nudge from the maintainer team.

This PR has been waiting for a fresh review since 2026-03-19. Since the last update:

This is the scoped-down split that @greysonlalonde requested back in #4885. Happy to address any remaining concerns. Is there a way to get this into a review queue?

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 45 days with no activity.

fede-kamel and others added 6 commits July 10, 2026 11:14
- OCICompletion(BaseLLM): sync call() and async acall() for generic
  (Meta, Google, OpenAI, xAI) and Cohere model families
- Shared OCI auth utilities (utilities/oci.py): API key, security token,
  instance principal, and resource principal auth
- Provider routing in llm.py: oci/ prefix and OCI model-id patterns
- oci registered as optional dependency (crewai[oci])
- Configurable timeout via DEFAULT_OCI_TIMEOUT constant
- Cohere and generic request/response paths fully separated

Tracking issue: crewAIInc#4944
Part 1 of series: crewAIInc#4959crewAIInc#4961crewAIInc#4962crewAIInc#4963crewAIInc#4964crewAIInc#4966crewAIInc#4982
- 15 unit tests (mocked OCI SDK, no credentials needed)
- 2 parametrized integration tests across 4 model families:
  meta.llama-3.3-70b-instruct, cohere.command-r-plus-08-2024,
  google.gemini-2.5-flash, openai.gpt-5.2-chat-latest
- conftest.py with shared fixtures for both test suites
Previously: any `openai.*` model on the GENERIC api_format route was
sent `max_completion_tokens` instead of `max_tokens`. That works for
the GPT-5 family (which OCI requires it on with HTTP 400 if you send
`max_tokens`), but is inconsistent with `_is_openai_gpt5_family()`
already used elsewhere in the same method for temperature and stop.

Switch the param-name routing to the same predicate so GPT-4o /
GPT-4.1 keep the standard `max_tokens` field, while only `openai.gpt-5*`
gets `max_completion_tokens`. Also reword the test pair to reflect the
two distinct behaviours.

Verified live against OCI us-chicago-1 — all 7 model families pass:
  openai.gpt-5.5          ok    (max_completion_tokens)
  openai.gpt-5            ok    (max_completion_tokens)
  openai.gpt-4o           Ok.   (max_tokens)
  openai.gpt-4.1          ok    (max_tokens)
  meta.llama-3.3-70b-instruct           ok
  meta.llama-4-scout-17b-16e-instruct   ok
  cohere.command-latest   ok    (CohereChatRequest)
Add reasoning_effort: str | None = None as a constructor kwarg. 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.

Single biggest cost knob for reasoning-capable models on OCI: setting
"LOW" typically cuts reasoning-token spend 5-10×. Other
GenericChatRequest fields (verbosity, parallel_tool_calls, logit_bias,
n, metadata, etc.) aren't exposed — they either duplicate existing
controls or aren't missing primitives.
Coderabbit's pre-merge check flagged 45.10% docstring coverage on this
PR; required threshold is 80%. Add concise docstrings for the
remaining 14 methods on OCICompletion (init, provider helpers,
message helpers, response extractors, call/acall, _chat). Coverage now
100% per ast walk; no behavioural change.
Drop unreachable os.getenv defaults in the live-config fixture and fix
the pytest path in the run instructions to include the lib/crewai/
prefix.
@fede-kamel

Copy link
Copy Markdown
Author

Rebased onto current main (85c467d) — merge conflicts resolved, PR is mergeable again.

Also addressed both CodeRabbit comments: the unreachable os.getenv defaults in the live-config fixture are gone, and the pytest run instructions now use the lib/crewai/ prefix.

Verified live against OCI Generative AI on-demand (us-chicago-1): basic completion passes for all five current model families — cohere.command-a-03-2025, meta.llama-4-scout-17b-16e-instruct, google.gemini-2.5-flash, xai.grok-4.3, and openai.gpt-oss-120b. Unit suite: 16 passed.

@fede-kamel

Copy link
Copy Markdown
Author

@joaomdmoura @lorenzejay this provider stack is ready for review — rebased onto current main this week, all mergeable, and verified live against OCI Generative AI on-demand (all five current model families, plus the Cohere v2 vision format).

Suggested review order (each PR builds on the previous):

  1. feat: add OCI Generative AI provider — basic text completion #4959 — core completion (this PR)
  2. feat: add streaming support to OCI Generative AI provider #4961 — streaming
  3. feat: add tool calling support to OCI Generative AI provider #4962 — tool calling
  4. feat: add structured output support to OCI Generative AI provider #4963 — structured output
  5. feat: add multimodal support to OCI Generative AI provider #4964 — multimodal + COHEREV2 api format
  6. feat: add OCI Generative AI embeddings provider #4966 — embeddings (RAG factory)
  7. feat: add true async support to OCI provider via aiohttp #4982 — true async via aiohttp

Happy to squash the stack into fewer PRs if you'd prefer it that way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant