uipath-openai-agents 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uipath_openai_agents/__init__.py +7 -0
- uipath_openai_agents/_cli/__init__.py +1 -0
- uipath_openai_agents/_cli/_templates/AGENTS.md.template +21 -0
- uipath_openai_agents/_cli/_templates/main.py.template +28 -0
- uipath_openai_agents/_cli/_templates/openai_agents.json.template +5 -0
- uipath_openai_agents/_cli/cli_new.py +81 -0
- uipath_openai_agents/chat/__init__.py +5 -0
- uipath_openai_agents/chat/openai.py +242 -0
- uipath_openai_agents/chat/supported_models.py +78 -0
- uipath_openai_agents/middlewares.py +8 -0
- uipath_openai_agents/py.typed +0 -0
- uipath_openai_agents/runtime/__init__.py +40 -0
- uipath_openai_agents/runtime/_serialize.py +51 -0
- uipath_openai_agents/runtime/_sqlite.py +190 -0
- uipath_openai_agents/runtime/_telemetry.py +32 -0
- uipath_openai_agents/runtime/agent.py +201 -0
- uipath_openai_agents/runtime/config.py +55 -0
- uipath_openai_agents/runtime/errors.py +48 -0
- uipath_openai_agents/runtime/factory.py +353 -0
- uipath_openai_agents/runtime/runtime.py +532 -0
- uipath_openai_agents/runtime/schema.py +490 -0
- uipath_openai_agents/runtime/storage.py +357 -0
- uipath_openai_agents-0.0.1.dist-info/METADATA +53 -0
- uipath_openai_agents-0.0.1.dist-info/RECORD +26 -0
- uipath_openai_agents-0.0.1.dist-info/WHEEL +4 -0
- uipath_openai_agents-0.0.1.dist-info/entry_points.txt +5 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Async SQLite connection manager with automatic serialization."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Iterable
|
|
7
|
+
from contextlib import asynccontextmanager
|
|
8
|
+
from sqlite3 import Row
|
|
9
|
+
from typing import Any, AsyncIterator
|
|
10
|
+
|
|
11
|
+
import aiosqlite
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AsyncSqlite:
|
|
15
|
+
"""Async SQLite wrapper with automatic serialization via locks.
|
|
16
|
+
|
|
17
|
+
Provides thread-safe access to a SQLite database using asyncio locks
|
|
18
|
+
to serialize operations. Maintains a single connection and ensures
|
|
19
|
+
proper WAL mode configuration.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, db_path: str, timeout: float = 30.0):
|
|
23
|
+
"""
|
|
24
|
+
Initialize AsyncSQLite manager.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
db_path: Path to the SQLite database file
|
|
28
|
+
timeout: Database connection timeout in seconds
|
|
29
|
+
"""
|
|
30
|
+
self.db_path = db_path
|
|
31
|
+
self.timeout = timeout
|
|
32
|
+
self.conn: aiosqlite.Connection | None = None
|
|
33
|
+
self.lock = asyncio.Lock()
|
|
34
|
+
self.is_setup = False
|
|
35
|
+
|
|
36
|
+
async def __aenter__(self) -> AsyncSqlite:
|
|
37
|
+
"""Async context manager entry."""
|
|
38
|
+
await self.connect()
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
async def __aexit__(self, *args) -> None:
|
|
42
|
+
"""Async context manager exit."""
|
|
43
|
+
await self.close()
|
|
44
|
+
|
|
45
|
+
async def connect(self) -> None:
|
|
46
|
+
"""Establish database connection and apply initial pragmas."""
|
|
47
|
+
if self.conn is not None:
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
self.conn = await aiosqlite.connect(self.db_path, timeout=self.timeout)
|
|
51
|
+
await self._apply_connection_pragmas()
|
|
52
|
+
|
|
53
|
+
# WAL mode is persistent, set once
|
|
54
|
+
await self.conn.execute("PRAGMA journal_mode=WAL")
|
|
55
|
+
await self.conn.commit()
|
|
56
|
+
|
|
57
|
+
async def close(self) -> None:
|
|
58
|
+
"""Close database connection."""
|
|
59
|
+
if self.conn:
|
|
60
|
+
await self.conn.close()
|
|
61
|
+
self.conn = None
|
|
62
|
+
self.is_setup = False
|
|
63
|
+
|
|
64
|
+
async def execute(
|
|
65
|
+
self, query: str, parameters: tuple[Any, ...] | None = None
|
|
66
|
+
) -> aiosqlite.Cursor:
|
|
67
|
+
"""
|
|
68
|
+
Execute a single query with automatic locking.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
query: SQL query to execute
|
|
72
|
+
parameters: Query parameters
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Cursor with query results
|
|
76
|
+
"""
|
|
77
|
+
if self.conn is None:
|
|
78
|
+
await self.connect()
|
|
79
|
+
|
|
80
|
+
assert self.conn is not None
|
|
81
|
+
|
|
82
|
+
async with self.lock:
|
|
83
|
+
return await self.conn.execute(query, parameters or ())
|
|
84
|
+
|
|
85
|
+
async def executemany(
|
|
86
|
+
self, query: str, parameters_list: list[tuple[Any, ...]]
|
|
87
|
+
) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Execute a query multiple times with different parameters.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
query: SQL query to execute
|
|
93
|
+
parameters_list: List of parameter tuples
|
|
94
|
+
"""
|
|
95
|
+
if self.conn is None:
|
|
96
|
+
await self.connect()
|
|
97
|
+
|
|
98
|
+
assert self.conn is not None
|
|
99
|
+
|
|
100
|
+
async with self.lock:
|
|
101
|
+
await self.conn.executemany(query, parameters_list)
|
|
102
|
+
await self.conn.commit()
|
|
103
|
+
|
|
104
|
+
async def executescript(self, script: str) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Execute a SQL script (multiple statements).
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
script: SQL script to execute
|
|
110
|
+
"""
|
|
111
|
+
if self.conn is None:
|
|
112
|
+
await self.connect()
|
|
113
|
+
|
|
114
|
+
assert self.conn is not None
|
|
115
|
+
|
|
116
|
+
async with self.lock:
|
|
117
|
+
await self.conn.executescript(script)
|
|
118
|
+
await self.conn.commit()
|
|
119
|
+
|
|
120
|
+
async def commit(self) -> None:
|
|
121
|
+
"""Commit the current transaction."""
|
|
122
|
+
if self.conn is None:
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
assert self.conn is not None
|
|
126
|
+
|
|
127
|
+
async with self.lock:
|
|
128
|
+
await self.conn.commit()
|
|
129
|
+
|
|
130
|
+
@asynccontextmanager
|
|
131
|
+
async def cursor(self) -> AsyncIterator[aiosqlite.Cursor]:
|
|
132
|
+
"""
|
|
133
|
+
Get a cursor with automatic locking.
|
|
134
|
+
|
|
135
|
+
Yields:
|
|
136
|
+
Database cursor
|
|
137
|
+
"""
|
|
138
|
+
if self.conn is None:
|
|
139
|
+
await self.connect()
|
|
140
|
+
|
|
141
|
+
assert self.conn is not None
|
|
142
|
+
|
|
143
|
+
async with self.lock:
|
|
144
|
+
cursor = await self.conn.cursor()
|
|
145
|
+
try:
|
|
146
|
+
yield cursor
|
|
147
|
+
finally:
|
|
148
|
+
await cursor.close()
|
|
149
|
+
|
|
150
|
+
async def fetchone(
|
|
151
|
+
self, query: str, parameters: tuple[Any, ...] | None = None
|
|
152
|
+
) -> Row | None:
|
|
153
|
+
"""
|
|
154
|
+
Execute query and fetch one result.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
query: SQL query to execute
|
|
158
|
+
parameters: Query parameters
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Single row or None
|
|
162
|
+
"""
|
|
163
|
+
cursor = await self.execute(query, parameters)
|
|
164
|
+
return await cursor.fetchone()
|
|
165
|
+
|
|
166
|
+
async def fetchall(
|
|
167
|
+
self, query: str, parameters: tuple[Any, ...] | None = None
|
|
168
|
+
) -> Iterable[Row]:
|
|
169
|
+
"""
|
|
170
|
+
Execute query and fetch all results.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
query: SQL query to execute
|
|
174
|
+
parameters: Query parameters
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
List of rows
|
|
178
|
+
"""
|
|
179
|
+
cursor = await self.execute(query, parameters)
|
|
180
|
+
return await cursor.fetchall()
|
|
181
|
+
|
|
182
|
+
async def _apply_connection_pragmas(self) -> None:
|
|
183
|
+
"""Apply per-connection PRAGMA settings for optimal concurrency."""
|
|
184
|
+
if self.conn is None:
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
await self.conn.execute(f"PRAGMA busy_timeout={int(self.timeout * 1000)}")
|
|
188
|
+
await self.conn.execute("PRAGMA synchronous=NORMAL")
|
|
189
|
+
await self.conn.execute("PRAGMA cache_size=10000")
|
|
190
|
+
await self.conn.execute("PRAGMA temp_store=MEMORY")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""OpenInference tracing integration for OpenAI Agents."""
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from opentelemetry import trace
|
|
5
|
+
|
|
6
|
+
TELEMETRY_AVAILABLE = True
|
|
7
|
+
except ImportError:
|
|
8
|
+
TELEMETRY_AVAILABLE = False
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if TELEMETRY_AVAILABLE:
|
|
12
|
+
|
|
13
|
+
def get_current_span_wrapper():
|
|
14
|
+
"""Wrapper to get the current span from OpenTelemetry.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
The current OpenTelemetry span if available, None otherwise
|
|
18
|
+
"""
|
|
19
|
+
return trace.get_current_span()
|
|
20
|
+
|
|
21
|
+
else:
|
|
22
|
+
|
|
23
|
+
def get_current_span_wrapper():
|
|
24
|
+
"""Stub function when OpenTelemetry is not available.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
None since telemetry dependencies are not available
|
|
28
|
+
"""
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = ["get_current_span_wrapper"]
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Self
|
|
7
|
+
|
|
8
|
+
from agents import Agent
|
|
9
|
+
from uipath.runtime.errors import UiPathErrorCategory
|
|
10
|
+
|
|
11
|
+
from .errors import (
|
|
12
|
+
UiPathOpenAIAgentsErrorCode,
|
|
13
|
+
UiPathOpenAIAgentsRuntimeError,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OpenAiAgentLoader:
|
|
18
|
+
"""Load agent from a Python file path (e.g.: 'main.py:agent')"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, name: str, file_path: str, variable_name: str):
|
|
21
|
+
"""Initialize the openi agent loader.
|
|
22
|
+
Args:
|
|
23
|
+
name: The name of the agent.
|
|
24
|
+
file_path: The path to the Python file containing the agent.
|
|
25
|
+
variable_name: The name of the variable that contains the agent instance.
|
|
26
|
+
"""
|
|
27
|
+
self.name = name
|
|
28
|
+
self.file_path = file_path
|
|
29
|
+
self.variable_name = variable_name
|
|
30
|
+
self._context_manager: Any = None
|
|
31
|
+
self._loaded_object: Any = (
|
|
32
|
+
None # Store original loaded object for type inference
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def from_path_string(cls, name: str, file_path: str) -> Self:
|
|
37
|
+
"""
|
|
38
|
+
Create an OpenAiAgentLoader from a path string.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
name: Human-readable name of the agent.
|
|
42
|
+
path: The path string in the format 'file_path:variable_name'.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
An instance of OpenAiAgentLoader.
|
|
46
|
+
"""
|
|
47
|
+
if ":" not in file_path:
|
|
48
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
49
|
+
code=UiPathOpenAIAgentsErrorCode.CONFIG_INVALID,
|
|
50
|
+
title="Invalid agent path format",
|
|
51
|
+
detail=f"Invalid path format '{file_path}'. Expected format 'file_path:variable_name'.",
|
|
52
|
+
category=UiPathErrorCategory.USER,
|
|
53
|
+
)
|
|
54
|
+
file, variable = file_path.split(":", 1)
|
|
55
|
+
return cls(name=name, file_path=file, variable_name=variable)
|
|
56
|
+
|
|
57
|
+
async def load(self) -> Agent:
|
|
58
|
+
"""
|
|
59
|
+
Load and return the agent.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
An instance of the loaded Agent.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
ValueError: If file path is outside current directory
|
|
66
|
+
FileNotFoundError: If file doesn't exist
|
|
67
|
+
ImportError: If module can't be loaded
|
|
68
|
+
TypeError: If loaded object isn't a valid workflow
|
|
69
|
+
"""
|
|
70
|
+
# Validate and normalize paths
|
|
71
|
+
cwd = os.path.abspath(os.getcwd())
|
|
72
|
+
abs_file_path = os.path.abspath(os.path.normpath(self.file_path))
|
|
73
|
+
|
|
74
|
+
if not abs_file_path.startswith(cwd):
|
|
75
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
76
|
+
code=UiPathOpenAIAgentsErrorCode.AGENT_VALUE_ERROR,
|
|
77
|
+
title="Invalid agent file path",
|
|
78
|
+
detail=f"Agent file path '{self.file_path}' must be within the current working directory.",
|
|
79
|
+
category=UiPathErrorCategory.USER,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if not os.path.exists(abs_file_path):
|
|
83
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
84
|
+
code=UiPathOpenAIAgentsErrorCode.AGENT_NOT_FOUND,
|
|
85
|
+
title="Agent file not found",
|
|
86
|
+
detail=f"Agent file '{self.file_path}' does not exist.",
|
|
87
|
+
category=UiPathErrorCategory.USER,
|
|
88
|
+
)
|
|
89
|
+
# Ensure the current directory and src/ is in sys.path
|
|
90
|
+
self._setup_python_path(cwd)
|
|
91
|
+
|
|
92
|
+
# Import the module and retrieve the agent instance
|
|
93
|
+
module = self._import_module(abs_file_path)
|
|
94
|
+
|
|
95
|
+
# Get the agent instance from the module
|
|
96
|
+
agent_object = getattr(module, self.variable_name, None)
|
|
97
|
+
if agent_object is None:
|
|
98
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
99
|
+
code=UiPathOpenAIAgentsErrorCode.AGENT_NOT_FOUND,
|
|
100
|
+
title="Agent variable not found",
|
|
101
|
+
detail=f"'{self.variable_name}' not found in module '{self.file_path}'.",
|
|
102
|
+
category=UiPathErrorCategory.USER,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Store the original loaded object for type inference
|
|
106
|
+
self._loaded_object = agent_object
|
|
107
|
+
|
|
108
|
+
agent = await self._resolve_agent(agent_object)
|
|
109
|
+
if not isinstance(agent, Agent):
|
|
110
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
111
|
+
code=UiPathOpenAIAgentsErrorCode.AGENT_TYPE_ERROR,
|
|
112
|
+
title="Invalid agent type",
|
|
113
|
+
detail=f"Expected Agent, got '{type(agent).__name__}'.",
|
|
114
|
+
category=UiPathErrorCategory.USER,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return agent
|
|
118
|
+
|
|
119
|
+
def _setup_python_path(self, cwd: str) -> None:
|
|
120
|
+
"""Add current directory and src/ to Python path if needed."""
|
|
121
|
+
if cwd not in sys.path:
|
|
122
|
+
sys.path.insert(0, cwd)
|
|
123
|
+
|
|
124
|
+
# Support src-layout projects (mimics editable install)
|
|
125
|
+
src_dir = os.path.join(cwd, "src")
|
|
126
|
+
if os.path.isdir(src_dir) and src_dir not in sys.path:
|
|
127
|
+
sys.path.insert(0, src_dir)
|
|
128
|
+
|
|
129
|
+
def _import_module(self, abs_file_path: str) -> Any:
|
|
130
|
+
"""Import a Python module from a file path."""
|
|
131
|
+
module_name = Path(abs_file_path).stem
|
|
132
|
+
spec = importlib.util.spec_from_file_location(module_name, abs_file_path)
|
|
133
|
+
|
|
134
|
+
if not spec or not spec.loader:
|
|
135
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
136
|
+
code=UiPathOpenAIAgentsErrorCode.AGENT_IMPORT_ERROR,
|
|
137
|
+
title="Failed to load agent module",
|
|
138
|
+
detail=f"Could not load module from: {abs_file_path}",
|
|
139
|
+
category=UiPathErrorCategory.USER,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
module = importlib.util.module_from_spec(spec)
|
|
144
|
+
sys.modules[module_name] = module
|
|
145
|
+
spec.loader.exec_module(module)
|
|
146
|
+
return module
|
|
147
|
+
except Exception as e:
|
|
148
|
+
raise UiPathOpenAIAgentsRuntimeError(
|
|
149
|
+
code=UiPathOpenAIAgentsErrorCode.AGENT_LOAD_ERROR,
|
|
150
|
+
title="Failed to execute agent module",
|
|
151
|
+
detail=f"Error loading module from {abs_file_path}: {str(e)}",
|
|
152
|
+
category=UiPathErrorCategory.USER,
|
|
153
|
+
) from e
|
|
154
|
+
|
|
155
|
+
async def _resolve_agent(self, agent_object: Any) -> Agent:
|
|
156
|
+
"""
|
|
157
|
+
Resolve an agent object that might be:
|
|
158
|
+
- A direct Agent
|
|
159
|
+
- A function that returns an Agent
|
|
160
|
+
- An async function that returns an Agent
|
|
161
|
+
- An async context manager that yields an Agent
|
|
162
|
+
"""
|
|
163
|
+
agent_instance = None
|
|
164
|
+
# Handle callable (sync or async)
|
|
165
|
+
if callable(agent_object):
|
|
166
|
+
if inspect.iscoroutinefunction(agent_object):
|
|
167
|
+
agent_instance = await agent_object()
|
|
168
|
+
else:
|
|
169
|
+
agent_instance = agent_object()
|
|
170
|
+
else:
|
|
171
|
+
agent_instance = agent_object
|
|
172
|
+
|
|
173
|
+
# Handle async context manager
|
|
174
|
+
if hasattr(agent_instance, "__aenter__") and callable(
|
|
175
|
+
agent_instance.__aenter__
|
|
176
|
+
):
|
|
177
|
+
self._context_manager = agent_instance
|
|
178
|
+
return await agent_instance.__aenter__()
|
|
179
|
+
|
|
180
|
+
return agent_instance
|
|
181
|
+
|
|
182
|
+
def get_loaded_object(self) -> Any:
|
|
183
|
+
"""
|
|
184
|
+
Get the original loaded object before agent resolution.
|
|
185
|
+
|
|
186
|
+
This is useful for extracting type annotations from wrapper functions.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
The original loaded object (could be an Agent, function, or callable)
|
|
190
|
+
"""
|
|
191
|
+
return self._loaded_object
|
|
192
|
+
|
|
193
|
+
async def cleanup(self) -> None:
|
|
194
|
+
"""Clean up resources (e.g., exit async context managers)."""
|
|
195
|
+
if self._context_manager:
|
|
196
|
+
try:
|
|
197
|
+
await self._context_manager.__aexit__(None, None, None)
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print(f"Error during agent cleanup: {e}")
|
|
200
|
+
finally:
|
|
201
|
+
self._context_manager = None
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class OpenAiAgentsConfig:
|
|
6
|
+
"""Simple loader for OpenAi Agents configuration."""
|
|
7
|
+
|
|
8
|
+
def __init__(self, config_path: str = "openai_agents.json"):
|
|
9
|
+
self.config_path = config_path
|
|
10
|
+
self._agents: dict[str, str] | None = None
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def exists(self) -> bool:
|
|
14
|
+
"""Check if the configuration file exists."""
|
|
15
|
+
return os.path.exists(self.config_path)
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def agents(self) -> dict[str, str]:
|
|
19
|
+
"""Get agents names -> path mapping from config.
|
|
20
|
+
|
|
21
|
+
Returns: A dictionary mapping agent names to their paths.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
if self._agents is None:
|
|
25
|
+
self._agents = self._load_agents()
|
|
26
|
+
return self._agents
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def entrypoint(self) -> list[str]:
|
|
30
|
+
"""Get the entrypoint for the agents runtime.
|
|
31
|
+
|
|
32
|
+
Returns: A list representing the entrypoint command.
|
|
33
|
+
"""
|
|
34
|
+
return list(self.agents.keys())
|
|
35
|
+
|
|
36
|
+
def _load_agents(self) -> dict[str, str]:
|
|
37
|
+
"""Load agents from the configuration file."""
|
|
38
|
+
if not self.exists:
|
|
39
|
+
raise FileNotFoundError(
|
|
40
|
+
f"OpenAi Agents configuration file not found at {self.config_path}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
with open(self.config_path, "r") as f:
|
|
45
|
+
config = json.load(f)
|
|
46
|
+
if "agents" not in config:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
"Missing 'agents' key in openai_agents.json configuration file."
|
|
49
|
+
)
|
|
50
|
+
agents = config["agents"]
|
|
51
|
+
if not isinstance(agents, dict):
|
|
52
|
+
raise ValueError("'agents' must be a dictionary.")
|
|
53
|
+
return agents
|
|
54
|
+
except json.JSONDecodeError as e:
|
|
55
|
+
raise ValueError(f"Invalid JSON in '{self.config_path}': {e}") from e
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Error handling for OpenAI Agents runtime."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
from uipath.runtime.errors import (
|
|
6
|
+
UiPathBaseRuntimeError,
|
|
7
|
+
UiPathErrorCategory,
|
|
8
|
+
UiPathErrorCode,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UiPathOpenAIAgentsErrorCode(Enum):
|
|
13
|
+
"""Error codes specific to OpenAI Agents runtime."""
|
|
14
|
+
|
|
15
|
+
AGENT_EXECUTION_FAILURE = "AGENT_EXECUTION_FAILURE"
|
|
16
|
+
TIMEOUT_ERROR = "TIMEOUT_ERROR"
|
|
17
|
+
SERIALIZE_OUTPUT_ERROR = "SERIALIZE_OUTPUT_ERROR"
|
|
18
|
+
|
|
19
|
+
CONFIG_MISSING = "CONFIG_MISSING"
|
|
20
|
+
CONFIG_INVALID = "CONFIG_INVALID"
|
|
21
|
+
|
|
22
|
+
AGENT_NOT_FOUND = "AGENT_NOT_FOUND"
|
|
23
|
+
AGENT_TYPE_ERROR = "AGENT_TYPE_ERROR"
|
|
24
|
+
AGENT_VALUE_ERROR = "AGENT_VALUE_ERROR"
|
|
25
|
+
AGENT_LOAD_ERROR = "AGENT_LOAD_ERROR"
|
|
26
|
+
AGENT_IMPORT_ERROR = "AGENT_IMPORT_ERROR"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class UiPathOpenAIAgentsRuntimeError(UiPathBaseRuntimeError):
|
|
30
|
+
"""Custom exception for OpenAI Agents runtime errors with structured error information."""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
code: UiPathOpenAIAgentsErrorCode | UiPathErrorCode,
|
|
35
|
+
title: str,
|
|
36
|
+
detail: str,
|
|
37
|
+
category: UiPathErrorCategory = UiPathErrorCategory.UNKNOWN,
|
|
38
|
+
status: int | None = None,
|
|
39
|
+
):
|
|
40
|
+
super().__init__(
|
|
41
|
+
code.value, title, detail, category, status, prefix="OpenAI-Agents"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
"UiPathOpenAIAgentsErrorCode",
|
|
47
|
+
"UiPathOpenAIAgentsRuntimeError",
|
|
48
|
+
]
|