select-ai 1.2.0rc3__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.
- select_ai/__init__.py +66 -0
- select_ai/_abc.py +82 -0
- select_ai/_enums.py +14 -0
- select_ai/_validations.py +123 -0
- select_ai/action.py +23 -0
- select_ai/agent/__init__.py +25 -0
- select_ai/agent/core.py +511 -0
- select_ai/agent/sql.py +82 -0
- select_ai/agent/task.py +521 -0
- select_ai/agent/team.py +590 -0
- select_ai/agent/tool.py +1129 -0
- select_ai/async_profile.py +648 -0
- select_ai/base_profile.py +265 -0
- select_ai/conversation.py +295 -0
- select_ai/credential.py +135 -0
- select_ai/db.py +191 -0
- select_ai/errors.py +113 -0
- select_ai/feedback.py +19 -0
- select_ai/privilege.py +135 -0
- select_ai/profile.py +579 -0
- select_ai/provider.py +195 -0
- select_ai/sql.py +111 -0
- select_ai/summary.py +61 -0
- select_ai/synthetic_data.py +90 -0
- select_ai/vector_index.py +642 -0
- select_ai/version.py +8 -0
- select_ai-1.2.0rc3.dist-info/METADATA +129 -0
- select_ai-1.2.0rc3.dist-info/RECORD +31 -0
- select_ai-1.2.0rc3.dist-info/WHEEL +5 -0
- select_ai-1.2.0rc3.dist-info/licenses/LICENSE.txt +35 -0
- select_ai-1.2.0rc3.dist-info/top_level.txt +1 -0
select_ai/agent/tool.py
ADDED
|
@@ -0,0 +1,1129 @@
|
|
|
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_TOOL,
|
|
28
|
+
GET_USER_AI_AGENT_TOOL_ATTRIBUTES,
|
|
29
|
+
LIST_USER_AI_AGENT_TOOLS,
|
|
30
|
+
)
|
|
31
|
+
from select_ai.async_profile import AsyncProfile
|
|
32
|
+
from select_ai.db import async_cursor, cursor
|
|
33
|
+
from select_ai.errors import AgentToolNotFoundError
|
|
34
|
+
from select_ai.profile import Profile
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class NotificationType(StrEnum):
|
|
38
|
+
"""
|
|
39
|
+
Notification Types
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
SLACK = "slack"
|
|
43
|
+
EMAIL = "email"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ToolType(StrEnum):
|
|
47
|
+
"""
|
|
48
|
+
Built-in Tool Types
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
EMAIL = "EMAIL"
|
|
52
|
+
HUMAN = "HUMAN"
|
|
53
|
+
HTTP = "HTTP"
|
|
54
|
+
RAG = "RAG"
|
|
55
|
+
SQL = "SQL"
|
|
56
|
+
SLACK = "SLACK"
|
|
57
|
+
WEBSEARCH = "WEBSEARCH"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class ToolParams(SelectAIDataClass):
|
|
62
|
+
"""
|
|
63
|
+
Parameters to register a built-in Tool
|
|
64
|
+
|
|
65
|
+
:param str credential_name: Used by SLACK, EMAIL and WEBSEARCH tools
|
|
66
|
+
|
|
67
|
+
:param str endpoint: Send HTTP requests to this endpoint
|
|
68
|
+
|
|
69
|
+
:param select_ai.agent.NotificationType: Either SLACK or EMAIL
|
|
70
|
+
|
|
71
|
+
:param str profile_name: Name of AI profile to use
|
|
72
|
+
|
|
73
|
+
:param str recipient: Recipient used for EMAIL notification
|
|
74
|
+
|
|
75
|
+
:param str sender: Sender used for EMAIL notification
|
|
76
|
+
|
|
77
|
+
:param str slack_channel: Slack channel to use
|
|
78
|
+
|
|
79
|
+
:param str smtp_host: SMTP host to use for EMAIL notification
|
|
80
|
+
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
_REQUIRED_FIELDS: Optional[List] = None
|
|
84
|
+
|
|
85
|
+
credential_name: Optional[str] = None
|
|
86
|
+
endpoint: Optional[str] = None
|
|
87
|
+
notification_type: Optional[NotificationType] = None
|
|
88
|
+
profile_name: Optional[str] = None
|
|
89
|
+
recipient: Optional[str] = None
|
|
90
|
+
sender: Optional[str] = None
|
|
91
|
+
slack_channel: Optional[str] = None
|
|
92
|
+
smtp_host: Optional[str] = None
|
|
93
|
+
|
|
94
|
+
def __post_init__(self):
|
|
95
|
+
super().__post_init__()
|
|
96
|
+
if self._REQUIRED_FIELDS:
|
|
97
|
+
for field in self._REQUIRED_FIELDS:
|
|
98
|
+
if getattr(self, field) is None:
|
|
99
|
+
raise AttributeError(
|
|
100
|
+
"Required field '{}' not found.".format(field)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def create(cls, *, tool_type: Optional[ToolType] = None, **kwargs):
|
|
105
|
+
tool_params_cls = ToolTypeParams.get(tool_type, ToolParams)
|
|
106
|
+
return tool_params_cls(**kwargs)
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def keys(cls):
|
|
110
|
+
return {
|
|
111
|
+
"credential_name",
|
|
112
|
+
"endpoint",
|
|
113
|
+
"notification_type",
|
|
114
|
+
"profile_name",
|
|
115
|
+
"recipient",
|
|
116
|
+
"sender",
|
|
117
|
+
"slack_channel",
|
|
118
|
+
"smtp_host",
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass
|
|
123
|
+
class SQLToolParams(ToolParams):
|
|
124
|
+
|
|
125
|
+
_REQUIRED_FIELDS = ["profile_name"]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class RAGToolParams(ToolParams):
|
|
130
|
+
|
|
131
|
+
_REQUIRED_FIELDS = ["profile_name"]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@dataclass
|
|
135
|
+
class SlackNotificationToolParams(ToolParams):
|
|
136
|
+
|
|
137
|
+
_REQUIRED_FIELDS = ["credential_name", "slack_channel"]
|
|
138
|
+
notification_type: NotificationType = NotificationType.SLACK
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass
|
|
142
|
+
class EmailNotificationToolParams(ToolParams):
|
|
143
|
+
|
|
144
|
+
_REQUIRED_FIELDS = ["credential_name", "recipient", "sender", "smtp_host"]
|
|
145
|
+
notification_type: NotificationType = NotificationType.EMAIL
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@dataclass
|
|
149
|
+
class WebSearchToolParams(ToolParams):
|
|
150
|
+
|
|
151
|
+
_REQUIRED_FIELDS = ["credential_name"]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@dataclass
|
|
155
|
+
class HumanToolParams(ToolParams):
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
160
|
+
class HTTPToolParams(ToolParams):
|
|
161
|
+
|
|
162
|
+
_REQUIRED_FIELDS = ["credential_name", "endpoint"]
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class ToolAttributes(SelectAIDataClass):
|
|
167
|
+
"""
|
|
168
|
+
AI Tool attributes
|
|
169
|
+
|
|
170
|
+
:param str instruction: Statement that describes what the tool
|
|
171
|
+
should accomplish and how to do it. This text is included
|
|
172
|
+
in the prompt sent to the LLM.
|
|
173
|
+
:param function: Specifies the PL/SQL procedure or
|
|
174
|
+
function to call when the tool is used
|
|
175
|
+
:param select_ai.agent.ToolParams tool_params: Tool parameters
|
|
176
|
+
for built-in tools
|
|
177
|
+
:param List[Mapping] tool_inputs: Describes input arguments.
|
|
178
|
+
Similar to column comments in a table. For example:
|
|
179
|
+
"tool_inputs": [
|
|
180
|
+
{
|
|
181
|
+
"name": "data_guard",
|
|
182
|
+
"description": "Only supported values are "Enabled" and "Disabled""
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
instruction: Optional[str] = None
|
|
189
|
+
function: Optional[str] = None
|
|
190
|
+
tool_params: Optional[ToolParams] = None
|
|
191
|
+
tool_inputs: Optional[List[Mapping]] = None
|
|
192
|
+
tool_type: Optional[ToolType] = None
|
|
193
|
+
|
|
194
|
+
def dict(self, exclude_null=True):
|
|
195
|
+
attributes = {}
|
|
196
|
+
for k, v in self.__dict__.items():
|
|
197
|
+
if v is not None or not exclude_null:
|
|
198
|
+
if isinstance(v, ToolParams):
|
|
199
|
+
attributes[k] = v.dict(exclude_null=exclude_null)
|
|
200
|
+
else:
|
|
201
|
+
attributes[k] = v
|
|
202
|
+
return attributes
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def create(cls, **kwargs):
|
|
206
|
+
tool_attributes = {}
|
|
207
|
+
tool_params = {}
|
|
208
|
+
for k, v in kwargs.items():
|
|
209
|
+
if isinstance(v, oracledb.LOB):
|
|
210
|
+
v = v.read()
|
|
211
|
+
if k in ToolParams.keys():
|
|
212
|
+
tool_params[k] = v
|
|
213
|
+
elif k == "tool_params" and v is not None:
|
|
214
|
+
tool_params = json.loads(v)
|
|
215
|
+
else:
|
|
216
|
+
tool_attributes[k] = v
|
|
217
|
+
tool_params = ToolParams.create(
|
|
218
|
+
tool_type=tool_attributes.get("tool_type"), **tool_params
|
|
219
|
+
)
|
|
220
|
+
tool_attributes["tool_params"] = tool_params
|
|
221
|
+
return ToolAttributes(**tool_attributes)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
ToolTypeParams = {
|
|
225
|
+
ToolType.EMAIL: EmailNotificationToolParams,
|
|
226
|
+
ToolType.SLACK: SlackNotificationToolParams,
|
|
227
|
+
ToolType.HTTP: HTTPToolParams,
|
|
228
|
+
ToolType.RAG: RAGToolParams,
|
|
229
|
+
ToolType.SQL: SQLToolParams,
|
|
230
|
+
ToolType.WEBSEARCH: WebSearchToolParams,
|
|
231
|
+
ToolType.HUMAN: HumanToolParams,
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class _BaseTool(ABC):
|
|
236
|
+
|
|
237
|
+
def __init__(
|
|
238
|
+
self,
|
|
239
|
+
tool_name: Optional[str] = None,
|
|
240
|
+
description: Optional[str] = None,
|
|
241
|
+
attributes: Optional[ToolAttributes] = None,
|
|
242
|
+
):
|
|
243
|
+
"""Initialize an AI Agent Tool"""
|
|
244
|
+
if attributes and not isinstance(attributes, ToolAttributes):
|
|
245
|
+
raise TypeError(
|
|
246
|
+
"'attributes' must be an object of type "
|
|
247
|
+
"select_ai.agent.ToolAttributes"
|
|
248
|
+
)
|
|
249
|
+
self.tool_name = tool_name
|
|
250
|
+
self.attributes = attributes
|
|
251
|
+
self.description = description
|
|
252
|
+
|
|
253
|
+
def __repr__(self):
|
|
254
|
+
return (
|
|
255
|
+
f"{self.__class__.__name__}("
|
|
256
|
+
f"tool_name={self.tool_name}, "
|
|
257
|
+
f"attributes={self.attributes}, description={self.description})"
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class Tool(_BaseTool):
|
|
262
|
+
|
|
263
|
+
@staticmethod
|
|
264
|
+
def _get_attributes(tool_name: str) -> ToolAttributes:
|
|
265
|
+
"""Get attributes of an AI tool
|
|
266
|
+
|
|
267
|
+
:return: select_ai.agent.ToolAttributes
|
|
268
|
+
:raises: AgentToolNotFoundError
|
|
269
|
+
"""
|
|
270
|
+
with cursor() as cr:
|
|
271
|
+
cr.execute(
|
|
272
|
+
GET_USER_AI_AGENT_TOOL_ATTRIBUTES, tool_name=tool_name.upper()
|
|
273
|
+
)
|
|
274
|
+
attributes = cr.fetchall()
|
|
275
|
+
if attributes:
|
|
276
|
+
post_processed_attributes = {}
|
|
277
|
+
for k, v in attributes:
|
|
278
|
+
if isinstance(v, oracledb.LOB):
|
|
279
|
+
post_processed_attributes[k] = v.read()
|
|
280
|
+
else:
|
|
281
|
+
post_processed_attributes[k] = v
|
|
282
|
+
return ToolAttributes.create(**post_processed_attributes)
|
|
283
|
+
else:
|
|
284
|
+
raise AgentToolNotFoundError(tool_name=tool_name)
|
|
285
|
+
|
|
286
|
+
@staticmethod
|
|
287
|
+
def _get_description(tool_name: str) -> Union[str, None]:
|
|
288
|
+
with cursor() as cr:
|
|
289
|
+
cr.execute(GET_USER_AI_AGENT_TOOL, tool_name=tool_name.upper())
|
|
290
|
+
tool = cr.fetchone()
|
|
291
|
+
if tool:
|
|
292
|
+
if tool[1] is not None:
|
|
293
|
+
return tool[1].read()
|
|
294
|
+
else:
|
|
295
|
+
return None
|
|
296
|
+
else:
|
|
297
|
+
raise AgentToolNotFoundError(tool_name=tool_name)
|
|
298
|
+
|
|
299
|
+
def create(
|
|
300
|
+
self, enabled: Optional[bool] = True, replace: Optional[bool] = False
|
|
301
|
+
):
|
|
302
|
+
if self.tool_name is None:
|
|
303
|
+
raise AttributeError("Tool must have a name")
|
|
304
|
+
if self.attributes is None:
|
|
305
|
+
raise AttributeError("Tool must have attributes")
|
|
306
|
+
|
|
307
|
+
parameters = {
|
|
308
|
+
"tool_name": self.tool_name,
|
|
309
|
+
"attributes": self.attributes.json(),
|
|
310
|
+
}
|
|
311
|
+
if self.description:
|
|
312
|
+
parameters["description"] = self.description
|
|
313
|
+
|
|
314
|
+
if not enabled:
|
|
315
|
+
parameters["status"] = "disabled"
|
|
316
|
+
|
|
317
|
+
with cursor() as cr:
|
|
318
|
+
try:
|
|
319
|
+
cr.callproc(
|
|
320
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TOOL",
|
|
321
|
+
keyword_parameters=parameters,
|
|
322
|
+
)
|
|
323
|
+
except oracledb.Error as err:
|
|
324
|
+
(err_obj,) = err.args
|
|
325
|
+
if err_obj.code in (20050, 20052) and replace:
|
|
326
|
+
self.delete(force=True)
|
|
327
|
+
cr.callproc(
|
|
328
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TOOL",
|
|
329
|
+
keyword_parameters=parameters,
|
|
330
|
+
)
|
|
331
|
+
else:
|
|
332
|
+
raise
|
|
333
|
+
|
|
334
|
+
@classmethod
|
|
335
|
+
def create_built_in_tool(
|
|
336
|
+
cls,
|
|
337
|
+
tool_name: str,
|
|
338
|
+
tool_params: ToolParams,
|
|
339
|
+
tool_type: ToolType,
|
|
340
|
+
description: Optional[str] = None,
|
|
341
|
+
replace: Optional[bool] = False,
|
|
342
|
+
) -> "Tool":
|
|
343
|
+
"""
|
|
344
|
+
Register a built-in tool
|
|
345
|
+
|
|
346
|
+
:param str tool_name: The name of the tool
|
|
347
|
+
:param select_ai.agent.ToolParams tool_params:
|
|
348
|
+
Parameters required by built-in tool
|
|
349
|
+
:param select_ai.agent.ToolType tool_type: The built-in tool type
|
|
350
|
+
:param str description: Description of the tool
|
|
351
|
+
:param bool replace: Whether to replace the existing tool.
|
|
352
|
+
Default value is False
|
|
353
|
+
|
|
354
|
+
:return: select_ai.agent.Tool
|
|
355
|
+
"""
|
|
356
|
+
if not isinstance(tool_params, ToolParams):
|
|
357
|
+
raise TypeError(
|
|
358
|
+
"'tool_params' must be an object of "
|
|
359
|
+
"type select_ai.agent.ToolParams"
|
|
360
|
+
)
|
|
361
|
+
attributes = ToolAttributes(
|
|
362
|
+
tool_params=tool_params, tool_type=tool_type
|
|
363
|
+
)
|
|
364
|
+
tool = cls(
|
|
365
|
+
tool_name=tool_name, attributes=attributes, description=description
|
|
366
|
+
)
|
|
367
|
+
tool.create(replace=replace)
|
|
368
|
+
return tool
|
|
369
|
+
|
|
370
|
+
@classmethod
|
|
371
|
+
def create_email_notification_tool(
|
|
372
|
+
cls,
|
|
373
|
+
tool_name: str,
|
|
374
|
+
credential_name: str,
|
|
375
|
+
recipient: str,
|
|
376
|
+
sender: str,
|
|
377
|
+
smtp_host: str,
|
|
378
|
+
description: Optional[str],
|
|
379
|
+
replace: bool = False,
|
|
380
|
+
) -> "Tool":
|
|
381
|
+
"""
|
|
382
|
+
Register an email notification tool
|
|
383
|
+
|
|
384
|
+
:param str tool_name: The name of the tool
|
|
385
|
+
:param str credential_name: The name of the credential
|
|
386
|
+
:param str recipient: The recipient of the email
|
|
387
|
+
:param str sender: The sender of the email
|
|
388
|
+
:param str smtp_host: The SMTP host of the email server
|
|
389
|
+
:param str description: The description of the tool
|
|
390
|
+
:param bool replace: Whether to replace the existing tool.
|
|
391
|
+
Default value is False
|
|
392
|
+
|
|
393
|
+
:return: select_ai.agent.Tool
|
|
394
|
+
|
|
395
|
+
"""
|
|
396
|
+
email_notification_tool_params = EmailNotificationToolParams(
|
|
397
|
+
credential_name=credential_name,
|
|
398
|
+
recipient=recipient,
|
|
399
|
+
sender=sender,
|
|
400
|
+
smtp_host=smtp_host,
|
|
401
|
+
)
|
|
402
|
+
return cls.create_built_in_tool(
|
|
403
|
+
tool_name=tool_name,
|
|
404
|
+
tool_type=ToolType.EMAIL,
|
|
405
|
+
tool_params=email_notification_tool_params,
|
|
406
|
+
description=description,
|
|
407
|
+
replace=replace,
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
@classmethod
|
|
411
|
+
def create_http_tool(
|
|
412
|
+
cls,
|
|
413
|
+
tool_name: str,
|
|
414
|
+
credential_name: str,
|
|
415
|
+
endpoint: str,
|
|
416
|
+
description: Optional[str] = None,
|
|
417
|
+
replace: bool = False,
|
|
418
|
+
) -> "Tool":
|
|
419
|
+
http_tool_params = HTTPToolParams(
|
|
420
|
+
credential_name=credential_name, endpoint=endpoint
|
|
421
|
+
)
|
|
422
|
+
return cls.create_built_in_tool(
|
|
423
|
+
tool_name=tool_name,
|
|
424
|
+
tool_type=ToolType.HTTP,
|
|
425
|
+
tool_params=http_tool_params,
|
|
426
|
+
description=description,
|
|
427
|
+
replace=replace,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
@classmethod
|
|
431
|
+
def create_pl_sql_tool(
|
|
432
|
+
cls,
|
|
433
|
+
tool_name: str,
|
|
434
|
+
function: str,
|
|
435
|
+
description: Optional[str] = None,
|
|
436
|
+
replace: bool = False,
|
|
437
|
+
) -> "Tool":
|
|
438
|
+
"""
|
|
439
|
+
Create a custom tool to invoke PL/SQL procedure or function
|
|
440
|
+
|
|
441
|
+
:param str tool_name: The name of the tool
|
|
442
|
+
:param str function: The name of the PL/SQL procedure or function
|
|
443
|
+
:param str description: The description of the tool
|
|
444
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
445
|
+
is False
|
|
446
|
+
|
|
447
|
+
"""
|
|
448
|
+
tool_attributes = ToolAttributes(function=function)
|
|
449
|
+
tool = cls(
|
|
450
|
+
tool_name=tool_name,
|
|
451
|
+
attributes=tool_attributes,
|
|
452
|
+
description=description,
|
|
453
|
+
)
|
|
454
|
+
tool.create(replace=replace)
|
|
455
|
+
return tool
|
|
456
|
+
|
|
457
|
+
@classmethod
|
|
458
|
+
def create_rag_tool(
|
|
459
|
+
cls,
|
|
460
|
+
tool_name: str,
|
|
461
|
+
profile_name: str,
|
|
462
|
+
description: Optional[str] = None,
|
|
463
|
+
replace: bool = False,
|
|
464
|
+
) -> "Tool":
|
|
465
|
+
"""
|
|
466
|
+
Register a RAG tool, which will use a VectorIndex linked AI Profile
|
|
467
|
+
|
|
468
|
+
:param str tool_name: The name of the tool
|
|
469
|
+
:param str profile_name: The name of the profile to
|
|
470
|
+
use for Vector Index based RAG
|
|
471
|
+
:param str description: The description of the tool
|
|
472
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
473
|
+
is False
|
|
474
|
+
"""
|
|
475
|
+
tool_params = RAGToolParams(profile_name=profile_name)
|
|
476
|
+
return cls.create_built_in_tool(
|
|
477
|
+
tool_name=tool_name,
|
|
478
|
+
tool_type=ToolType.RAG,
|
|
479
|
+
tool_params=tool_params,
|
|
480
|
+
description=description,
|
|
481
|
+
replace=replace,
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
@classmethod
|
|
485
|
+
def create_sql_tool(
|
|
486
|
+
cls,
|
|
487
|
+
tool_name: str,
|
|
488
|
+
profile_name: str,
|
|
489
|
+
description: Optional[str] = None,
|
|
490
|
+
replace: bool = False,
|
|
491
|
+
) -> "Tool":
|
|
492
|
+
"""
|
|
493
|
+
Register a SQL tool to perform natural language to SQL translation
|
|
494
|
+
|
|
495
|
+
:param str tool_name: The name of the tool
|
|
496
|
+
:param str profile_name: The name of the profile to use for SQL
|
|
497
|
+
translation
|
|
498
|
+
:param str description: The description of the tool
|
|
499
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
500
|
+
is False
|
|
501
|
+
"""
|
|
502
|
+
tool_params = SQLToolParams(profile_name=profile_name)
|
|
503
|
+
return cls.create_built_in_tool(
|
|
504
|
+
tool_name=tool_name,
|
|
505
|
+
tool_type=ToolType.SQL,
|
|
506
|
+
tool_params=tool_params,
|
|
507
|
+
description=description,
|
|
508
|
+
replace=replace,
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
@classmethod
|
|
512
|
+
def create_slack_notification_tool(
|
|
513
|
+
cls,
|
|
514
|
+
tool_name: str,
|
|
515
|
+
credential_name: str,
|
|
516
|
+
slack_channel: str,
|
|
517
|
+
description: Optional[str] = None,
|
|
518
|
+
replace: bool = False,
|
|
519
|
+
) -> "Tool":
|
|
520
|
+
"""
|
|
521
|
+
Register a Slack notification tool
|
|
522
|
+
|
|
523
|
+
:param str tool_name: The name of the Slack notification tool
|
|
524
|
+
:param str credential_name: The name of the Slack credential
|
|
525
|
+
:param str slack_channel: The name of the Slack channel
|
|
526
|
+
:param str description: The description of the Slack notification tool
|
|
527
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
528
|
+
is False
|
|
529
|
+
|
|
530
|
+
"""
|
|
531
|
+
slack_notification_tool_params = SlackNotificationToolParams(
|
|
532
|
+
credential_name=credential_name,
|
|
533
|
+
slack_channel=slack_channel,
|
|
534
|
+
)
|
|
535
|
+
return cls.create_built_in_tool(
|
|
536
|
+
tool_name=tool_name,
|
|
537
|
+
tool_type=ToolType.SLACK,
|
|
538
|
+
tool_params=slack_notification_tool_params,
|
|
539
|
+
description=description,
|
|
540
|
+
replace=replace,
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
@classmethod
|
|
544
|
+
def create_websearch_tool(
|
|
545
|
+
cls,
|
|
546
|
+
tool_name: str,
|
|
547
|
+
credential_name: str,
|
|
548
|
+
description: Optional[str],
|
|
549
|
+
replace: bool = False,
|
|
550
|
+
) -> "Tool":
|
|
551
|
+
"""
|
|
552
|
+
Register a built-in websearch tool to search information
|
|
553
|
+
on the web
|
|
554
|
+
|
|
555
|
+
:param str tool_name: The name of the tool
|
|
556
|
+
:param str credential_name: The name of the credential object
|
|
557
|
+
storing OpenAI credentials
|
|
558
|
+
:param str description: The description of the tool
|
|
559
|
+
:param bool replace: Whether to replace the existing tool
|
|
560
|
+
|
|
561
|
+
"""
|
|
562
|
+
web_search_tool_params = WebSearchToolParams(
|
|
563
|
+
credential_name=credential_name,
|
|
564
|
+
)
|
|
565
|
+
return cls.create_built_in_tool(
|
|
566
|
+
tool_name=tool_name,
|
|
567
|
+
tool_type=ToolType.WEBSEARCH,
|
|
568
|
+
tool_params=web_search_tool_params,
|
|
569
|
+
description=description,
|
|
570
|
+
replace=replace,
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
def delete(self, force: bool = False):
|
|
574
|
+
"""
|
|
575
|
+
Delete AI Tool from the database
|
|
576
|
+
|
|
577
|
+
:param bool force: Force the deletion. Default value is False.
|
|
578
|
+
"""
|
|
579
|
+
with cursor() as cr:
|
|
580
|
+
cr.callproc(
|
|
581
|
+
"DBMS_CLOUD_AI_AGENT.DROP_TOOL",
|
|
582
|
+
keyword_parameters={
|
|
583
|
+
"tool_name": self.tool_name,
|
|
584
|
+
"force": force,
|
|
585
|
+
},
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
def disable(self):
|
|
589
|
+
"""
|
|
590
|
+
Disable AI Tool
|
|
591
|
+
"""
|
|
592
|
+
with cursor() as cr:
|
|
593
|
+
cr.callproc(
|
|
594
|
+
"DBMS_CLOUD_AI_AGENT.DISABLE_TOOL",
|
|
595
|
+
keyword_parameters={
|
|
596
|
+
"tool_name": self.tool_name,
|
|
597
|
+
},
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
def enable(self):
|
|
601
|
+
"""
|
|
602
|
+
Enable AI Tool
|
|
603
|
+
"""
|
|
604
|
+
with cursor() as cr:
|
|
605
|
+
cr.callproc(
|
|
606
|
+
"DBMS_CLOUD_AI_AGENT.ENABLE_TOOL",
|
|
607
|
+
keyword_parameters={
|
|
608
|
+
"tool_name": self.tool_name,
|
|
609
|
+
},
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
@classmethod
|
|
613
|
+
def fetch(cls, tool_name: str) -> "Tool":
|
|
614
|
+
"""
|
|
615
|
+
Fetch AI Tool attributes from the Database and build a proxy object in
|
|
616
|
+
the Python layer
|
|
617
|
+
|
|
618
|
+
:param str tool_name: The name of the AI Task
|
|
619
|
+
|
|
620
|
+
:return: select_ai.agent.Tool
|
|
621
|
+
|
|
622
|
+
:raises select_ai.errors.AgentToolNotFoundError:
|
|
623
|
+
If the AI Tool is not found
|
|
624
|
+
|
|
625
|
+
"""
|
|
626
|
+
attributes = cls._get_attributes(tool_name)
|
|
627
|
+
description = cls._get_description(tool_name)
|
|
628
|
+
return cls(
|
|
629
|
+
tool_name=tool_name, attributes=attributes, description=description
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
@classmethod
|
|
633
|
+
def list(cls, tool_name_pattern: str = ".*") -> Iterator["Tool"]:
|
|
634
|
+
"""List AI Tools
|
|
635
|
+
|
|
636
|
+
:param str tool_name_pattern: Regular expressions can be used
|
|
637
|
+
to specify a pattern. Function REGEXP_LIKE is used to perform the
|
|
638
|
+
match. Default value is ".*" i.e. match all tool name.
|
|
639
|
+
|
|
640
|
+
:return: Iterator[Tool]
|
|
641
|
+
"""
|
|
642
|
+
with cursor() as cr:
|
|
643
|
+
cr.execute(
|
|
644
|
+
LIST_USER_AI_AGENT_TOOLS,
|
|
645
|
+
tool_name_pattern=tool_name_pattern,
|
|
646
|
+
)
|
|
647
|
+
for row in cr.fetchall():
|
|
648
|
+
tool_name = row[0]
|
|
649
|
+
if row[1]:
|
|
650
|
+
description = row[1].read() # Oracle.LOB
|
|
651
|
+
else:
|
|
652
|
+
description = None
|
|
653
|
+
attributes = cls._get_attributes(tool_name=tool_name)
|
|
654
|
+
yield cls(
|
|
655
|
+
tool_name=tool_name,
|
|
656
|
+
description=description,
|
|
657
|
+
attributes=attributes,
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
def set_attributes(self, attributes: ToolAttributes) -> None:
|
|
661
|
+
"""
|
|
662
|
+
Set the attributes of the AI Agent tool
|
|
663
|
+
"""
|
|
664
|
+
parameters = {
|
|
665
|
+
"object_name": self.tool_name,
|
|
666
|
+
"object_type": "tool",
|
|
667
|
+
"attributes": attributes.json(),
|
|
668
|
+
}
|
|
669
|
+
with cursor() as cr:
|
|
670
|
+
cr.callproc(
|
|
671
|
+
"DBMS_CLOUD_AI_AGENT.SET_ATTRIBUTES",
|
|
672
|
+
keyword_parameters=parameters,
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
def set_attribute(self, attribute_name: str, attribute_value: Any) -> None:
|
|
676
|
+
"""
|
|
677
|
+
Set the attribute of the AI Agent tool specified by
|
|
678
|
+
`attribute_name` and `attribute_value`.
|
|
679
|
+
"""
|
|
680
|
+
parameters = {
|
|
681
|
+
"object_name": self.tool_name,
|
|
682
|
+
"object_type": "tool",
|
|
683
|
+
"attribute_name": attribute_name,
|
|
684
|
+
"attribute_value": attribute_value,
|
|
685
|
+
}
|
|
686
|
+
with cursor() as cr:
|
|
687
|
+
cr.callproc(
|
|
688
|
+
"DBMS_CLOUD_AI_AGENT.SET_ATTRIBUTE",
|
|
689
|
+
keyword_parameters=parameters,
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
class AsyncTool(_BaseTool):
|
|
694
|
+
|
|
695
|
+
@staticmethod
|
|
696
|
+
async def _get_attributes(tool_name: str) -> ToolAttributes:
|
|
697
|
+
"""Get attributes of an AI tool
|
|
698
|
+
|
|
699
|
+
:return: select_ai.agent.ToolAttributes
|
|
700
|
+
:raises: AgentToolNotFoundError
|
|
701
|
+
"""
|
|
702
|
+
async with async_cursor() as cr:
|
|
703
|
+
await cr.execute(
|
|
704
|
+
GET_USER_AI_AGENT_TOOL_ATTRIBUTES, tool_name=tool_name.upper()
|
|
705
|
+
)
|
|
706
|
+
attributes = await cr.fetchall()
|
|
707
|
+
if attributes:
|
|
708
|
+
post_processed_attributes = {}
|
|
709
|
+
for k, v in attributes:
|
|
710
|
+
if isinstance(v, oracledb.AsyncLOB):
|
|
711
|
+
post_processed_attributes[k] = await v.read()
|
|
712
|
+
else:
|
|
713
|
+
post_processed_attributes[k] = v
|
|
714
|
+
return ToolAttributes.create(**post_processed_attributes)
|
|
715
|
+
else:
|
|
716
|
+
raise AgentToolNotFoundError(tool_name=tool_name)
|
|
717
|
+
|
|
718
|
+
@staticmethod
|
|
719
|
+
async def _get_description(tool_name: str) -> Union[str, None]:
|
|
720
|
+
async with async_cursor() as cr:
|
|
721
|
+
await cr.execute(
|
|
722
|
+
GET_USER_AI_AGENT_TOOL, tool_name=tool_name.upper()
|
|
723
|
+
)
|
|
724
|
+
tool = await cr.fetchone()
|
|
725
|
+
if tool:
|
|
726
|
+
if tool[1] is not None:
|
|
727
|
+
return await tool[1].read()
|
|
728
|
+
else:
|
|
729
|
+
return None
|
|
730
|
+
else:
|
|
731
|
+
raise AgentToolNotFoundError(tool_name=tool_name)
|
|
732
|
+
|
|
733
|
+
async def create(
|
|
734
|
+
self, enabled: Optional[bool] = True, replace: Optional[bool] = False
|
|
735
|
+
):
|
|
736
|
+
if self.tool_name is None:
|
|
737
|
+
raise AttributeError("Tool must have a name")
|
|
738
|
+
if self.attributes is None:
|
|
739
|
+
raise AttributeError("Tool must have attributes")
|
|
740
|
+
|
|
741
|
+
parameters = {
|
|
742
|
+
"tool_name": self.tool_name,
|
|
743
|
+
"attributes": self.attributes.json(),
|
|
744
|
+
}
|
|
745
|
+
if self.description:
|
|
746
|
+
parameters["description"] = self.description
|
|
747
|
+
|
|
748
|
+
if not enabled:
|
|
749
|
+
parameters["status"] = "disabled"
|
|
750
|
+
|
|
751
|
+
async with async_cursor() as cr:
|
|
752
|
+
try:
|
|
753
|
+
await cr.callproc(
|
|
754
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TOOL",
|
|
755
|
+
keyword_parameters=parameters,
|
|
756
|
+
)
|
|
757
|
+
except oracledb.Error as err:
|
|
758
|
+
(err_obj,) = err.args
|
|
759
|
+
if err_obj.code in (20050, 20052) and replace:
|
|
760
|
+
await self.delete(force=True)
|
|
761
|
+
await cr.callproc(
|
|
762
|
+
"DBMS_CLOUD_AI_AGENT.CREATE_TOOL",
|
|
763
|
+
keyword_parameters=parameters,
|
|
764
|
+
)
|
|
765
|
+
else:
|
|
766
|
+
raise
|
|
767
|
+
|
|
768
|
+
@classmethod
|
|
769
|
+
async def create_built_in_tool(
|
|
770
|
+
cls,
|
|
771
|
+
tool_name: str,
|
|
772
|
+
tool_params: ToolParams,
|
|
773
|
+
tool_type: ToolType,
|
|
774
|
+
description: Optional[str] = None,
|
|
775
|
+
replace: Optional[bool] = False,
|
|
776
|
+
) -> "AsyncTool":
|
|
777
|
+
"""
|
|
778
|
+
Register a built-in tool
|
|
779
|
+
|
|
780
|
+
:param str tool_name: The name of the tool
|
|
781
|
+
:param select_ai.agent.ToolParams tool_params:
|
|
782
|
+
Parameters required by built-in tool
|
|
783
|
+
:param select_ai.agent.ToolType tool_type: The built-in tool type
|
|
784
|
+
:param str description: Description of the tool
|
|
785
|
+
:param bool replace: Whether to replace the existing tool.
|
|
786
|
+
Default value is False
|
|
787
|
+
|
|
788
|
+
:return: select_ai.agent.Tool
|
|
789
|
+
"""
|
|
790
|
+
if not isinstance(tool_params, ToolParams):
|
|
791
|
+
raise TypeError(
|
|
792
|
+
"'tool_params' must be an object of "
|
|
793
|
+
"type select_ai.agent.ToolParams"
|
|
794
|
+
)
|
|
795
|
+
attributes = ToolAttributes(
|
|
796
|
+
tool_params=tool_params, tool_type=tool_type
|
|
797
|
+
)
|
|
798
|
+
tool = cls(
|
|
799
|
+
tool_name=tool_name, attributes=attributes, description=description
|
|
800
|
+
)
|
|
801
|
+
await tool.create(replace=replace)
|
|
802
|
+
return tool
|
|
803
|
+
|
|
804
|
+
@classmethod
|
|
805
|
+
async def create_email_notification_tool(
|
|
806
|
+
cls,
|
|
807
|
+
tool_name: str,
|
|
808
|
+
credential_name: str,
|
|
809
|
+
recipient: str,
|
|
810
|
+
sender: str,
|
|
811
|
+
smtp_host: str,
|
|
812
|
+
description: Optional[str],
|
|
813
|
+
replace: bool = False,
|
|
814
|
+
) -> "AsyncTool":
|
|
815
|
+
"""
|
|
816
|
+
Register an email notification tool
|
|
817
|
+
|
|
818
|
+
:param str tool_name: The name of the tool
|
|
819
|
+
:param str credential_name: The name of the credential
|
|
820
|
+
:param str recipient: The recipient of the email
|
|
821
|
+
:param str sender: The sender of the email
|
|
822
|
+
:param str smtp_host: The SMTP host of the email server
|
|
823
|
+
:param str description: The description of the tool
|
|
824
|
+
:param bool replace: Whether to replace the existing tool.
|
|
825
|
+
Default value is False
|
|
826
|
+
|
|
827
|
+
:return: select_ai.agent.Tool
|
|
828
|
+
|
|
829
|
+
"""
|
|
830
|
+
email_notification_tool_params = EmailNotificationToolParams(
|
|
831
|
+
credential_name=credential_name,
|
|
832
|
+
recipient=recipient,
|
|
833
|
+
sender=sender,
|
|
834
|
+
smtp_host=smtp_host,
|
|
835
|
+
)
|
|
836
|
+
return await cls.create_built_in_tool(
|
|
837
|
+
tool_name=tool_name,
|
|
838
|
+
tool_type=ToolType.EMAIL,
|
|
839
|
+
tool_params=email_notification_tool_params,
|
|
840
|
+
description=description,
|
|
841
|
+
replace=replace,
|
|
842
|
+
)
|
|
843
|
+
|
|
844
|
+
@classmethod
|
|
845
|
+
async def create_http_tool(
|
|
846
|
+
cls,
|
|
847
|
+
tool_name: str,
|
|
848
|
+
credential_name: str,
|
|
849
|
+
endpoint: str,
|
|
850
|
+
description: Optional[str] = None,
|
|
851
|
+
replace: bool = False,
|
|
852
|
+
) -> "AsyncTool":
|
|
853
|
+
http_tool_params = HTTPToolParams(
|
|
854
|
+
credential_name=credential_name, endpoint=endpoint
|
|
855
|
+
)
|
|
856
|
+
return await cls.create_built_in_tool(
|
|
857
|
+
tool_name=tool_name,
|
|
858
|
+
tool_type=ToolType.HTTP,
|
|
859
|
+
tool_params=http_tool_params,
|
|
860
|
+
description=description,
|
|
861
|
+
replace=replace,
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
@classmethod
|
|
865
|
+
async def create_pl_sql_tool(
|
|
866
|
+
cls,
|
|
867
|
+
tool_name: str,
|
|
868
|
+
function: str,
|
|
869
|
+
description: Optional[str] = None,
|
|
870
|
+
replace: bool = False,
|
|
871
|
+
) -> "AsyncTool":
|
|
872
|
+
"""
|
|
873
|
+
Create a custom tool to invoke PL/SQL procedure or function
|
|
874
|
+
|
|
875
|
+
:param str tool_name: The name of the tool
|
|
876
|
+
:param str function: The name of the PL/SQL procedure or function
|
|
877
|
+
:param str description: The description of the tool
|
|
878
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
879
|
+
is False
|
|
880
|
+
|
|
881
|
+
"""
|
|
882
|
+
tool_attributes = ToolAttributes(function=function)
|
|
883
|
+
tool = cls(
|
|
884
|
+
tool_name=tool_name,
|
|
885
|
+
attributes=tool_attributes,
|
|
886
|
+
description=description,
|
|
887
|
+
)
|
|
888
|
+
await tool.create(replace=replace)
|
|
889
|
+
return tool
|
|
890
|
+
|
|
891
|
+
@classmethod
|
|
892
|
+
async def create_rag_tool(
|
|
893
|
+
cls,
|
|
894
|
+
tool_name: str,
|
|
895
|
+
profile_name: str,
|
|
896
|
+
description: Optional[str] = None,
|
|
897
|
+
replace: bool = False,
|
|
898
|
+
) -> "AsyncTool":
|
|
899
|
+
"""
|
|
900
|
+
Register a RAG tool, which will use a VectorIndex linked AI Profile
|
|
901
|
+
|
|
902
|
+
:param str tool_name: The name of the tool
|
|
903
|
+
:param str profile_name: The name of the profile to
|
|
904
|
+
use for Vector Index based RAG
|
|
905
|
+
:param str description: The description of the tool
|
|
906
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
907
|
+
is False
|
|
908
|
+
"""
|
|
909
|
+
tool_params = RAGToolParams(profile_name=profile_name)
|
|
910
|
+
return await cls.create_built_in_tool(
|
|
911
|
+
tool_name=tool_name,
|
|
912
|
+
tool_type=ToolType.RAG,
|
|
913
|
+
tool_params=tool_params,
|
|
914
|
+
description=description,
|
|
915
|
+
replace=replace,
|
|
916
|
+
)
|
|
917
|
+
|
|
918
|
+
@classmethod
|
|
919
|
+
async def create_sql_tool(
|
|
920
|
+
cls,
|
|
921
|
+
tool_name: str,
|
|
922
|
+
profile_name: str,
|
|
923
|
+
description: Optional[str] = None,
|
|
924
|
+
replace: bool = False,
|
|
925
|
+
) -> "AsyncTool":
|
|
926
|
+
"""
|
|
927
|
+
Register a SQL tool to perform natural language to SQL translation
|
|
928
|
+
|
|
929
|
+
:param str tool_name: The name of the tool
|
|
930
|
+
:param str profile_name: The name of the profile to use for SQL
|
|
931
|
+
translation
|
|
932
|
+
:param str description: The description of the tool
|
|
933
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
934
|
+
is False
|
|
935
|
+
"""
|
|
936
|
+
tool_params = SQLToolParams(profile_name=profile_name)
|
|
937
|
+
return await cls.create_built_in_tool(
|
|
938
|
+
tool_name=tool_name,
|
|
939
|
+
tool_type=ToolType.SQL,
|
|
940
|
+
tool_params=tool_params,
|
|
941
|
+
description=description,
|
|
942
|
+
replace=replace,
|
|
943
|
+
)
|
|
944
|
+
|
|
945
|
+
@classmethod
|
|
946
|
+
async def create_slack_notification_tool(
|
|
947
|
+
cls,
|
|
948
|
+
tool_name: str,
|
|
949
|
+
credential_name: str,
|
|
950
|
+
slack_channel: str,
|
|
951
|
+
description: Optional[str] = None,
|
|
952
|
+
replace: bool = False,
|
|
953
|
+
) -> "AsyncTool":
|
|
954
|
+
"""
|
|
955
|
+
Register a Slack notification tool
|
|
956
|
+
|
|
957
|
+
:param str tool_name: The name of the Slack notification tool
|
|
958
|
+
:param str credential_name: The name of the Slack credential
|
|
959
|
+
:param str slack_channel: The name of the Slack channel
|
|
960
|
+
:param str description: The description of the Slack notification tool
|
|
961
|
+
:param bool replace: Whether to replace existing tool. Default value
|
|
962
|
+
is False
|
|
963
|
+
|
|
964
|
+
"""
|
|
965
|
+
slack_notification_tool_params = SlackNotificationToolParams(
|
|
966
|
+
credential_name=credential_name,
|
|
967
|
+
slack_channel=slack_channel,
|
|
968
|
+
)
|
|
969
|
+
return await cls.create_built_in_tool(
|
|
970
|
+
tool_name=tool_name,
|
|
971
|
+
tool_type=ToolType.SLACK,
|
|
972
|
+
tool_params=slack_notification_tool_params,
|
|
973
|
+
description=description,
|
|
974
|
+
replace=replace,
|
|
975
|
+
)
|
|
976
|
+
|
|
977
|
+
@classmethod
|
|
978
|
+
async def create_websearch_tool(
|
|
979
|
+
cls,
|
|
980
|
+
tool_name: str,
|
|
981
|
+
credential_name: str,
|
|
982
|
+
description: Optional[str],
|
|
983
|
+
replace: bool = False,
|
|
984
|
+
) -> "AsyncTool":
|
|
985
|
+
"""
|
|
986
|
+
Register a built-in websearch tool to search information
|
|
987
|
+
on the web
|
|
988
|
+
|
|
989
|
+
:param str tool_name: The name of the tool
|
|
990
|
+
:param str credential_name: The name of the credential object
|
|
991
|
+
storing OpenAI credentials
|
|
992
|
+
:param str description: The description of the tool
|
|
993
|
+
:param bool replace: Whether to replace the existing tool
|
|
994
|
+
|
|
995
|
+
"""
|
|
996
|
+
web_search_tool_params = WebSearchToolParams(
|
|
997
|
+
credential_name=credential_name,
|
|
998
|
+
)
|
|
999
|
+
return await cls.create_built_in_tool(
|
|
1000
|
+
tool_name=tool_name,
|
|
1001
|
+
tool_type=ToolType.WEBSEARCH,
|
|
1002
|
+
tool_params=web_search_tool_params,
|
|
1003
|
+
description=description,
|
|
1004
|
+
replace=replace,
|
|
1005
|
+
)
|
|
1006
|
+
|
|
1007
|
+
async def delete(self, force: bool = False):
|
|
1008
|
+
"""
|
|
1009
|
+
Delete AI Tool from the database
|
|
1010
|
+
|
|
1011
|
+
:param bool force: Force the deletion. Default value is False.
|
|
1012
|
+
"""
|
|
1013
|
+
async with async_cursor() as cr:
|
|
1014
|
+
await cr.callproc(
|
|
1015
|
+
"DBMS_CLOUD_AI_AGENT.DROP_TOOL",
|
|
1016
|
+
keyword_parameters={
|
|
1017
|
+
"tool_name": self.tool_name,
|
|
1018
|
+
"force": force,
|
|
1019
|
+
},
|
|
1020
|
+
)
|
|
1021
|
+
|
|
1022
|
+
async def disable(self):
|
|
1023
|
+
"""
|
|
1024
|
+
Disable AI Tool
|
|
1025
|
+
"""
|
|
1026
|
+
async with async_cursor() as cr:
|
|
1027
|
+
await cr.callproc(
|
|
1028
|
+
"DBMS_CLOUD_AI_AGENT.DISABLE_TOOL",
|
|
1029
|
+
keyword_parameters={
|
|
1030
|
+
"tool_name": self.tool_name,
|
|
1031
|
+
},
|
|
1032
|
+
)
|
|
1033
|
+
|
|
1034
|
+
async def enable(self):
|
|
1035
|
+
"""
|
|
1036
|
+
Enable AI Tool
|
|
1037
|
+
"""
|
|
1038
|
+
async with async_cursor() as cr:
|
|
1039
|
+
await cr.callproc(
|
|
1040
|
+
"DBMS_CLOUD_AI_AGENT.ENABLE_TOOL",
|
|
1041
|
+
keyword_parameters={
|
|
1042
|
+
"tool_name": self.tool_name,
|
|
1043
|
+
},
|
|
1044
|
+
)
|
|
1045
|
+
|
|
1046
|
+
@classmethod
|
|
1047
|
+
async def fetch(cls, tool_name: str) -> "AsyncTool":
|
|
1048
|
+
"""
|
|
1049
|
+
Fetch AI Tool attributes from the Database and build a proxy object in
|
|
1050
|
+
the Python layer
|
|
1051
|
+
|
|
1052
|
+
:param str tool_name: The name of the AI Task
|
|
1053
|
+
|
|
1054
|
+
:return: select_ai.agent.Tool
|
|
1055
|
+
|
|
1056
|
+
:raises select_ai.errors.AgentToolNotFoundError:
|
|
1057
|
+
If the AI Tool is not found
|
|
1058
|
+
|
|
1059
|
+
"""
|
|
1060
|
+
attributes = await cls._get_attributes(tool_name)
|
|
1061
|
+
description = await cls._get_description(tool_name)
|
|
1062
|
+
return cls(
|
|
1063
|
+
tool_name=tool_name, attributes=attributes, description=description
|
|
1064
|
+
)
|
|
1065
|
+
|
|
1066
|
+
@classmethod
|
|
1067
|
+
async def list(
|
|
1068
|
+
cls, tool_name_pattern: str = ".*"
|
|
1069
|
+
) -> AsyncGenerator["AsyncTool", None]:
|
|
1070
|
+
"""List AI Tools
|
|
1071
|
+
|
|
1072
|
+
:param str tool_name_pattern: Regular expressions can be used
|
|
1073
|
+
to specify a pattern. Function REGEXP_LIKE is used to perform the
|
|
1074
|
+
match. Default value is ".*" i.e. match all tool name.
|
|
1075
|
+
|
|
1076
|
+
:return: Iterator[Tool]
|
|
1077
|
+
"""
|
|
1078
|
+
async with async_cursor() as cr:
|
|
1079
|
+
await cr.execute(
|
|
1080
|
+
LIST_USER_AI_AGENT_TOOLS,
|
|
1081
|
+
tool_name_pattern=tool_name_pattern,
|
|
1082
|
+
)
|
|
1083
|
+
rows = await cr.fetchall()
|
|
1084
|
+
for row in rows:
|
|
1085
|
+
tool_name = row[0]
|
|
1086
|
+
if row[1]:
|
|
1087
|
+
description = await row[1].read() # Oracle.AsyncLOB
|
|
1088
|
+
else:
|
|
1089
|
+
description = None
|
|
1090
|
+
attributes = await cls._get_attributes(tool_name=tool_name)
|
|
1091
|
+
yield cls(
|
|
1092
|
+
tool_name=tool_name,
|
|
1093
|
+
description=description,
|
|
1094
|
+
attributes=attributes,
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1097
|
+
async def set_attributes(self, attributes: ToolAttributes) -> None:
|
|
1098
|
+
"""
|
|
1099
|
+
Set the attributes of the AI Agent tool
|
|
1100
|
+
"""
|
|
1101
|
+
parameters = {
|
|
1102
|
+
"object_name": self.tool_name,
|
|
1103
|
+
"object_type": "tool",
|
|
1104
|
+
"attributes": attributes.json(),
|
|
1105
|
+
}
|
|
1106
|
+
async with async_cursor() as cr:
|
|
1107
|
+
await cr.callproc(
|
|
1108
|
+
"DBMS_CLOUD_AI_AGENT.SET_ATTRIBUTES",
|
|
1109
|
+
keyword_parameters=parameters,
|
|
1110
|
+
)
|
|
1111
|
+
|
|
1112
|
+
async def set_attribute(
|
|
1113
|
+
self, attribute_name: str, attribute_value: Any
|
|
1114
|
+
) -> None:
|
|
1115
|
+
"""
|
|
1116
|
+
Set the attribute of the AI Agent tool specified by
|
|
1117
|
+
`attribute_name` and `attribute_value`.
|
|
1118
|
+
"""
|
|
1119
|
+
parameters = {
|
|
1120
|
+
"object_name": self.tool_name,
|
|
1121
|
+
"object_type": "tool",
|
|
1122
|
+
"attribute_name": attribute_name,
|
|
1123
|
+
"attribute_value": attribute_value,
|
|
1124
|
+
}
|
|
1125
|
+
async with async_cursor() as cr:
|
|
1126
|
+
await cr.callproc(
|
|
1127
|
+
"DBMS_CLOUD_AI_AGENT.SET_ATTRIBUTE",
|
|
1128
|
+
keyword_parameters=parameters,
|
|
1129
|
+
)
|