select-ai 1.1.0__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/errors.py +40 -0
- select_ai/sql.py +10 -4
- select_ai/vector_index.py +12 -0
- select_ai/version.py +1 -1
- {select_ai-1.1.0.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.0.dist-info/RECORD +0 -22
- {select_ai-1.1.0.dist-info → select_ai-1.2.0rc1.dist-info}/WHEEL +0 -0
- {select_ai-1.1.0.dist-info → select_ai-1.2.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
- {select_ai-1.1.0.dist-info → select_ai-1.2.0rc1.dist-info}/top_level.txt +0 -0
select_ai/agent/tool.py
ADDED
|
@@ -0,0 +1,620 @@
|
|
|
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 AsyncGenerator, Iterator, List, Mapping, Optional, Union
|
|
12
|
+
|
|
13
|
+
import oracledb
|
|
14
|
+
|
|
15
|
+
from select_ai import BaseProfile
|
|
16
|
+
from select_ai._abc import SelectAIDataClass
|
|
17
|
+
from select_ai._enums import StrEnum
|
|
18
|
+
from select_ai.agent.sql import (
|
|
19
|
+
GET_USER_AI_AGENT_TOOL_ATTRIBUTES,
|
|
20
|
+
LIST_USER_AI_AGENT_TOOLS,
|
|
21
|
+
)
|
|
22
|
+
from select_ai.async_profile import AsyncProfile
|
|
23
|
+
from select_ai.db import async_cursor, cursor
|
|
24
|
+
from select_ai.errors import AgentToolNotFoundError
|
|
25
|
+
from select_ai.profile import Profile
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NotificationType(StrEnum):
|
|
29
|
+
"""
|
|
30
|
+
Notification Types
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
SLACK = "slack"
|
|
34
|
+
EMAIL = "email"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ToolType(StrEnum):
|
|
38
|
+
"""
|
|
39
|
+
Built-in Tool Types
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
EMAIL = "EMAIL"
|
|
43
|
+
HUMAN = "HUMAN"
|
|
44
|
+
HTTP = "HTTP"
|
|
45
|
+
RAG = "RAG"
|
|
46
|
+
SQL = "SQL"
|
|
47
|
+
SLACK = "SLACK"
|
|
48
|
+
WEBSEARCH = "WEBSEARCH"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class ToolParams(SelectAIDataClass):
|
|
53
|
+
"""
|
|
54
|
+
Parameters to register a built-in Tool
|
|
55
|
+
|
|
56
|
+
:param str credential_name: Used by SLACK, EMAIL and WEBSEARCH tools
|
|
57
|
+
|
|
58
|
+
:param str endpoint: Send HTTP requests to this endpoint
|
|
59
|
+
|
|
60
|
+
:param select_ai.agent.NotificationType: Either SLACK or EMAIL
|
|
61
|
+
|
|
62
|
+
:param str profile_name: Name of AI profile to use
|
|
63
|
+
|
|
64
|
+
:param str recipient: Recipient used for EMAIL notification
|
|
65
|
+
|
|
66
|
+
:param str sender: Sender used for EMAIL notification
|
|
67
|
+
|
|
68
|
+
:param str slack_channel: Slack channel to use
|
|
69
|
+
|
|
70
|
+
:param str smtp_host: SMTP host to use for EMAIL notification
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
_REQUIRED_FIELDS: Optional[List] = None
|
|
75
|
+
|
|
76
|
+
credential_name: Optional[str] = None
|
|
77
|
+
endpoint: Optional[str] = None
|
|
78
|
+
notification_type: Optional[NotificationType] = None
|
|
79
|
+
profile_name: Optional[str] = None
|
|
80
|
+
recipient: Optional[str] = None
|
|
81
|
+
sender: Optional[str] = None
|
|
82
|
+
slack_channel: Optional[str] = None
|
|
83
|
+
smtp_host: Optional[str] = None
|
|
84
|
+
|
|
85
|
+
def __post_init__(self):
|
|
86
|
+
super().__post_init__()
|
|
87
|
+
if self._REQUIRED_FIELDS:
|
|
88
|
+
for field in self._REQUIRED_FIELDS:
|
|
89
|
+
if getattr(self, field) is None:
|
|
90
|
+
raise AttributeError(
|
|
91
|
+
"Required field '{}' not found.".format(field)
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def create(cls, *, tool_type: Optional[ToolType] = None, **kwargs):
|
|
96
|
+
tool_params_cls = ToolTypeParams.get(tool_type, ToolParams)
|
|
97
|
+
return tool_params_cls(**kwargs)
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def keys(cls):
|
|
101
|
+
return {
|
|
102
|
+
"credential_name",
|
|
103
|
+
"endpoint",
|
|
104
|
+
"notification_type",
|
|
105
|
+
"profile_name",
|
|
106
|
+
"recipient",
|
|
107
|
+
"sender",
|
|
108
|
+
"slack_channel",
|
|
109
|
+
"smtp_host",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass
|
|
114
|
+
class SQLToolParams(ToolParams):
|
|
115
|
+
|
|
116
|
+
_REQUIRED_FIELDS = ["profile_name"]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass
|
|
120
|
+
class RAGToolParams(ToolParams):
|
|
121
|
+
|
|
122
|
+
_REQUIRED_FIELDS = ["profile_name"]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class SlackNotificationToolParams(ToolParams):
|
|
127
|
+
|
|
128
|
+
_REQUIRED_FIELDS = ["credential_name", "slack_channel"]
|
|
129
|
+
notification_type: NotificationType = NotificationType.SLACK
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass
|
|
133
|
+
class EmailNotificationToolParams(ToolParams):
|
|
134
|
+
|
|
135
|
+
_REQUIRED_FIELDS = ["credential_name", "recipient", "sender", "smtp_host"]
|
|
136
|
+
notification_type: NotificationType = NotificationType.EMAIL
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass
|
|
140
|
+
class WebSearchToolParams(ToolParams):
|
|
141
|
+
|
|
142
|
+
_REQUIRED_FIELDS = ["credential_name"]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass
|
|
146
|
+
class HumanToolParams(ToolParams):
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass
|
|
151
|
+
class HTTPToolParams(ToolParams):
|
|
152
|
+
|
|
153
|
+
_REQUIRED_FIELDS = ["credential_name", "endpoint"]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@dataclass
|
|
157
|
+
class ToolAttributes(SelectAIDataClass):
|
|
158
|
+
"""
|
|
159
|
+
AI Tool attributes
|
|
160
|
+
|
|
161
|
+
:param str instruction: Statement that describes what the tool
|
|
162
|
+
should accomplish and how to do it. This text is included
|
|
163
|
+
in the prompt sent to the LLM.
|
|
164
|
+
:param function: Specifies the PL/SQL procedure or
|
|
165
|
+
function to call when the tool is used
|
|
166
|
+
:param select_ai.agent.ToolParams tool_params: Tool parameters
|
|
167
|
+
for built-in tools
|
|
168
|
+
:param List[Mapping] tool_inputs: Describes input arguments.
|
|
169
|
+
Similar to column comments in a table. For example:
|
|
170
|
+
"tool_inputs": [
|
|
171
|
+
{
|
|
172
|
+
"name": "data_guard",
|
|
173
|
+
"description": "Only supported values are "Enabled" and "Disabled""
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
instruction: Optional[str] = None
|
|
180
|
+
function: Optional[str] = None
|
|
181
|
+
tool_params: Optional[ToolParams] = None
|
|
182
|
+
tool_inputs: Optional[List[Mapping]] = None
|
|
183
|
+
tool_type: Optional[ToolType] = None
|
|
184
|
+
|
|
185
|
+
def dict(self, exclude_null=True):
|
|
186
|
+
attributes = {}
|
|
187
|
+
for k, v in self.__dict__.items():
|
|
188
|
+
if v is not None or not exclude_null:
|
|
189
|
+
if isinstance(v, ToolParams):
|
|
190
|
+
attributes[k] = v.dict(exclude_null=exclude_null)
|
|
191
|
+
else:
|
|
192
|
+
attributes[k] = v
|
|
193
|
+
return attributes
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
def create(cls, **kwargs):
|
|
197
|
+
tool_attributes = {}
|
|
198
|
+
tool_params = {}
|
|
199
|
+
for k, v in kwargs.items():
|
|
200
|
+
if isinstance(v, oracledb.LOB):
|
|
201
|
+
v = v.read()
|
|
202
|
+
if k in ToolParams.keys():
|
|
203
|
+
tool_params[k] = v
|
|
204
|
+
elif k == "tool_params" and v is not None:
|
|
205
|
+
tool_params = json.loads(v)
|
|
206
|
+
else:
|
|
207
|
+
tool_attributes[k] = v
|
|
208
|
+
tool_params = ToolParams.create(
|
|
209
|
+
tool_type=tool_attributes.get("tool_type"), **tool_params
|
|
210
|
+
)
|
|
211
|
+
tool_attributes["tool_params"] = tool_params
|
|
212
|
+
return ToolAttributes(**tool_attributes)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
ToolTypeParams = {
|
|
216
|
+
ToolType.EMAIL: EmailNotificationToolParams,
|
|
217
|
+
ToolType.SLACK: SlackNotificationToolParams,
|
|
218
|
+
ToolType.HTTP: HTTPToolParams,
|
|
219
|
+
ToolType.RAG: RAGToolParams,
|
|
220
|
+
ToolType.SQL: SQLToolParams,
|
|
221
|
+
ToolType.WEBSEARCH: WebSearchToolParams,
|
|
222
|
+
ToolType.HUMAN: HumanToolParams,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class _BaseTool(ABC):
|
|
227
|
+
|
|
228
|
+
def __init__(
|
|
229
|
+
self,
|
|
230
|
+
tool_name: Optional[str] = None,
|
|
231
|
+
description: Optional[str] = None,
|
|
232
|
+
attributes: Optional[ToolAttributes] = None,
|
|
233
|
+
):
|
|
234
|
+
"""Initialize an AI Agent Tool"""
|
|
235
|
+
if attributes and not isinstance(attributes, ToolAttributes):
|
|
236
|
+
raise TypeError(
|
|
237
|
+
"'attributes' must be an object of type "
|
|
238
|
+
"select_ai.agent.ToolAttributes"
|
|
239
|
+
)
|
|
240
|
+
self.tool_name = tool_name
|
|
241
|
+
self.attributes = attributes
|
|
242
|
+
self.description = description
|
|
243
|
+
|
|
244
|
+
def __repr__(self):
|
|
245
|
+
return (
|
|
246
|
+
f"{self.__class__.__name__}("
|
|
247
|
+
f"tool_name={self.tool_name}, "
|
|
248
|
+
f"attributes={self.attributes}, description={self.description})"
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class Tool(_BaseTool):
|
|
253
|
+
|
|
254
|
+
@staticmethod
|
|
255
|
+
def _get_attributes(tool_name: str) -> ToolAttributes:
|
|
256
|
+
"""Get attributes of an AI tool
|
|
257
|
+
|
|
258
|
+
:return: select_ai.agent.ToolAttributes
|
|
259
|
+
:raises: AgentToolNotFoundError
|
|
260
|
+
"""
|
|
261
|
+
with cursor() as cr:
|
|
262
|
+
cr.execute(
|
|
263
|
+
GET_USER_AI_AGENT_TOOL_ATTRIBUTES, tool_name=tool_name.upper()
|
|
264
|
+
)
|
|
265
|
+
attributes = cr.fetchall()
|
|
266
|
+
if attributes:
|
|
267
|
+
post_processed_attributes = {}
|
|
268
|
+
for k, v in attributes:
|
|
269
|
+
if isinstance(v, oracledb.LOB):
|
|
270
|
+
post_processed_attributes[k] = v.read()
|
|
271
|
+
else:
|
|
272
|
+
post_processed_attributes[k] = v
|
|
273
|
+
return ToolAttributes.create(**post_processed_attributes)
|
|
274
|
+
else:
|
|
275
|
+
raise AgentToolNotFoundError(tool_name=tool_name)
|
|
276
|
+
|
|
277
|
+
def create(
|
|
278
|
+
self, enabled: Optional[bool] = True, replace: Optional[bool] = False
|
|
279
|
+
):
|
|
280
|
+
if self.tool_name is None:
|
|
281
|
+
raise AttributeError("Tool must have a name")
|
|
282
|
+
if self.attributes is None:
|
|
283
|
+
raise AttributeError("Tool must have attributes")
|
|
284
|
+
|
|
285
|
+
parameters = {
|
|
286
|
+
"tool_name": self.tool_name,
|
|
287
|
+
"attributes": self.attributes.json(),
|
|
288
|
+
}
|
|
289
|
+
if self.description:
|
|
290
|
+
parameters["description"] = self.description
|
|
291
|
+
|
|
292
|
+
if not enabled:
|
|
293
|
+
parameters["status"] = "disabled"
|
|
294
|
+
|
|
295
|
+
with cursor() as cr:
|
|
296
|
+
try:
|
|
297
|
+
cr.callproc(
|
|
298
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TOOL",
|
|
299
|
+
keyword_parameters=parameters,
|
|
300
|
+
)
|
|
301
|
+
except oracledb.Error as err:
|
|
302
|
+
(err_obj,) = err.args
|
|
303
|
+
if err_obj.code in (20050, 20052) and replace:
|
|
304
|
+
self.delete(force=True)
|
|
305
|
+
cr.callproc(
|
|
306
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TOOL",
|
|
307
|
+
keyword_parameters=parameters,
|
|
308
|
+
)
|
|
309
|
+
else:
|
|
310
|
+
raise
|
|
311
|
+
|
|
312
|
+
@classmethod
|
|
313
|
+
def create_built_in_tool(
|
|
314
|
+
cls,
|
|
315
|
+
tool_name: str,
|
|
316
|
+
tool_params: ToolParams,
|
|
317
|
+
tool_type: ToolType,
|
|
318
|
+
description: Optional[str] = None,
|
|
319
|
+
replace: Optional[bool] = False,
|
|
320
|
+
) -> "Tool":
|
|
321
|
+
"""
|
|
322
|
+
Register a built-in tool
|
|
323
|
+
|
|
324
|
+
:param str tool_name: The name of the tool
|
|
325
|
+
:param select_ai.agent.ToolParams tool_params:
|
|
326
|
+
Parameters required by built-in tool
|
|
327
|
+
:param select_ai.agent.ToolType tool_type: The built-in tool type
|
|
328
|
+
:param str description: Description of the tool
|
|
329
|
+
:param bool replace: Whether to replace the existing tool.
|
|
330
|
+
Default value is False
|
|
331
|
+
|
|
332
|
+
:return: select_ai.agent.Tool
|
|
333
|
+
"""
|
|
334
|
+
if not isinstance(tool_params, ToolParams):
|
|
335
|
+
raise TypeError(
|
|
336
|
+
"'tool_params' must be an object of "
|
|
337
|
+
"type select_ai.agent.ToolParams"
|
|
338
|
+
)
|
|
339
|
+
attributes = ToolAttributes(
|
|
340
|
+
tool_params=tool_params, tool_type=tool_type
|
|
341
|
+
)
|
|
342
|
+
tool = cls(
|
|
343
|
+
tool_name=tool_name, attributes=attributes, description=description
|
|
344
|
+
)
|
|
345
|
+
tool.create(replace=replace)
|
|
346
|
+
return tool
|
|
347
|
+
|
|
348
|
+
@classmethod
|
|
349
|
+
def create_email_notification_tool(
|
|
350
|
+
cls,
|
|
351
|
+
tool_name: str,
|
|
352
|
+
credential_name: str,
|
|
353
|
+
recipient: str,
|
|
354
|
+
sender: str,
|
|
355
|
+
smtp_host: str,
|
|
356
|
+
description: Optional[str],
|
|
357
|
+
replace: bool = False,
|
|
358
|
+
) -> "Tool":
|
|
359
|
+
"""
|
|
360
|
+
Register an email notification tool
|
|
361
|
+
|
|
362
|
+
:param str tool_name: The name of the tool
|
|
363
|
+
:param str credential_name: The name of the credential
|
|
364
|
+
:param str recipient: The recipient of the email
|
|
365
|
+
:param str sender: The sender of the email
|
|
366
|
+
:param str smtp_host: The SMTP host of the email server
|
|
367
|
+
:param str description: The description of the tool
|
|
368
|
+
:param bool replace: Whether to replace the existing tool.
|
|
369
|
+
Default value is False
|
|
370
|
+
|
|
371
|
+
:return: select_ai.agent.Tool
|
|
372
|
+
|
|
373
|
+
"""
|
|
374
|
+
email_notification_tool_params = EmailNotificationToolParams(
|
|
375
|
+
credential_name=credential_name,
|
|
376
|
+
recipient=recipient,
|
|
377
|
+
sender=sender,
|
|
378
|
+
smtp_host=smtp_host,
|
|
379
|
+
)
|
|
380
|
+
return cls.create_built_in_tool(
|
|
381
|
+
tool_name=tool_name,
|
|
382
|
+
tool_type=ToolType.EMAIL,
|
|
383
|
+
tool_params=email_notification_tool_params,
|
|
384
|
+
description=description,
|
|
385
|
+
replace=replace,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
@classmethod
|
|
389
|
+
def create_http_tool(
|
|
390
|
+
cls,
|
|
391
|
+
tool_name: str,
|
|
392
|
+
credential_name: str,
|
|
393
|
+
endpoint: str,
|
|
394
|
+
description: Optional[str] = None,
|
|
395
|
+
replace: bool = False,
|
|
396
|
+
) -> "Tool":
|
|
397
|
+
http_tool_params = HTTPToolParams(
|
|
398
|
+
credential_name=credential_name, endpoint=endpoint
|
|
399
|
+
)
|
|
400
|
+
return cls.create_built_in_tool(
|
|
401
|
+
tool_name=tool_name,
|
|
402
|
+
tool_type=ToolType.HTTP,
|
|
403
|
+
tool_params=http_tool_params,
|
|
404
|
+
description=description,
|
|
405
|
+
replace=replace,
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
@classmethod
|
|
409
|
+
def create_pl_sql_tool(
|
|
410
|
+
cls,
|
|
411
|
+
tool_name: str,
|
|
412
|
+
function: str,
|
|
413
|
+
description: Optional[str] = None,
|
|
414
|
+
replace: bool = False,
|
|
415
|
+
) -> "Tool":
|
|
416
|
+
"""
|
|
417
|
+
Create a custom tool to invoke PL/SQL procedure or function
|
|
418
|
+
|
|
419
|
+
:param str tool_name: The name of the tool
|
|
420
|
+
:param str function: The name of the PL/SQL procedure or function
|
|
421
|
+
:param str description: The description of the tool
|
|
422
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
423
|
+
is False
|
|
424
|
+
|
|
425
|
+
"""
|
|
426
|
+
tool_attributes = ToolAttributes(function=function)
|
|
427
|
+
tool = cls(
|
|
428
|
+
tool_name=tool_name,
|
|
429
|
+
attributes=tool_attributes,
|
|
430
|
+
description=description,
|
|
431
|
+
)
|
|
432
|
+
tool.create(replace=replace)
|
|
433
|
+
return tool
|
|
434
|
+
|
|
435
|
+
@classmethod
|
|
436
|
+
def create_rag_tool(
|
|
437
|
+
cls,
|
|
438
|
+
tool_name: str,
|
|
439
|
+
profile_name: str,
|
|
440
|
+
description: Optional[str] = None,
|
|
441
|
+
replace: bool = False,
|
|
442
|
+
) -> "Tool":
|
|
443
|
+
"""
|
|
444
|
+
Register a RAG tool, which will use a VectorIndex linked AI Profile
|
|
445
|
+
|
|
446
|
+
:param str tool_name: The name of the tool
|
|
447
|
+
:param str profile_name: The name of the profile to
|
|
448
|
+
use for Vector Index based RAG
|
|
449
|
+
:param str description: The description of the tool
|
|
450
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
451
|
+
is False
|
|
452
|
+
"""
|
|
453
|
+
tool_params = RAGToolParams(profile_name=profile_name)
|
|
454
|
+
return cls.create_built_in_tool(
|
|
455
|
+
tool_name=tool_name,
|
|
456
|
+
tool_type=ToolType.RAG,
|
|
457
|
+
tool_params=tool_params,
|
|
458
|
+
description=description,
|
|
459
|
+
replace=replace,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
@classmethod
|
|
463
|
+
def create_sql_tool(
|
|
464
|
+
cls,
|
|
465
|
+
tool_name: str,
|
|
466
|
+
profile_name: str,
|
|
467
|
+
description: Optional[str] = None,
|
|
468
|
+
replace: bool = False,
|
|
469
|
+
) -> "Tool":
|
|
470
|
+
"""
|
|
471
|
+
Register a SQL tool to perform natural language to SQL translation
|
|
472
|
+
|
|
473
|
+
:param str tool_name: The name of the tool
|
|
474
|
+
:param str profile_name: The name of the profile to use for SQL
|
|
475
|
+
translation
|
|
476
|
+
:param str description: The description of the tool
|
|
477
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
478
|
+
is False
|
|
479
|
+
"""
|
|
480
|
+
tool_params = SQLToolParams(profile_name=profile_name)
|
|
481
|
+
return cls.create_built_in_tool(
|
|
482
|
+
tool_name=tool_name,
|
|
483
|
+
tool_type=ToolType.SQL,
|
|
484
|
+
tool_params=tool_params,
|
|
485
|
+
description=description,
|
|
486
|
+
replace=replace,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
@classmethod
|
|
490
|
+
def create_slack_notification_tool(
|
|
491
|
+
cls,
|
|
492
|
+
tool_name: str,
|
|
493
|
+
credential_name: str,
|
|
494
|
+
slack_channel: str,
|
|
495
|
+
description: Optional[str] = None,
|
|
496
|
+
replace: bool = False,
|
|
497
|
+
) -> "Tool":
|
|
498
|
+
"""
|
|
499
|
+
Register a Slack notification tool
|
|
500
|
+
|
|
501
|
+
:param str tool_name: The name of the Slack notification tool
|
|
502
|
+
:param str credential_name: The name of the Slack credential
|
|
503
|
+
:param str slack_channel: The name of the Slack channel
|
|
504
|
+
:param str description: The description of the Slack notification tool
|
|
505
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
506
|
+
is False
|
|
507
|
+
|
|
508
|
+
"""
|
|
509
|
+
slack_notification_tool_params = SlackNotificationToolParams(
|
|
510
|
+
credential_name=credential_name,
|
|
511
|
+
slack_channel=slack_channel,
|
|
512
|
+
)
|
|
513
|
+
return cls.create_built_in_tool(
|
|
514
|
+
tool_name=tool_name,
|
|
515
|
+
tool_type=ToolType.SLACK,
|
|
516
|
+
tool_params=slack_notification_tool_params,
|
|
517
|
+
description=description,
|
|
518
|
+
replace=replace,
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
@classmethod
|
|
522
|
+
def create_websearch_tool(
|
|
523
|
+
cls,
|
|
524
|
+
tool_name: str,
|
|
525
|
+
credential_name: str,
|
|
526
|
+
description: Optional[str],
|
|
527
|
+
replace: bool = False,
|
|
528
|
+
) -> "Tool":
|
|
529
|
+
"""
|
|
530
|
+
Register a built-in websearch tool to search information
|
|
531
|
+
on the web
|
|
532
|
+
|
|
533
|
+
:param str tool_name: The name of the tool
|
|
534
|
+
:param str credential_name: The name of the credential object
|
|
535
|
+
storing OpenAI credentials
|
|
536
|
+
:param str description: The description of the tool
|
|
537
|
+
:param bool replace: Whether to replace the existing tool
|
|
538
|
+
|
|
539
|
+
"""
|
|
540
|
+
web_search_tool_params = WebSearchToolParams(
|
|
541
|
+
credential_name=credential_name,
|
|
542
|
+
)
|
|
543
|
+
return cls.create_built_in_tool(
|
|
544
|
+
tool_name=tool_name,
|
|
545
|
+
tool_type=ToolType.WEBSEARCH,
|
|
546
|
+
tool_params=web_search_tool_params,
|
|
547
|
+
description=description,
|
|
548
|
+
replace=replace,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
def disable(self):
|
|
552
|
+
"""
|
|
553
|
+
Disable AI Tool
|
|
554
|
+
"""
|
|
555
|
+
pass
|
|
556
|
+
|
|
557
|
+
def delete(self, force: bool = False):
|
|
558
|
+
"""
|
|
559
|
+
Delete AI Tool from the database
|
|
560
|
+
|
|
561
|
+
:param bool force: Force the deletion. Default value is False.
|
|
562
|
+
"""
|
|
563
|
+
with cursor() as cr:
|
|
564
|
+
cr.callproc(
|
|
565
|
+
"DBMS_CLOUD_AI_AGENT.DROP_TOOL",
|
|
566
|
+
keyword_parameters={
|
|
567
|
+
"tool_name": self.tool_name,
|
|
568
|
+
"force": force,
|
|
569
|
+
},
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
def enable(self):
|
|
573
|
+
"""
|
|
574
|
+
Enable AI Tool
|
|
575
|
+
"""
|
|
576
|
+
pass
|
|
577
|
+
|
|
578
|
+
@classmethod
|
|
579
|
+
def fetch(cls, tool_name: str) -> "Tool":
|
|
580
|
+
"""
|
|
581
|
+
Fetch AI Tool attributes from the Database and build a proxy object in
|
|
582
|
+
the Python layer
|
|
583
|
+
|
|
584
|
+
:param str tool_name: The name of the AI Task
|
|
585
|
+
|
|
586
|
+
:return: select_ai.agent.Tool
|
|
587
|
+
|
|
588
|
+
:raises select_ai.errors.AgentToolNotFoundError:
|
|
589
|
+
If the AI Tool is not found
|
|
590
|
+
|
|
591
|
+
"""
|
|
592
|
+
pass
|
|
593
|
+
|
|
594
|
+
@classmethod
|
|
595
|
+
def list(cls, tool_name_pattern: str = ".*") -> Iterator["Tool"]:
|
|
596
|
+
"""List AI Tools
|
|
597
|
+
|
|
598
|
+
:param str tool_name_pattern: Regular expressions can be used
|
|
599
|
+
to specify a pattern. Function REGEXP_LIKE is used to perform the
|
|
600
|
+
match. Default value is ".*" i.e. match all tool name.
|
|
601
|
+
|
|
602
|
+
:return: Iterator[Tool]
|
|
603
|
+
"""
|
|
604
|
+
with cursor() as cr:
|
|
605
|
+
cr.execute(
|
|
606
|
+
LIST_USER_AI_AGENT_TOOLS,
|
|
607
|
+
tool_name_pattern=tool_name_pattern,
|
|
608
|
+
)
|
|
609
|
+
for row in cr.fetchall():
|
|
610
|
+
tool_name = row[0]
|
|
611
|
+
if row[1]:
|
|
612
|
+
description = row[1].read() # Oracle.LOB
|
|
613
|
+
else:
|
|
614
|
+
description = None
|
|
615
|
+
attributes = cls._get_attributes(tool_name=tool_name)
|
|
616
|
+
yield cls(
|
|
617
|
+
tool_name=tool_name,
|
|
618
|
+
description=description,
|
|
619
|
+
attributes=attributes,
|
|
620
|
+
)
|
select_ai/errors.py
CHANGED
|
@@ -71,3 +71,43 @@ class VectorIndexNotFoundError(SelectAIError):
|
|
|
71
71
|
)
|
|
72
72
|
else:
|
|
73
73
|
return f"VectorIndex {self.index_name} not found"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AgentNotFoundError(SelectAIError):
|
|
77
|
+
"""Agent not found in the database"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, agent_name: str):
|
|
80
|
+
self.agent_name = agent_name
|
|
81
|
+
|
|
82
|
+
def __str__(self):
|
|
83
|
+
return f"Agent {self.agent_name} not found"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class AgentTaskNotFoundError(SelectAIError):
|
|
87
|
+
"""Agent task not found in the database"""
|
|
88
|
+
|
|
89
|
+
def __init__(self, task_name: str):
|
|
90
|
+
self.task_name = task_name
|
|
91
|
+
|
|
92
|
+
def __str__(self):
|
|
93
|
+
return f"Agent Task {self.task_name} not found"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class AgentToolNotFoundError(SelectAIError):
|
|
97
|
+
"""Agent tool not found in the database"""
|
|
98
|
+
|
|
99
|
+
def __init__(self, tool_name: str):
|
|
100
|
+
self.tool_name = tool_name
|
|
101
|
+
|
|
102
|
+
def __str__(self):
|
|
103
|
+
return f"Agent Tool {self.tool_name} not found"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class AgentTeamNotFoundError(SelectAIError):
|
|
107
|
+
"""Agent team not found in the database"""
|
|
108
|
+
|
|
109
|
+
def __init__(self, team_name: str):
|
|
110
|
+
self.team_name = team_name
|
|
111
|
+
|
|
112
|
+
def __str__(self):
|
|
113
|
+
return f"Agent Team {self.team_name} not found"
|
select_ai/sql.py
CHANGED
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
GRANT_PRIVILEGES_TO_USER = """
|
|
9
9
|
DECLARE
|
|
10
|
-
TYPE array_t IS VARRAY(
|
|
10
|
+
TYPE array_t IS VARRAY(4) OF VARCHAR2(60);
|
|
11
11
|
v_packages array_t;
|
|
12
12
|
BEGIN
|
|
13
13
|
v_packages := array_t(
|
|
14
|
-
'DBMS_CLOUD',
|
|
14
|
+
'DBMS_CLOUD',
|
|
15
|
+
'DBMS_CLOUD_AI',
|
|
16
|
+
'DBMS_CLOUD_AI_AGENT',
|
|
17
|
+
'DBMS_CLOUD_PIPELINE'
|
|
15
18
|
);
|
|
16
19
|
FOR i in 1..v_packages.count LOOP
|
|
17
20
|
EXECUTE IMMEDIATE
|
|
@@ -22,11 +25,14 @@ END;
|
|
|
22
25
|
|
|
23
26
|
REVOKE_PRIVILEGES_FROM_USER = """
|
|
24
27
|
DECLARE
|
|
25
|
-
TYPE array_t IS VARRAY(
|
|
28
|
+
TYPE array_t IS VARRAY(4) OF VARCHAR2(60);
|
|
26
29
|
v_packages array_t;
|
|
27
30
|
BEGIN
|
|
28
31
|
v_packages := array_t(
|
|
29
|
-
'DBMS_CLOUD',
|
|
32
|
+
'DBMS_CLOUD',
|
|
33
|
+
'DBMS_CLOUD_AI',
|
|
34
|
+
'DBMS_CLOUD_AI_AGENT',
|
|
35
|
+
'DBMS_CLOUD_PIPELINE'
|
|
30
36
|
);
|
|
31
37
|
FOR i in 1..v_packages.count LOOP
|
|
32
38
|
EXECUTE IMMEDIATE
|