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.
@@ -0,0 +1,357 @@
1
+ """Storage implementation for OpenAI Agents runtime.
2
+
3
+ Provides persistence for agent sessions, resume triggers, and key-value storage.
4
+ Based on the UiPath LlamaIndex storage implementation but adapted for OpenAI Agents.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ from typing import Any, cast
12
+
13
+ from pydantic import BaseModel
14
+ from uipath.core.errors import ErrorCategory, UiPathFaultedTriggerError
15
+ from uipath.runtime import (
16
+ UiPathApiTrigger,
17
+ UiPathResumeTrigger,
18
+ UiPathResumeTriggerName,
19
+ UiPathResumeTriggerType,
20
+ )
21
+
22
+ from ._sqlite import AsyncSqlite
23
+
24
+
25
+ class SqliteAgentStorage:
26
+ """SQLite database storage for agent sessions, resume triggers, and state."""
27
+
28
+ def __init__(self, storage_path: str):
29
+ """
30
+ Initialize SQLite storage.
31
+
32
+ Args:
33
+ storage_path: Path to the SQLite database file
34
+ """
35
+ self.storage_path = storage_path
36
+ self._db: AsyncSqlite | None = None
37
+
38
+ async def _get_db(self) -> AsyncSqlite:
39
+ """Get or create database connection."""
40
+ if self._db is None:
41
+ self._db = AsyncSqlite(self.storage_path, timeout=30.0)
42
+ await self._db.connect()
43
+ return self._db
44
+
45
+ async def dispose(self) -> None:
46
+ """Dispose of the storage and close database connection."""
47
+ if self._db:
48
+ await self._db.close()
49
+ self._db = None
50
+
51
+ async def __aenter__(self) -> SqliteAgentStorage:
52
+ """Async context manager entry."""
53
+ await self.setup()
54
+ return self
55
+
56
+ async def __aexit__(self, *args) -> None:
57
+ """Async context manager exit."""
58
+ await self.dispose()
59
+
60
+ async def setup(self) -> None:
61
+ """Ensure storage directory and database tables exist."""
62
+ dir_name = os.path.dirname(self.storage_path)
63
+ if dir_name:
64
+ os.makedirs(dir_name, exist_ok=True)
65
+
66
+ try:
67
+ db = await self._get_db()
68
+
69
+ # Table for agent state/metadata
70
+ await db.execute("""
71
+ CREATE TABLE IF NOT EXISTS agent_state (
72
+ runtime_id TEXT PRIMARY KEY,
73
+ state_data TEXT NOT NULL,
74
+ timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
75
+ )
76
+ """)
77
+
78
+ # Table for resume triggers
79
+ await db.execute("""
80
+ CREATE TABLE IF NOT EXISTS resume_triggers (
81
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
82
+ runtime_id TEXT NOT NULL,
83
+ interrupt_id TEXT NOT NULL,
84
+ trigger_data TEXT NOT NULL,
85
+ timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
86
+ )
87
+ """)
88
+
89
+ await db.execute(
90
+ """
91
+ CREATE INDEX IF NOT EXISTS idx_resume_triggers_runtime_id
92
+ ON resume_triggers(runtime_id)
93
+ """
94
+ )
95
+
96
+ # Table for key-value storage
97
+ await db.execute(
98
+ """
99
+ CREATE TABLE IF NOT EXISTS runtime_kv (
100
+ runtime_id TEXT NOT NULL,
101
+ namespace TEXT NOT NULL,
102
+ key TEXT NOT NULL,
103
+ value TEXT,
104
+ timestamp DATETIME DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now', 'utc')),
105
+ PRIMARY KEY (runtime_id, namespace, key)
106
+ )
107
+ """
108
+ )
109
+
110
+ await db.commit()
111
+ except Exception as exc:
112
+ msg = f"Failed to initialize SQLite storage at {self.storage_path!r}: {exc}"
113
+ raise UiPathFaultedTriggerError(ErrorCategory.SYSTEM, msg) from exc
114
+
115
+ async def save_triggers(
116
+ self, runtime_id: str, triggers: list[UiPathResumeTrigger]
117
+ ) -> None:
118
+ """Save resume triggers to SQLite database."""
119
+ try:
120
+ db = await self._get_db()
121
+
122
+ # Delete all existing triggers for this runtime_id
123
+ await db.execute(
124
+ """
125
+ DELETE FROM resume_triggers
126
+ WHERE runtime_id = ?
127
+ """,
128
+ (runtime_id,),
129
+ )
130
+
131
+ # Insert new triggers
132
+ for trigger in triggers:
133
+ trigger_dict = self._serialize_trigger(trigger)
134
+ trigger_json = json.dumps(trigger_dict)
135
+ await db.execute(
136
+ "INSERT INTO resume_triggers (runtime_id, interrupt_id, trigger_data) VALUES (?, ?, ?)",
137
+ (runtime_id, trigger.interrupt_id, trigger_json),
138
+ )
139
+
140
+ await db.commit()
141
+ except Exception as exc:
142
+ msg = f"Failed to save resume triggers to database {self.storage_path!r}: {exc}"
143
+ raise UiPathFaultedTriggerError(ErrorCategory.SYSTEM, msg) from exc
144
+
145
+ async def get_triggers(self, runtime_id: str) -> list[UiPathResumeTrigger] | None:
146
+ """Get resume triggers from SQLite database."""
147
+ try:
148
+ db = await self._get_db()
149
+ rows = await db.fetchall(
150
+ "SELECT trigger_data FROM resume_triggers WHERE runtime_id = ? ORDER BY id ASC",
151
+ (runtime_id,),
152
+ )
153
+ except Exception as exc:
154
+ msg = f"Failed to retrieve resume triggers from database {self.storage_path!r}: {exc}"
155
+ raise UiPathFaultedTriggerError(ErrorCategory.SYSTEM, msg) from exc
156
+
157
+ if not rows:
158
+ return None
159
+
160
+ triggers = []
161
+ for row in rows:
162
+ trigger_dict = json.loads(row[0])
163
+ triggers.append(self._deserialize_trigger(trigger_dict))
164
+ return triggers
165
+
166
+ async def delete_trigger(
167
+ self, runtime_id: str, trigger: UiPathResumeTrigger
168
+ ) -> None:
169
+ """Delete resume trigger from storage."""
170
+ try:
171
+ db = await self._get_db()
172
+ await db.execute(
173
+ """
174
+ DELETE FROM resume_triggers
175
+ WHERE runtime_id = ? AND interrupt_id = ?
176
+ """,
177
+ (runtime_id, trigger.interrupt_id),
178
+ )
179
+ await db.commit()
180
+ except Exception as exc:
181
+ msg = f"Failed to delete resume trigger from database {self.storage_path!r}: {exc}"
182
+ raise UiPathFaultedTriggerError(ErrorCategory.SYSTEM, msg) from exc
183
+
184
+ async def save_state(self, runtime_id: str, state_data: dict[str, Any]) -> None:
185
+ """
186
+ Save agent state to SQLite database.
187
+
188
+ Args:
189
+ runtime_id: Unique identifier for the runtime instance
190
+ state_data: Serialized agent state dictionary
191
+ """
192
+ state_json = json.dumps(state_data)
193
+
194
+ try:
195
+ db = await self._get_db()
196
+ await db.execute(
197
+ """
198
+ INSERT INTO agent_state (runtime_id, state_data)
199
+ VALUES (?, ?)
200
+ ON CONFLICT(runtime_id) DO UPDATE SET
201
+ state_data = excluded.state_data,
202
+ timestamp = CURRENT_TIMESTAMP
203
+ """,
204
+ (runtime_id, state_json),
205
+ )
206
+ await db.commit()
207
+ except Exception as exc:
208
+ msg = f"Failed to save agent state to database {self.storage_path!r}: {exc}"
209
+ raise UiPathFaultedTriggerError(ErrorCategory.SYSTEM, msg) from exc
210
+
211
+ async def load_state(self, runtime_id: str) -> dict[str, Any] | None:
212
+ """
213
+ Load agent state from SQLite database.
214
+
215
+ Args:
216
+ runtime_id: Unique identifier for the runtime instance
217
+
218
+ Returns:
219
+ Serialized agent state dictionary or None if not found
220
+ """
221
+ try:
222
+ db = await self._get_db()
223
+ row = await db.fetchone(
224
+ "SELECT state_data FROM agent_state WHERE runtime_id = ?",
225
+ (runtime_id,),
226
+ )
227
+ except Exception as exc:
228
+ msg = (
229
+ f"Failed to load agent state from database {self.storage_path!r}: {exc}"
230
+ )
231
+ raise UiPathFaultedTriggerError(ErrorCategory.SYSTEM, msg) from exc
232
+
233
+ if not row:
234
+ return None
235
+
236
+ return json.loads(row[0])
237
+
238
+ async def set_value(
239
+ self,
240
+ runtime_id: str,
241
+ namespace: str,
242
+ key: str,
243
+ value: Any,
244
+ ) -> None:
245
+ """Save arbitrary key-value pair to database."""
246
+ if not (
247
+ isinstance(value, str)
248
+ or isinstance(value, dict)
249
+ or isinstance(value, BaseModel)
250
+ or value is None
251
+ ):
252
+ raise TypeError("Value must be str, dict, BaseModel or None.")
253
+
254
+ value_text = self._dump_value(value)
255
+
256
+ db = await self._get_db()
257
+ await db.execute(
258
+ """
259
+ INSERT INTO runtime_kv (runtime_id, namespace, key, value)
260
+ VALUES (?, ?, ?, ?)
261
+ ON CONFLICT(runtime_id, namespace, key)
262
+ DO UPDATE SET
263
+ value = excluded.value,
264
+ timestamp = (strftime('%Y-%m-%d %H:%M:%S', 'now', 'utc'))
265
+ """,
266
+ (runtime_id, namespace, key, value_text),
267
+ )
268
+ await db.commit()
269
+
270
+ async def get_value(self, runtime_id: str, namespace: str, key: str) -> Any:
271
+ """Get arbitrary key-value pair from database (scoped by runtime_id + namespace)."""
272
+ db = await self._get_db()
273
+ row = await db.fetchone(
274
+ """
275
+ SELECT value
276
+ FROM runtime_kv
277
+ WHERE runtime_id = ? AND namespace = ? AND key = ?
278
+ LIMIT 1
279
+ """,
280
+ (runtime_id, namespace, key),
281
+ )
282
+
283
+ if not row:
284
+ return None
285
+
286
+ return self._load_value(cast(str | None, row[0]))
287
+
288
+ def _serialize_trigger(self, trigger: UiPathResumeTrigger) -> dict[str, Any]:
289
+ """Serialize a resume trigger to a dictionary."""
290
+ trigger_key = (
291
+ trigger.api_resume.inbox_id if trigger.api_resume else trigger.item_key
292
+ )
293
+ payload = (
294
+ json.dumps(trigger.payload)
295
+ if isinstance(trigger.payload, dict)
296
+ else str(trigger.payload)
297
+ if trigger.payload
298
+ else None
299
+ )
300
+
301
+ return {
302
+ "type": trigger.trigger_type.value,
303
+ "key": trigger_key,
304
+ "name": trigger.trigger_name.value,
305
+ "payload": payload,
306
+ "interrupt_id": trigger.interrupt_id,
307
+ "folder_path": trigger.folder_path,
308
+ "folder_key": trigger.folder_key,
309
+ }
310
+
311
+ def _deserialize_trigger(self, trigger_data: dict[str, Any]) -> UiPathResumeTrigger:
312
+ """Deserialize a resume trigger from a dictionary."""
313
+ trigger_type = trigger_data["type"]
314
+ key = trigger_data["key"]
315
+ name = trigger_data["name"]
316
+ folder_path = trigger_data.get("folder_path")
317
+ folder_key = trigger_data.get("folder_key")
318
+ payload = trigger_data.get("payload")
319
+ interrupt_id = trigger_data.get("interrupt_id")
320
+
321
+ resume_trigger = UiPathResumeTrigger(
322
+ trigger_type=UiPathResumeTriggerType(trigger_type),
323
+ trigger_name=UiPathResumeTriggerName(name),
324
+ item_key=key,
325
+ folder_path=folder_path,
326
+ folder_key=folder_key,
327
+ payload=payload,
328
+ interrupt_id=interrupt_id,
329
+ )
330
+
331
+ if resume_trigger.trigger_type == UiPathResumeTriggerType.API:
332
+ resume_trigger.api_resume = UiPathApiTrigger(
333
+ inbox_id=resume_trigger.item_key, request=resume_trigger.payload
334
+ )
335
+
336
+ return resume_trigger
337
+
338
+ def _dump_value(self, value: str | dict[str, Any] | BaseModel | None) -> str | None:
339
+ if value is None:
340
+ return None
341
+ if isinstance(value, BaseModel):
342
+ return "j:" + json.dumps(value.model_dump())
343
+ if isinstance(value, dict):
344
+ return "j:" + json.dumps(value)
345
+ return "s:" + value
346
+
347
+ def _load_value(self, raw: str | None) -> Any:
348
+ if raw is None:
349
+ return None
350
+ if raw.startswith("s:"):
351
+ return raw[2:]
352
+ if raw.startswith("j:"):
353
+ return json.loads(raw[2:])
354
+ return raw
355
+
356
+
357
+ __all__ = ["SqliteAgentStorage"]
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: uipath-openai-agents
3
+ Version: 0.0.1
4
+ Summary: UiPath OpenAI Agents SDK
5
+ Project-URL: Homepage, https://uipath.com
6
+ Project-URL: Repository, https://github.com/UiPath/uipath-llamaindex-python
7
+ Maintainer-email: Marius Cosareanu <marius.cosareanu@uipath.com>, Cristian Pufu <cristian.pufu@uipath.com>
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Software Development :: Build Tools
13
+ Requires-Python: >=3.11
14
+ Requires-Dist: aiosqlite>=0.20.0
15
+ Requires-Dist: openai-agents>=0.6.5
16
+ Requires-Dist: openai>=1.0.0
17
+ Requires-Dist: openinference-instrumentation-openai-agents>=1.4.0
18
+ Requires-Dist: uipath-runtime<0.6.0,>=0.5.0
19
+ Requires-Dist: uipath<2.6.0,>=2.5.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ # UiPath OpenAI Agents SDK
23
+
24
+ Build intelligent AI agents with OpenAI's Agents framework and UiPath.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install uipath-openai-agents
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ See the [main repository documentation](../../docs/) for getting started guides and examples.
35
+
36
+ ## Features
37
+
38
+ - **OpenAI Agents Integration**: Build agents using OpenAI's native Agents framework
39
+ - **Agent Orchestration**: Multi-agent coordination and communication
40
+ - **State Management**: Persistent agent state with SQLite sessions
41
+ - **UiPath Integration**: Seamless integration with UiPath runtime and tooling
42
+
43
+ ## Status
44
+
45
+ ⚠️ **Early Development**: This package is in early development (v0.1.0). APIs may change as the OpenAI Agents framework evolves.
46
+
47
+ ## Documentation
48
+
49
+ Full documentation is available in the [main repository](https://github.com/UiPath/uipath-llamaindex-python).
50
+
51
+ ## License
52
+
53
+ See [LICENSE](../../LICENSE) in the repository root.
@@ -0,0 +1,26 @@
1
+ uipath_openai_agents/__init__.py,sha256=KOUmJ726xaYXE6QZ7uD_yeaZQym5VZpPmP4Yxy35I_0,190
2
+ uipath_openai_agents/middlewares.py,sha256=TMZAwdBh4gUMfgUZPhhxVDWf3pl-GBaeLlmCtipa-WM,299
3
+ uipath_openai_agents/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ uipath_openai_agents/_cli/__init__.py,sha256=juqd9PbXs4yg45zMJ7BHAOPQjb7sgEbWE9InBtGZhfo,24
5
+ uipath_openai_agents/_cli/cli_new.py,sha256=ZY2-DdlKiGEVh8GmDncGpxH-mzLsB_x9BdUudcjS7Yk,2967
6
+ uipath_openai_agents/_cli/_templates/AGENTS.md.template,sha256=5a40W58c3gH349sxuCOOmi_5UG5fLDrJWkWpdLQBAIA,1292
7
+ uipath_openai_agents/_cli/_templates/main.py.template,sha256=BwOcvHA-RAWUB49NtXA7bLhf3Kqzzhd36fjTjz-lZRg,681
8
+ uipath_openai_agents/_cli/_templates/openai_agents.json.template,sha256=MH1nK-wZ-GMfFmCW5-pD8zUNFaEmlQUfZKiNXDqUgGM,51
9
+ uipath_openai_agents/chat/__init__.py,sha256=gIb5QKN-N83_wfvkuhy5rHgvNztLeJv4VMQVSdGXwMk,103
10
+ uipath_openai_agents/chat/openai.py,sha256=KjbDKS_tUKYjuvjUYbouSsoJsOmzbtdHUzuDarDpFYM,8640
11
+ uipath_openai_agents/chat/supported_models.py,sha256=ieaUKL1Xl_e7XeIr6-mw2Wi3z9uwi-vXW0QKb8sChmc,2874
12
+ uipath_openai_agents/runtime/__init__.py,sha256=R08yyN_4dRX1ZUFhz3liqFcbT6wpCEeCBzXk9Ouxq0o,1102
13
+ uipath_openai_agents/runtime/_serialize.py,sha256=2PZZtDXjCONK78BeoK_MPAPmGYvBFG2VmkjHMQ5o-Bg,1462
14
+ uipath_openai_agents/runtime/_sqlite.py,sha256=SroeZowJPQw5j54lfxv1_J4k56S48YA0U9MeubD7IBw,5380
15
+ uipath_openai_agents/runtime/_telemetry.py,sha256=s_Ggb9rlwR-MLi-ssIayYLdGwkSRnRq9qFzrS5TzMwM,714
16
+ uipath_openai_agents/runtime/agent.py,sha256=ieDvHbkxJu9clExOnbE1OqQBUB-Er9fZN_siddr2hbU,7559
17
+ uipath_openai_agents/runtime/config.py,sha256=gtDCIMB1fcAry9Tj_xJSR1xVaARMNmrr5HmwSn4Nh-w,1808
18
+ uipath_openai_agents/runtime/errors.py,sha256=AgUmbikoM53O02CktbZAKVjVmK1ZCl9-EG0gWaYtrn0,1333
19
+ uipath_openai_agents/runtime/factory.py,sha256=WPhnYzjnVMhVP9SekZ6_Au7kzy4rMmZN-GMjS--XEwc,12354
20
+ uipath_openai_agents/runtime/runtime.py,sha256=GLnFeIrejIgke8mLg1wJOFc9pTedCAJxiRLwFyUYXVw,18605
21
+ uipath_openai_agents/runtime/schema.py,sha256=iM5mHgdlnFrW-jRreL-EYoOsG-qn0pmw364hml2m2gs,15565
22
+ uipath_openai_agents/runtime/storage.py,sha256=AxzhdNY4nMF3CSZkT2SJRxqvzxs37fHPbZlZmSwPka0,12197
23
+ uipath_openai_agents-0.0.1.dist-info/METADATA,sha256=gTqtBJSJfZjSBP9zmRQ2DH_aOOO2oAM22rGd0SeIos4,1815
24
+ uipath_openai_agents-0.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ uipath_openai_agents-0.0.1.dist-info/entry_points.txt,sha256=2tY1wvop4ulDwWMUXFZzOREIKyIf5cFYsefLWNA2-9w,183
26
+ uipath_openai_agents-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,5 @@
1
+ [uipath.middlewares]
2
+ register = uipath_openai_agents.middlewares:register_middleware
3
+
4
+ [uipath.runtime.factories]
5
+ openai-agents = uipath_openai_agents.runtime:register_runtime_factory