Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,81 @@ The package provides the `agentex` CLI with these main commands:
- Debug agents: `agentex agents run --manifest manifest.yaml --debug-worker`
- Debug with custom port: `agentex agents run --manifest manifest.yaml --debug-worker --debug-port 5679`

### Custom OpenAI Client for Agents SDK

Configure custom OpenAI clients **specifically for the OpenAI Agents SDK** integration (Agent and Runner classes).

⚠️ **Scope**: This configuration ONLY affects OpenAI Agents SDK operations. It does NOT affect:
- LiteLLM integration (configure LiteLLM separately via environment variables or LiteLLM config)
- SGP integration
- Direct OpenAI API calls

#### Requirements
- Must use **async** client: `AsyncOpenAI` or `AsyncAzureOpenAI`
- Sync clients (`OpenAI`) are not supported by the Agents SDK

#### Basic Usage (Custom Endpoint)

Use this for custom OpenAI-compatible endpoints such as LiteLLM proxy for cost tracking:

```python
from openai import AsyncOpenAI
from agentex.lib.adk.providers._modules.openai_agents_config import (
initialize_openai_agents_client
)

# Configure custom endpoint
client = AsyncOpenAI(
base_url="https://your-proxy.com/v1",
api_key=os.getenv("CUSTOM_API_KEY")
)
initialize_openai_agents_client(client)
```

#### Azure OpenAI

```python
from openai import AsyncAzureOpenAI
from agentex.lib.adk.providers._modules.openai_agents_config import (
initialize_openai_agents_client
)

client = AsyncAzureOpenAI(
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_KEY"),
api_version="2024-02-01"
)
initialize_openai_agents_client(client)
```

#### Temporal Workers

Call `initialize_openai_agents_client()` in your worker startup script **BEFORE** starting the worker:

```python
# run_worker.py
import os
from openai import AsyncOpenAI
from agentex.lib.adk.providers._modules.openai_agents_config import (
initialize_openai_agents_client
)

# Step 1: Configure client before starting worker
if os.getenv("CUSTOM_OPENAI_BASE_URL"):
client = AsyncOpenAI(
base_url=os.getenv("CUSTOM_OPENAI_BASE_URL"),
api_key=os.getenv("OPENAI_API_KEY")
)
initialize_openai_agents_client(client)

# Step 2: Start worker (all agent operations will use configured client)
# ... worker startup code ...
```

#### Backward Compatibility

If `initialize_openai_agents_client()` is not called, the OpenAI Agents SDK uses default OpenAI configuration via the `OPENAI_API_KEY` environment variable. All existing code continues to work without changes.

## Architecture Overview

### Code Structure
Expand Down
116 changes: 116 additions & 0 deletions src/agentex/lib/adk/providers/_modules/openai_agents_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""
OpenAI Agents SDK Client Configuration

Configures custom OpenAI clients specifically for the OpenAI Agents SDK.
This affects ONLY the OpenAI Agents SDK integration (Agent and Runner).

For LiteLLM integration, use separate LiteLLM configuration methods.
"""

from typing import Union
from openai import AsyncOpenAI, AsyncAzureOpenAI
from agents import set_default_openai_client
from agentex.lib.utils.logging import make_logger

logger = make_logger(__name__)

# Type alias for supported async OpenAI clients
AsyncOpenAIClient = Union[AsyncOpenAI, AsyncAzureOpenAI]

_client_initialized = False


def initialize_openai_agents_client(client: AsyncOpenAIClient) -> None:
"""
Initialize custom OpenAI client for OpenAI Agents SDK operations.

⚠️ IMPORTANT: This ONLY affects the OpenAI Agents SDK integration
(Agent and Runner classes). It does NOT affect:
- LiteLLM integration (use LiteLLM configuration separately)
- SGP integration
- Direct OpenAI API calls

This should be called ONCE at application or worker startup, before any
agents are created using the OpenAI Agents SDK.

Args:
client: Pre-configured async OpenAI client (AsyncOpenAI or AsyncAzureOpenAI)

Raises:
TypeError: If a non-async client is passed (will be caught by type checker)

Examples:
# Custom endpoint (e.g., LiteLLM proxy for cost tracking):
from openai import AsyncOpenAI
from agentex.lib.adk.providers._modules.openai_agents_config import (
initialize_openai_agents_client
)

client = AsyncOpenAI(
base_url="https://your-proxy.com/v1",
api_key=os.getenv("CUSTOM_API_KEY")
)
initialize_openai_agents_client(client)

# Azure OpenAI:
from openai import AsyncAzureOpenAI

client = AsyncAzureOpenAI(
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_KEY"),
api_version="2024-02-01"
)
initialize_openai_agents_client(client)

# For Temporal workers, call this in worker startup:
# run_worker.py:
# initialize_openai_agents_client(client)
# # Then start worker...

Note:
If not called, the OpenAI Agents SDK uses default OpenAI configuration
via the OPENAI_API_KEY environment variable.
"""
global _client_initialized

if _client_initialized:
logger.warning(
"OpenAI Agents SDK client already initialized. "
"Ignoring subsequent initialization. "
"This may indicate multiple workers or initialization calls."
)
return

# Runtime validation for async client
if not isinstance(client, (AsyncOpenAI, AsyncAzureOpenAI)):
raise TypeError(
f"Client must be AsyncOpenAI or AsyncAzureOpenAI, got {type(client).__name__}. "
f"The OpenAI Agents SDK requires async clients. "
f"Use AsyncOpenAI instead of OpenAI."
)

set_default_openai_client(client)
logger.info(f"OpenAI Agents SDK client configured: {type(client).__name__}")

_client_initialized = True


def is_openai_agents_client_initialized() -> bool:
"""
Check if custom OpenAI Agents SDK client has been initialized.

Returns:
bool: True if initialize_openai_agents_client() has been called
"""
return _client_initialized


def reset_openai_agents_client_initialization() -> None:
"""
Reset initialization flag (primarily for testing).

Warning: This does NOT reset the actual client in the agents library,
only the initialization tracking flag in this module.
"""
global _client_initialized
_client_initialized = False
Loading