diff --git a/MIGRATION.md b/MIGRATION.md index 7ff0799..21ad8a4 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -7,9 +7,7 @@ This guide helps existing `oci-openai` users migrate to `oci-genai-auth`. - Replace dependency `oci-openai` with `oci-genai-auth`. - Continue using the `openai` Python SDK client. - Use `OciSessionAuth` to sign requests with OCI IAM. -- Choose endpoint/config based on API mode.: - - AgentHub: `https://inference.generativeai..oci.oraclecloud.com/openai/v1` + `project` - - Partner : `https://inference.generativeai..oci.oraclecloud.com/20231130/actions/v1` + `opc-compartment-id` +- Use endpoint `https://inference.generativeai..oci.oraclecloud.com/openai/v1` with a `project` OCID. ## 1) Dependency Changes @@ -30,8 +28,6 @@ from oci_openai import OciSessionAuth ## 3) Client Initialization Changes -### AgentHub - Use the OpenAI-compatible endpoint and provide project OCID: ```python @@ -47,28 +43,7 @@ client = OpenAI( ) ``` -### Partner APIs - -Use `/v1` and include compartment header: - -```python -import httpx -from openai import OpenAI -from oci_genai_auth import OciSessionAuth - -client = OpenAI( - base_url="https://inference.generativeai..oci.oraclecloud.com/v1", - api_key="not-used", - default_headers={"opc-compartment-id": ""}, - http_client=httpx.Client(auth=OciSessionAuth(profile_name="DEFAULT")), -) -``` - ## 4) Endpoint and required parameters -- AgentHub: - - `base_url`: `https://inference.generativeai..oci.oraclecloud.com/openai/v1` - - required: `project=` -- Partner: - - `base_url`: `https://inference.generativeai..oci.oraclecloud.com/v1` - - required header: `opc-compartment-id=` +- `base_url`: `https://inference.generativeai..oci.oraclecloud.com/openai/v1` +- required: `project=` diff --git a/README.md b/README.md index 173abee..4a23dfa 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,7 @@ The **OCI GenAI Auth** Python library provides OCI request-signing helpers for t - [Using OCI IAM Auth](#using-oci-iam-auth) - [Using API Key Auth](#using-api-key-auth) - [Using AgentHub APIs](#using-agenthub-apis) -- [Using Partner APIs (passthrough)](#using-partner-apis-passthrough) -- [Running the Examples](#running-the-examples) +- [Examples](#examples) - [Contributing](#contributing) - [Security](#security) - [License](#license) @@ -86,33 +85,8 @@ client = OpenAI( ) ``` -## Using Partner APIs (passthrough) - -OCI also offers Partner API which passes through your calls to partners such as OpenAI. We will support more partners in the future. - -You can leverage Partner API when you want to use OpenAI's API and GPT models, but with OCI auth and billing. - -Note: Currently Partner API is only available to Oracle internal teams. Only features that meet partner's Zero Data Retention are available through Partner API. - -If you want multi-provider model access and features unavailable under partner's Zero Data Retention (such as File Search), use the AgentHub APIs above. - -```python -import httpx -from openai import OpenAI -from oci_genai_auth import OciSessionAuth - -client = OpenAI( - base_url="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/v1", - api_key="not-used", - default_headers={ - "opc-compartment-id": "ocid1.compartment.oc1..aaaaaaaaexample", - }, - http_client=httpx.Client(auth=OciSessionAuth(profile_name="DEFAULT")), -) -``` - ## Examples -Demo code and instructions on how to run them, for both agenthub and partner usecases can be found in ```examples``` folder. +Demo code and instructions on how to run them can be found in the ```examples``` folder. ## Contributing diff --git a/examples/partner/README.md b/examples/partner/README.md deleted file mode 100644 index ccadd0a..0000000 --- a/examples/partner/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Partner Examples - -This folder contains partner API examples using the OpenAI Python SDK. - -## Prerequisites - -1. Install dependencies: - - ```bash - pip install -e '.[dev]' - ``` - -2. Configure shared values in `examples/partner/common.py`: - - `PROFILE_NAME` - - `COMPARTMENT_ID` - - `REGION` - -## How to run - -From repository root: - -```bash -python -m examples.partner.openai.quickstart_openai_chat_completions -``` - -## Notes - -- Partner endpoints use pass-through mode and require the `opc-compartment-id` header. -- These examples use IAM signing through `oci-genai-auth`. diff --git a/examples/partner/__init__.py b/examples/partner/__init__.py deleted file mode 100644 index b38e643..0000000 --- a/examples/partner/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/examples/partner/common.py b/examples/partner/common.py deleted file mode 100644 index 05cec13..0000000 --- a/examples/partner/common.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ - -"""Partner example clients and configuration.""" - -from __future__ import annotations - -import httpx -from openai import AsyncOpenAI, OpenAI - -from oci_genai_auth import OciSessionAuth - -PROFILE_NAME = "DEFAULT" -COMPARTMENT_ID = "<>" -REGION = "us-chicago-1" - -PARTNER_OPENAI_BASE_URL = f"https://inference.generativeai.{REGION}.oci.oraclecloud.com/20231130/actions/v1" - - -def build_openai_client() -> OpenAI: - client_kwargs = { - "api_key": "not-used", - "base_url": PARTNER_OPENAI_BASE_URL, - "http_client": httpx.Client(auth=OciSessionAuth(profile_name=PROFILE_NAME)), - } - if COMPARTMENT_ID: - client_kwargs["default_headers"] = {"opc-compartment-id": COMPARTMENT_ID} - return OpenAI(**client_kwargs) - - -def build_openai_async_client() -> AsyncOpenAI: - client_kwargs = { - "api_key": "not-used", - "base_url": PARTNER_OPENAI_BASE_URL, - "http_client": httpx.AsyncClient(auth=OciSessionAuth(profile_name=PROFILE_NAME)), - } - if COMPARTMENT_ID: - client_kwargs["default_headers"] = {"opc-compartment-id": COMPARTMENT_ID} - return AsyncOpenAI(**client_kwargs) diff --git a/examples/partner/openai/__init__.py b/examples/partner/openai/__init__.py deleted file mode 100644 index b38e643..0000000 --- a/examples/partner/openai/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/examples/partner/openai/basic_chat_completion.py b/examples/partner/openai/basic_chat_completion.py deleted file mode 100644 index 4437c5e..0000000 --- a/examples/partner/openai/basic_chat_completion.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ - -"""Demonstrates a basic chat completion request for the Partner endpoint.""" - -from rich import print - -from examples.partner import common - -MODEL = "openai.gpt-5.2" - - -def main(): - openai_client = common.build_openai_client() - - completion = openai_client.chat.completions.create( - model=MODEL, - messages=[ - {"role": "system", "content": "You are a concise assistant."}, - {"role": "user", "content": "List three creative uses for a paperclip."}, - ], - max_tokens=128, - ) - - print(completion.model_dump_json(indent=2)) - - -if __name__ == "__main__": - main() diff --git a/examples/partner/openai/basic_chat_completion_api_key.py b/examples/partner/openai/basic_chat_completion_api_key.py deleted file mode 100644 index 23fbbd8..0000000 --- a/examples/partner/openai/basic_chat_completion_api_key.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ - -"""Demonstrates the Basic chat completion api key example.""" - -import os - -from openai import OpenAI - -MODEL = "openai.gpt-5.2" - - -def main() -> None: - client = OpenAI( - api_key=os.getenv("OPENAI_API_KEY"), - base_url="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1", - ) - - response = client.chat.completions.create( - model=MODEL, - messages=[ - { - "role": "system", - "content": "You are a concise assistant who answers in one paragraph.", - }, - { - "role": "user", - "content": "Explain why the sky is blue as if you were a physics teacher.", - }, - ], - ) - - print(response.choices[0].message.content) - - -if __name__ == "__main__": - main() diff --git a/examples/partner/openai/quickstart_openai_chat_completions.py b/examples/partner/openai/quickstart_openai_chat_completions.py deleted file mode 100755 index 8d1b6ff..0000000 --- a/examples/partner/openai/quickstart_openai_chat_completions.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ - -"""Demonstrates a simple openai chat completions example.""" - -import logging - -from examples.partner import common - -logging.basicConfig(level=logging.DEBUG) - -MODEL="openai.gpt-5.2" - -def main(): - client = common.build_openai_client() - - completion = client.chat.completions.create( - model=MODEL, - messages=[ - { - "role": "user", - "content": "How do I output all files in a directory using Python?", - }, - ], - ) - print(completion.model_dump_json()) - - # Process the stream - print("=" * 80) - print("Process in streaming mode") - streaming = client.chat.completions.create( - model=MODEL, - messages=[ - { - "role": "user", - "content": "How do I output all files in a directory using Python?", - }, - ], - stream=True, - ) - for chunk in streaming: - print(chunk) - - -if __name__ == "__main__": - main() diff --git a/examples/partner/openai/streaming_chat_completion.py b/examples/partner/openai/streaming_chat_completion.py deleted file mode 100644 index 3abd7e1..0000000 --- a/examples/partner/openai/streaming_chat_completion.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ - -"""Demonstrates streaming chat completion responses for the Partner (pass-through) endpoint.""" - -from examples.partner import common - -MODEL = "openai.gpt-5.2" - - -def main(): - openai_client = common.build_openai_client() - - stream = openai_client.chat.completions.create( - model=MODEL, - messages=[ - { - "role": "system", - "content": "You are a concise assistant who answers in one paragraph.", - }, - { - "role": "user", - "content": "Explain why the sky is blue as if you were a physics teacher.", - }, - ], - stream=True, - ) - - for chunk in stream: - for choice in chunk.choices: - delta = choice.delta - if delta.content: - print(delta.content, end="", flush=True) - print() - - -if __name__ == "__main__": - main() diff --git a/examples/partner/openai/tool_call_chat_completion.py b/examples/partner/openai/tool_call_chat_completion.py deleted file mode 100644 index 81b0205..0000000 --- a/examples/partner/openai/tool_call_chat_completion.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (c) 2026 Oracle and/or its affiliates. -# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ - -"""Demonstrates tool calling with chat completions for the Partner endpoint.""" - -import json -from typing import Dict - -from examples.partner import common - -MODEL = "openai.gpt-5.2" - - -def get_current_weather(location: str, unit: str = "fahrenheit") -> Dict[str, str]: - # Simple stand-in for a real weather lookup. - return { - "location": location, - "temperature": "72", - "unit": unit, - "forecast": ["sunny", "windy"], - } - - -def main(): - openai_client = common.build_openai_client() - - messages = [ - { - "role": "user", - "content": "What is the weather like in Boston and San Francisco?", - } - ] - tools = [ - { - "type": "function", - "function": { - "name": "get_current_weather", - "description": "Get the current weather for a specific location.", - "parameters": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "City and state, for example Boston, MA.", - }, - "unit": { - "type": "string", - "enum": ["celsius", "fahrenheit"], - "description": "Temperature unit to use in the response.", - }, - }, - "required": ["location"], - }, - }, - } - ] - - first_response = openai_client.chat.completions.create( - model=MODEL, - messages=messages, - tools=tools, - tool_choice="auto", - ) - first_choice = first_response.choices[0] - - if first_choice.finish_reason == "tool_calls": - call_message = first_choice.message - new_messages = messages + [call_message] - for tool_call in call_message.tool_calls: - args = json.loads(tool_call.function.arguments) - tool_result = get_current_weather( - location=args.get("location", ""), - unit=args.get("unit", "fahrenheit"), - ) - new_messages.append( - { - "role": "tool", - "name": tool_call.function.name, - "tool_call_id": tool_call.id, - "content": json.dumps(tool_result), - } - ) - - follow_up = openai_client.chat.completions.create( - model=MODEL, - messages=new_messages, - ) - print(follow_up.choices[0].message.content) - else: - print(first_choice.message.content) - - -if __name__ == "__main__": - main()