Skip to content

Commit ebbd463

Browse files
committed
fix: llm gateway completions api
1 parent e7485f4 commit ebbd463

6 files changed

Lines changed: 133 additions & 248 deletions

File tree

Lines changed: 13 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -1,230 +1,21 @@
1-
# OpenAI Agents SDK with UiPath Integration
1+
# Agent Code Patterns Reference
22

3-
This document provides patterns for building coded agents using the **OpenAI Agents SDK** with UiPath.
3+
This document provides practical code patterns for building UiPath coded agents using the UiPath Python SDK.
44

55
---
66

7-
## Quick Reference
7+
## Documentation Structure
88

9-
### Agent Pattern (OpenAI Agents SDK)
9+
This documentation is split into multiple files for efficient context loading. Load only the files you need:
1010

11-
```python
12-
from agents import Agent, Runner
11+
1. **@.agent/REQUIRED_STRUCTURE.md** - Agent structure patterns and templates
12+
- **When to load:** Creating a new agent or understanding required patterns
13+
- **Contains:** Required Pydantic models (Input, Output), SDK initialization patterns, standard agent template
1314

14-
# Define your agent
15-
my_agent = Agent(
16-
name="my_agent",
17-
instructions="You are a helpful assistant...",
18-
model="gpt-4o", # Optional: defaults to gpt-4o
19-
tools=[], # Optional: add tools for capabilities
20-
)
15+
2. **@.agent/SDK_REFERENCE.md** - Complete SDK API reference
16+
- **When to load:** Calling UiPath SDK methods, working with services (actions, assets, jobs, etc.)
17+
- **Contains:** All SDK services and methods with full signatures and type annotations
2118

22-
# Register in openai_agents.json:
23-
# {
24-
# "agents": {
25-
# "agent": "main.py:my_agent"
26-
# }
27-
# }
28-
```
29-
30-
### Input Format
31-
32-
OpenAI Agents use **simple message input**:
33-
34-
```json
35-
{
36-
"message": "Your question here"
37-
}
38-
```
39-
40-
Or for conversation history:
41-
42-
```json
43-
{
44-
"messages": [
45-
{"role": "user", "content": "First message"},
46-
{"role": "assistant", "content": "Response"},
47-
{"role": "user", "content": "Follow-up"}
48-
]
49-
}
50-
```
51-
52-
**No Pydantic Input/Output models required** - the runtime handles conversion automatically!
53-
54-
---
55-
56-
## Key Concepts
57-
58-
### 1. Agent Definition
59-
60-
```python
61-
from agents import Agent
62-
63-
assistant = Agent(
64-
name="assistant_agent", # Used in logs and diagrams
65-
instructions="Your system prompt here",
66-
model="gpt-4o", # Optional
67-
tools=[tool1, tool2], # Optional
68-
)
69-
```
70-
71-
### 2. Running Agents
72-
73-
**Via UiPath CLI** (recommended):
74-
```bash
75-
uipath run agent --file input.json
76-
```
77-
78-
**Programmatically**:
79-
```python
80-
from agents import Runner
81-
82-
result = await Runner.run(
83-
starting_agent=assistant,
84-
input="User message" # or list of message dicts
85-
)
86-
```
87-
88-
### 3. Tools (for RAG, APIs, etc.)
89-
90-
```python
91-
from agents import tool
92-
93-
@tool
94-
async def search_docs(query: str) -> str:
95-
"""Search documentation for relevant info."""
96-
# Implementation here
97-
return results
98-
99-
# Add to agent:
100-
agent = Agent(
101-
name="rag_agent",
102-
tools=[search_docs],
103-
instructions="Use search_docs to find information before answering."
104-
)
105-
```
106-
107-
### 4. UiPath Integration
108-
109-
The runtime **automatically injects UiPathChatOpenAI** client when credentials are available:
110-
111-
```bash
112-
# Set these environment variables:
113-
export UIPATH_URL="https://your-tenant.uipath.com"
114-
export UIPATH_ORGANIZATION_ID="your-org-id"
115-
export UIPATH_TENANT_ID="your-tenant-id"
116-
export UIPATH_ACCESS_TOKEN="your-token"
117-
```
118-
119-
All agents will use **UiPath LLM Gateway** instead of direct OpenAI!
120-
121-
---
122-
123-
## Project Structure
124-
125-
```
126-
my-agent/
127-
├── main.py # Agent definition
128-
├── openai_agents.json # Agent registration
129-
├── pyproject.toml # Dependencies
130-
├── input.json # Test input
131-
├── .env # Credentials (gitignored)
132-
└── uipath.json # Runtime config (auto-generated)
133-
```
134-
135-
---
136-
137-
## Common Patterns
138-
139-
### Basic Q&A Agent
140-
141-
```python
142-
from agents import Agent
143-
144-
qa_agent = Agent(
145-
name="qa_agent",
146-
instructions="Answer questions concisely and accurately."
147-
)
148-
```
149-
150-
### Agent with Tools (RAG)
151-
152-
```python
153-
from agents import Agent, tool
154-
155-
@tool
156-
async def retrieve_context(query: str) -> str:
157-
"""Retrieve relevant context from knowledge base."""
158-
# Use UiPath Context Grounding or custom retriever
159-
return context
160-
161-
rag_agent = Agent(
162-
name="rag_agent",
163-
instructions="Use retrieve_context before answering questions.",
164-
tools=[retrieve_context]
165-
)
166-
```
167-
168-
### Multi-Agent (Handoffs)
169-
170-
```python
171-
from agents import Agent
172-
173-
specialist = Agent(
174-
name="specialist",
175-
instructions="You are a domain expert..."
176-
)
177-
178-
coordinator = Agent(
179-
name="coordinator",
180-
instructions="Route requests to the specialist when needed.",
181-
handoffs=[specialist]
182-
)
183-
```
184-
185-
---
186-
187-
## Testing
188-
189-
```bash
190-
# Initialize project
191-
uipath init
192-
193-
# Run agent
194-
uipath run agent --file input.json
195-
196-
# With inline input
197-
uipath run agent '{"message": "Hello!"}'
198-
199-
# Debug mode
200-
uipath run agent --debug --file input.json
201-
```
202-
203-
---
204-
205-
## Differences from LangGraph/LlamaIndex
206-
207-
| Aspect | OpenAI Agents SDK | LangGraph/LlamaIndex |
208-
|--------|-------------------|----------------------|
209-
| **Input** | `{"message": "..."}` | Pydantic Input model required |
210-
| **Output** | Free-form response | Pydantic Output model required |
211-
| **Agent Type** | Agentic (LLM decides) | Workflow-based (fixed graph) |
212-
| **Tools** | `@tool` decorator | Custom tool classes |
213-
| **Registration** | `openai_agents.json` | `uipath.json` functions |
214-
215-
---
216-
217-
## Resources
218-
219-
- **OpenAI Agents SDK**: https://github.com/openai/openai-agents-python
220-
- **UiPath Python SDK**: https://uipath.github.io/uipath-python/
221-
- **Samples**: Check `samples/` directory for examples
222-
223-
---
224-
225-
## Getting Help
226-
227-
If you need assistance:
228-
- Check sample projects in `samples/`
229-
- Review OpenAI Agents SDK documentation
230-
- Open issues at https://github.com/anthropics/claude-code/issues
19+
3. **@.agent/CLI_REFERENCE.md** - CLI commands documentation
20+
- **When to load:** Working with `uipath init`, `uipath run`, or `uipath eval` commands
21+
- **Contains:** Command syntax, options, usage examples, and workflows

packages/uipath-openai-agents/samples/rag-assistant/entry-points.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"entryPoints": [
55
{
66
"filePath": "agent",
7-
"uniqueId": "f3f04855-8064-46b5-a746-929568a6224d",
7+
"uniqueId": "31b69d3d-4ae1-4caa-be64-b2fe368590a7",
88
"type": "agent",
99
"input": {
1010
"type": "object",

packages/uipath-openai-agents/samples/rag-assistant/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Output(BaseModel):
3434
# Define the assistant agent
3535
assistant_agent = Agent(
3636
name="assistant_agent",
37+
model="gpt-4o-2024-11-20", # Use specific version supported by UiPath LLM Gateway
3738
instructions="""You are a helpful AI assistant that provides clear, concise answers.
3839
3940
Your capabilities:

packages/uipath-openai-agents/src/uipath_openai_agents/chat/openai.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
from .supported_models import OpenAIModels
1212

1313

14-
def _rewrite_openai_url(original_url: str, params: httpx.QueryParams) -> httpx.URL:
14+
def _rewrite_openai_url(
15+
original_url: str, params: httpx.QueryParams
16+
) -> httpx.URL | None:
1517
"""Rewrite OpenAI URLs to UiPath gateway completions endpoint.
1618
17-
Handles URL patterns from OpenAI SDK and rewrites them to .../completions
19+
Handles URL patterns from OpenAI SDK and rewrites to /completions.
20+
The X-UiPath-LlmGateway-ApiFlavor header determines API behavior.
1821
1922
Args:
2023
original_url: Original URL from OpenAI SDK
@@ -23,12 +26,15 @@ def _rewrite_openai_url(original_url: str, params: httpx.QueryParams) -> httpx.U
2326
Returns:
2427
Rewritten URL pointing to UiPath completions endpoint
2528
"""
26-
if "/chat/completions" in original_url:
29+
# Extract base URL before endpoint path
30+
if "/responses" in original_url:
31+
base_url = original_url.split("/responses")[0]
32+
elif "/chat/completions" in original_url:
2733
base_url = original_url.split("/chat/completions")[0]
2834
elif "/completions" in original_url:
2935
base_url = original_url.split("/completions")[0]
3036
else:
31-
# Handle base URL case
37+
# Handle base URL case - strip query string
3238
base_url = original_url.split("?")[0]
3339

3440
new_url_str = f"{base_url}/completions"
@@ -46,7 +52,8 @@ def __init__(self, verify: bool = True, **kwargs):
4652
async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
4753
"""Handle async request with URL rewriting."""
4854
new_url = _rewrite_openai_url(str(request.url), request.url.params)
49-
request.url = new_url
55+
if new_url:
56+
request.url = new_url
5057
return await super().handle_async_request(request)
5158

5259

@@ -59,7 +66,8 @@ def __init__(self, verify: bool = True, **kwargs):
5966
def handle_request(self, request: httpx.Request) -> httpx.Response:
6067
"""Handle sync request with URL rewriting."""
6168
new_url = _rewrite_openai_url(str(request.url), request.url.params)
62-
request.url = new_url
69+
if new_url:
70+
request.url = new_url
6371
return super().handle_request(request)
6472

6573

@@ -95,25 +103,28 @@ class UiPathChatOpenAI:
95103
def __init__(
96104
self,
97105
token: Optional[str] = None,
98-
model_name: str = OpenAIModels.gpt_4o,
106+
model_name: str = OpenAIModels.gpt_4o_2024_11_20,
99107
api_version: str = "2024-12-01-preview",
100108
org_id: Optional[str] = None,
101109
tenant_id: Optional[str] = None,
102110
agenthub_config: Optional[str] = None,
103111
extra_headers: Optional[dict[str, str]] = None,
104112
byo_connection_id: Optional[str] = None,
113+
api_flavor: str = "responses",
105114
):
106115
"""Initialize UiPath OpenAI client.
107116
108117
Args:
109118
token: UiPath access token (defaults to UIPATH_ACCESS_TOKEN env var)
110-
model_name: Model to use (e.g., "gpt-4o")
119+
model_name: Model to use (e.g., "gpt-4o-2024-11-20")
111120
api_version: OpenAI API version
112121
org_id: UiPath organization ID (defaults to UIPATH_ORGANIZATION_ID env var)
113122
tenant_id: UiPath tenant ID (defaults to UIPATH_TENANT_ID env var)
114123
agenthub_config: Optional AgentHub configuration
115124
extra_headers: Additional headers to include in requests
116125
byo_connection_id: Bring-your-own connection ID
126+
api_flavor: API flavor to use - "responses" (default, recommended for agents),
127+
"chat-completions" (traditional chat), or "auto" (let UiPath decide)
117128
"""
118129
# Get credentials from env vars if not provided
119130
self._org_id = org_id or os.getenv("UIPATH_ORGANIZATION_ID")
@@ -140,6 +151,7 @@ def __init__(
140151
self._vendor = "openai"
141152
self._agenthub_config = agenthub_config
142153
self._byo_connection_id = byo_connection_id
154+
self._api_flavor = api_flavor
143155
self._extra_headers = extra_headers or {}
144156

145157
# Build base URL and headers
@@ -175,7 +187,7 @@ def __init__(
175187
def _build_headers(self) -> dict[str, str]:
176188
"""Build headers for UiPath LLM Gateway."""
177189
headers = {
178-
"X-UiPath-LlmGateway-ApiFlavor": "auto",
190+
"X-UiPath-LlmGateway-ApiFlavor": self._api_flavor,
179191
"Authorization": f"Bearer {self._token}",
180192
}
181193

@@ -195,17 +207,22 @@ def _build_headers(self) -> dict[str, str]:
195207

196208
@property
197209
def endpoint(self) -> str:
198-
"""Get the UiPath endpoint for this model."""
210+
"""Get the UiPath endpoint for this model (without query parameters)."""
199211
vendor_endpoint = EndpointManager.get_vendor_endpoint()
200212
formatted_endpoint = vendor_endpoint.format(
201213
vendor=self._vendor,
202214
model=self._model_name,
203215
)
216+
# Remove /completions suffix - will be added by URL rewriting
204217
base_endpoint = formatted_endpoint.replace("/completions", "")
205-
return f"{base_endpoint}?api-version={self._api_version}"
218+
return base_endpoint
206219

207220
def _build_base_url(self) -> str:
208-
"""Build the base URL for OpenAI client."""
221+
"""Build the base URL for OpenAI client.
222+
223+
Note: Query parameters like api-version are added by the URL rewriting logic,
224+
not in the base URL, to allow the SDK to append paths properly.
225+
"""
209226
env_uipath_url = os.getenv("UIPATH_URL")
210227

211228
if env_uipath_url:

0 commit comments

Comments
 (0)