select-ai 1.1.0rc1__py3-none-any.whl → 1.2.0rc1__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.
Potentially problematic release.
This version of select-ai might be problematic. Click here for more details.
- select_ai/agent/__init__.py +24 -0
- select_ai/agent/core.py +235 -0
- select_ai/agent/sql.py +80 -0
- select_ai/agent/task.py +247 -0
- select_ai/agent/team.py +280 -0
- select_ai/agent/tool.py +620 -0
- select_ai/async_profile.py +1 -1
- select_ai/base_profile.py +1 -1
- select_ai/errors.py +40 -0
- select_ai/profile.py +2 -2
- select_ai/sql.py +10 -4
- select_ai/vector_index.py +84 -36
- select_ai/version.py +1 -1
- {select_ai-1.1.0rc1.dist-info → select_ai-1.2.0rc1.dist-info}/METADATA +1 -1
- select_ai-1.2.0rc1.dist-info/RECORD +28 -0
- select_ai-1.1.0rc1.dist-info/RECORD +0 -22
- {select_ai-1.1.0rc1.dist-info → select_ai-1.2.0rc1.dist-info}/WHEEL +0 -0
- {select_ai-1.1.0rc1.dist-info → select_ai-1.2.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
- {select_ai-1.1.0rc1.dist-info → select_ai-1.2.0rc1.dist-info}/top_level.txt +0 -0
select_ai/agent/team.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2025, Oracle and/or its affiliates.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Universal Permissive License v 1.0 as shown at
|
|
5
|
+
# http://oss.oracle.com/licenses/upl.
|
|
6
|
+
# -----------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from abc import ABC
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import (
|
|
12
|
+
Any,
|
|
13
|
+
AsyncGenerator,
|
|
14
|
+
Iterator,
|
|
15
|
+
List,
|
|
16
|
+
Mapping,
|
|
17
|
+
Optional,
|
|
18
|
+
Union,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
import oracledb
|
|
22
|
+
|
|
23
|
+
from select_ai import BaseProfile
|
|
24
|
+
from select_ai._abc import SelectAIDataClass
|
|
25
|
+
from select_ai._enums import StrEnum
|
|
26
|
+
from select_ai.agent.sql import (
|
|
27
|
+
GET_USER_AI_AGENT_TEAM,
|
|
28
|
+
GET_USER_AI_AGENT_TEAM_ATTRIBUTES,
|
|
29
|
+
LIST_USER_AI_AGENT_TEAMS,
|
|
30
|
+
)
|
|
31
|
+
from select_ai.async_profile import AsyncProfile
|
|
32
|
+
from select_ai.db import async_cursor, cursor
|
|
33
|
+
from select_ai.errors import AgentTeamNotFoundError
|
|
34
|
+
from select_ai.profile import Profile
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class TeamAttributes(SelectAIDataClass):
|
|
39
|
+
"""
|
|
40
|
+
AI agent team attributes
|
|
41
|
+
|
|
42
|
+
:param List[Mapping] agents: A List of Python dictionaries, each defining
|
|
43
|
+
the agent and the task name. [{"name": "<agent_name>",
|
|
44
|
+
"task": "<task_name>"}]
|
|
45
|
+
|
|
46
|
+
:param str process: Execution order of tasks. Currently only "sequential"
|
|
47
|
+
is supported.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
agents: List[Mapping]
|
|
52
|
+
process: str = "sequential"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class BaseTeam(ABC):
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
team_name: str,
|
|
60
|
+
attributes: TeamAttributes,
|
|
61
|
+
description: Optional[str] = None,
|
|
62
|
+
):
|
|
63
|
+
if not isinstance(attributes, TeamAttributes):
|
|
64
|
+
raise TypeError(
|
|
65
|
+
f"attributes must be an object of type "
|
|
66
|
+
f"select_ai.agent.TeamAttributes instance"
|
|
67
|
+
)
|
|
68
|
+
self.team_name = team_name
|
|
69
|
+
self.description = description
|
|
70
|
+
self.attributes = attributes
|
|
71
|
+
|
|
72
|
+
def __repr__(self):
|
|
73
|
+
return (
|
|
74
|
+
f"{self.__class__.__name__}("
|
|
75
|
+
f"team_name={self.team_name}, "
|
|
76
|
+
f"attributes={self.attributes}, description={self.description})"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Team(BaseTeam):
|
|
81
|
+
"""
|
|
82
|
+
A Team of AI agents work together to accomplish tasks
|
|
83
|
+
select_ai.agent.Team class lets you create, delete, enable, disable and
|
|
84
|
+
list AI Tasks.
|
|
85
|
+
|
|
86
|
+
:param str team_name: The name of the AI team
|
|
87
|
+
:param str description: Optional description of the AI team
|
|
88
|
+
:param select_ai.agent.TeamAttributes attributes: AI team attributes
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def _get_attributes(team_name: str) -> TeamAttributes:
|
|
94
|
+
with cursor() as cr:
|
|
95
|
+
cr.execute(
|
|
96
|
+
GET_USER_AI_AGENT_TEAM_ATTRIBUTES, team_name=team_name.upper()
|
|
97
|
+
)
|
|
98
|
+
attributes = cr.fetchall()
|
|
99
|
+
if attributes:
|
|
100
|
+
post_processed_attributes = {}
|
|
101
|
+
for k, v in attributes:
|
|
102
|
+
if isinstance(v, oracledb.LOB):
|
|
103
|
+
post_processed_attributes[k] = v.read()
|
|
104
|
+
else:
|
|
105
|
+
post_processed_attributes[k] = v
|
|
106
|
+
return TeamAttributes(**post_processed_attributes)
|
|
107
|
+
else:
|
|
108
|
+
raise AgentTeamNotFoundError(team_name=team_name)
|
|
109
|
+
|
|
110
|
+
def create(
|
|
111
|
+
self, enabled: Optional[bool] = True, replace: Optional[bool] = False
|
|
112
|
+
):
|
|
113
|
+
"""
|
|
114
|
+
Create a team of AI agents that work together to accomplish tasks.
|
|
115
|
+
|
|
116
|
+
:param bool enabled: Whether the AI agent team should be enabled.
|
|
117
|
+
Default value is True.
|
|
118
|
+
|
|
119
|
+
:param bool replace: Whether the AI agent team should be replaced.
|
|
120
|
+
Default value is False.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
if self.team_name is None:
|
|
124
|
+
raise AttributeError("Team must have a name")
|
|
125
|
+
if self.attributes is None:
|
|
126
|
+
raise AttributeError("Team must have attributes")
|
|
127
|
+
|
|
128
|
+
parameters = {
|
|
129
|
+
"team_name": self.team_name,
|
|
130
|
+
"attributes": self.attributes.json(),
|
|
131
|
+
}
|
|
132
|
+
if self.description:
|
|
133
|
+
parameters["description"] = self.description
|
|
134
|
+
|
|
135
|
+
if not enabled:
|
|
136
|
+
parameters["status"] = "disabled"
|
|
137
|
+
|
|
138
|
+
with cursor() as cr:
|
|
139
|
+
try:
|
|
140
|
+
cr.callproc(
|
|
141
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TEAM",
|
|
142
|
+
keyword_parameters=parameters,
|
|
143
|
+
)
|
|
144
|
+
except oracledb.Error as err:
|
|
145
|
+
(err_obj,) = err.args
|
|
146
|
+
if err_obj.code in (20053, 20052) and replace:
|
|
147
|
+
self.delete(force=True)
|
|
148
|
+
cr.callproc(
|
|
149
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TEAM",
|
|
150
|
+
keyword_parameters=parameters,
|
|
151
|
+
)
|
|
152
|
+
else:
|
|
153
|
+
raise
|
|
154
|
+
|
|
155
|
+
def delete(self, force: Optional[bool] = False):
|
|
156
|
+
"""
|
|
157
|
+
Delete an AI agent team from the database
|
|
158
|
+
|
|
159
|
+
:param bool force: Force the deletion. Default value is False.
|
|
160
|
+
"""
|
|
161
|
+
with cursor() as cr:
|
|
162
|
+
cr.callproc(
|
|
163
|
+
"DBMS_CLOUD_AI_AGENT.DROP_TEAM",
|
|
164
|
+
keyword_parameters={
|
|
165
|
+
"team_name": self.team_name,
|
|
166
|
+
"force": force,
|
|
167
|
+
},
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def disable(self):
|
|
171
|
+
"""
|
|
172
|
+
Disable the AI agent team
|
|
173
|
+
"""
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
def enable(self):
|
|
177
|
+
"""
|
|
178
|
+
Enable the AI agent team
|
|
179
|
+
"""
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def fetch(cls) -> "Team":
|
|
184
|
+
"""
|
|
185
|
+
Fetch AI Team attributes from the Database and build a proxy object in
|
|
186
|
+
the Python layer
|
|
187
|
+
|
|
188
|
+
:param str team_name: The name of the AI Team
|
|
189
|
+
|
|
190
|
+
:return: select_ai.agent.Team
|
|
191
|
+
|
|
192
|
+
:raises select_ai.errors.AgentTeamNotFoundError:
|
|
193
|
+
If the AI Team is not found
|
|
194
|
+
"""
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def list(cls, team_name_pattern: Optional[str] = ".*") -> Iterator["Team"]:
|
|
199
|
+
"""
|
|
200
|
+
List AI Agent Teams
|
|
201
|
+
|
|
202
|
+
:param str team_name_pattern: Regular expressions can be used
|
|
203
|
+
to specify a pattern. Function REGEXP_LIKE is used to perform the
|
|
204
|
+
match. Default value is ".*" i.e. match all teams.
|
|
205
|
+
|
|
206
|
+
:return: Iterator[Team]
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
with cursor() as cr:
|
|
210
|
+
cr.execute(
|
|
211
|
+
LIST_USER_AI_AGENT_TEAMS,
|
|
212
|
+
team_name_pattern=team_name_pattern,
|
|
213
|
+
)
|
|
214
|
+
for row in cr.fetchall():
|
|
215
|
+
team_name = row[0]
|
|
216
|
+
if row[1]:
|
|
217
|
+
description = row[1].read() # Oracle.LOB
|
|
218
|
+
else:
|
|
219
|
+
description = None
|
|
220
|
+
attributes = cls._get_attributes(team_name=team_name)
|
|
221
|
+
yield cls(
|
|
222
|
+
team_name=team_name,
|
|
223
|
+
description=description,
|
|
224
|
+
attributes=attributes,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
def run(self, prompt: str = None, params: Mapping = None):
|
|
228
|
+
"""
|
|
229
|
+
Start a new AI agent team or resume a paused one that is waiting
|
|
230
|
+
for human input. If you provide an existing process ID and the
|
|
231
|
+
associated team process is in the WAITING_FOR_HUMAN state, the
|
|
232
|
+
function resumes the workflow using the input you provide as
|
|
233
|
+
the human response
|
|
234
|
+
|
|
235
|
+
:param str prompt: Optional prompt for the user. If the task is
|
|
236
|
+
in the RUNNING state, the input acts as a placeholder for the
|
|
237
|
+
{query} in the task instruction. If the task is in the
|
|
238
|
+
WAITING_FOR_HUMAN state, the input serves as the human response.
|
|
239
|
+
|
|
240
|
+
:param Mapping[str, str] params: Optional parameters for the task.
|
|
241
|
+
Currently, the following parameters are supported:
|
|
242
|
+
|
|
243
|
+
- conversation_id: Identifies the conversation session associated
|
|
244
|
+
with the agent team
|
|
245
|
+
|
|
246
|
+
- variables: key-value pairs that provide additional input to the agent team.
|
|
247
|
+
|
|
248
|
+
"""
|
|
249
|
+
parameters = {
|
|
250
|
+
"team_name": self.team_name,
|
|
251
|
+
}
|
|
252
|
+
if prompt:
|
|
253
|
+
parameters["user_prompt"] = prompt
|
|
254
|
+
if params:
|
|
255
|
+
parameters["params"] = json.dumps(params)
|
|
256
|
+
|
|
257
|
+
with cursor() as cr:
|
|
258
|
+
data = cr.callfunc(
|
|
259
|
+
"DBMS_CLOUD_AI_AGENT.RUN_TEAM",
|
|
260
|
+
oracledb.DB_TYPE_CLOB,
|
|
261
|
+
keyword_parameters=parameters,
|
|
262
|
+
)
|
|
263
|
+
if data is not None:
|
|
264
|
+
result = data.read()
|
|
265
|
+
else:
|
|
266
|
+
result = None
|
|
267
|
+
return result
|
|
268
|
+
|
|
269
|
+
def set_attributes(self, attributes: TeamAttributes) -> None:
|
|
270
|
+
"""
|
|
271
|
+
Set the attributes of the AI Agent team
|
|
272
|
+
"""
|
|
273
|
+
pass
|
|
274
|
+
|
|
275
|
+
def set_attribute(self, attribute_name: str, attribute_value: Any) -> None:
|
|
276
|
+
"""
|
|
277
|
+
Set the attribute of the AI Agent team specified by
|
|
278
|
+
`attribute_name` and `attribute_value`.
|
|
279
|
+
"""
|
|
280
|
+
pass
|