vectara-agentic 0.3.3__py3-none-any.whl → 0.4.0__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 vectara-agentic might be problematic. Click here for more details.
- tests/__init__.py +7 -0
- tests/conftest.py +312 -0
- tests/endpoint.py +54 -17
- tests/run_tests.py +111 -0
- tests/test_agent.py +10 -5
- tests/test_agent_type.py +82 -143
- tests/test_api_endpoint.py +4 -0
- tests/test_bedrock.py +4 -0
- tests/test_fallback.py +4 -0
- tests/test_gemini.py +28 -45
- tests/test_groq.py +4 -0
- tests/test_private_llm.py +11 -2
- tests/test_return_direct.py +6 -2
- tests/test_serialization.py +4 -0
- tests/test_streaming.py +88 -0
- tests/test_tools.py +10 -82
- tests/test_vectara_llms.py +4 -0
- tests/test_vhc.py +66 -0
- tests/test_workflow.py +4 -0
- vectara_agentic/__init__.py +27 -4
- vectara_agentic/_callback.py +65 -67
- vectara_agentic/_observability.py +30 -30
- vectara_agentic/_version.py +1 -1
- vectara_agentic/agent.py +375 -848
- vectara_agentic/agent_config.py +15 -14
- vectara_agentic/agent_core/__init__.py +22 -0
- vectara_agentic/agent_core/factory.py +501 -0
- vectara_agentic/{_prompts.py → agent_core/prompts.py} +3 -35
- vectara_agentic/agent_core/serialization.py +345 -0
- vectara_agentic/agent_core/streaming.py +495 -0
- vectara_agentic/agent_core/utils/__init__.py +34 -0
- vectara_agentic/agent_core/utils/hallucination.py +202 -0
- vectara_agentic/agent_core/utils/logging.py +52 -0
- vectara_agentic/agent_core/utils/prompt_formatting.py +56 -0
- vectara_agentic/agent_core/utils/schemas.py +87 -0
- vectara_agentic/agent_core/utils/tools.py +125 -0
- vectara_agentic/agent_endpoint.py +4 -6
- vectara_agentic/db_tools.py +37 -12
- vectara_agentic/llm_utils.py +41 -42
- vectara_agentic/sub_query_workflow.py +9 -14
- vectara_agentic/tool_utils.py +138 -83
- vectara_agentic/tools.py +36 -21
- vectara_agentic/tools_catalog.py +16 -16
- vectara_agentic/types.py +98 -6
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/METADATA +69 -30
- vectara_agentic-0.4.0.dist-info/RECORD +50 -0
- tests/test_agent_planning.py +0 -64
- tests/test_hhem.py +0 -100
- vectara_agentic/hhem.py +0 -82
- vectara_agentic-0.3.3.dist-info/RECORD +0 -39
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/WHEEL +0 -0
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/top_level.txt +0 -0
vectara_agentic/tool_utils.py
CHANGED
|
@@ -4,6 +4,7 @@ This module contains the ToolsFactory class for creating agent tools.
|
|
|
4
4
|
|
|
5
5
|
import inspect
|
|
6
6
|
import re
|
|
7
|
+
import traceback
|
|
7
8
|
|
|
8
9
|
from typing import (
|
|
9
10
|
Callable,
|
|
@@ -17,7 +18,7 @@ from typing import (
|
|
|
17
18
|
get_origin,
|
|
18
19
|
get_args,
|
|
19
20
|
)
|
|
20
|
-
from pydantic import BaseModel, create_model
|
|
21
|
+
from pydantic import BaseModel, create_model, Field
|
|
21
22
|
from pydantic_core import PydanticUndefined
|
|
22
23
|
|
|
23
24
|
from llama_index.core.tools import FunctionTool
|
|
@@ -31,21 +32,26 @@ from .utils import is_float
|
|
|
31
32
|
|
|
32
33
|
class VectaraToolMetadata(ToolMetadata):
|
|
33
34
|
"""
|
|
34
|
-
A subclass of ToolMetadata adding the tool_type
|
|
35
|
+
A subclass of ToolMetadata adding the tool_type and vhc_eligible attributes.
|
|
35
36
|
"""
|
|
36
37
|
|
|
37
38
|
tool_type: ToolType
|
|
39
|
+
vhc_eligible: bool
|
|
38
40
|
|
|
39
|
-
def __init__(self, tool_type: ToolType, **kwargs):
|
|
41
|
+
def __init__(self, tool_type: ToolType, vhc_eligible: bool = True, **kwargs):
|
|
40
42
|
super().__init__(**kwargs)
|
|
41
43
|
self.tool_type = tool_type
|
|
44
|
+
self.vhc_eligible = vhc_eligible
|
|
42
45
|
|
|
43
46
|
def __repr__(self) -> str:
|
|
44
47
|
"""
|
|
45
|
-
Returns a string representation of the VectaraToolMetadata object,
|
|
48
|
+
Returns a string representation of the VectaraToolMetadata object,
|
|
49
|
+
including the tool_type and vhc_eligible attributes.
|
|
46
50
|
"""
|
|
47
51
|
base_repr = super().__repr__()
|
|
48
|
-
return
|
|
52
|
+
return (
|
|
53
|
+
f"{base_repr}, tool_type={self.tool_type}, vhc_eligible={self.vhc_eligible}"
|
|
54
|
+
)
|
|
49
55
|
|
|
50
56
|
|
|
51
57
|
class VectaraTool(FunctionTool):
|
|
@@ -59,11 +65,17 @@ class VectaraTool(FunctionTool):
|
|
|
59
65
|
metadata: ToolMetadata,
|
|
60
66
|
fn: Optional[Callable[..., Any]] = None,
|
|
61
67
|
async_fn: Optional[AsyncCallable] = None,
|
|
68
|
+
vhc_eligible: bool = True,
|
|
62
69
|
) -> None:
|
|
70
|
+
# Use Pydantic v2 compatible method for extracting metadata
|
|
63
71
|
metadata_dict = (
|
|
64
|
-
metadata.
|
|
72
|
+
metadata.model_dump()
|
|
73
|
+
if hasattr(metadata, "model_dump")
|
|
74
|
+
else metadata.dict() if hasattr(metadata, "dict") else metadata.__dict__
|
|
75
|
+
)
|
|
76
|
+
vm = VectaraToolMetadata(
|
|
77
|
+
tool_type=tool_type, vhc_eligible=vhc_eligible, **metadata_dict
|
|
65
78
|
)
|
|
66
|
-
vm = VectaraToolMetadata(tool_type=tool_type, **metadata_dict)
|
|
67
79
|
super().__init__(fn, vm, async_fn)
|
|
68
80
|
|
|
69
81
|
@classmethod
|
|
@@ -80,6 +92,7 @@ class VectaraTool(FunctionTool):
|
|
|
80
92
|
async_callback: Optional[AsyncCallable] = None,
|
|
81
93
|
partial_params: Optional[Dict[str, Any]] = None,
|
|
82
94
|
tool_type: ToolType = ToolType.QUERY,
|
|
95
|
+
vhc_eligible: bool = True,
|
|
83
96
|
) -> "VectaraTool":
|
|
84
97
|
tool = FunctionTool.from_defaults(
|
|
85
98
|
fn,
|
|
@@ -98,6 +111,7 @@ class VectaraTool(FunctionTool):
|
|
|
98
111
|
fn=tool.fn,
|
|
99
112
|
metadata=tool.metadata,
|
|
100
113
|
async_fn=tool.async_fn,
|
|
114
|
+
vhc_eligible=vhc_eligible,
|
|
101
115
|
)
|
|
102
116
|
return vectara_tool
|
|
103
117
|
|
|
@@ -123,94 +137,82 @@ class VectaraTool(FunctionTool):
|
|
|
123
137
|
)
|
|
124
138
|
return is_equal
|
|
125
139
|
|
|
126
|
-
def
|
|
127
|
-
self,
|
|
140
|
+
def _create_tool_error_output(
|
|
141
|
+
self, error: Exception, args: Any, kwargs: Any, include_traceback: bool = False
|
|
128
142
|
) -> ToolOutput:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
except TypeError as e:
|
|
143
|
+
"""Create standardized error output for tool execution failures."""
|
|
144
|
+
if isinstance(error, TypeError):
|
|
145
|
+
# Parameter validation error handling
|
|
133
146
|
sig = inspect.signature(self.metadata.fn_schema)
|
|
134
147
|
valid_parameters = list(sig.parameters.keys())
|
|
135
148
|
params_str = ", ".join(valid_parameters)
|
|
136
|
-
|
|
137
|
-
err_output = ToolOutput(
|
|
149
|
+
return ToolOutput(
|
|
138
150
|
tool_name=self.metadata.name,
|
|
139
151
|
content=(
|
|
140
|
-
f"Wrong argument used when calling {self.metadata.name}: {str(
|
|
141
|
-
f"Valid arguments: {params_str}.
|
|
152
|
+
f"Wrong argument used when calling {self.metadata.name}: {str(error)}. "
|
|
153
|
+
f"Valid arguments: {params_str}. Please call the tool again with the correct arguments."
|
|
142
154
|
),
|
|
143
155
|
raw_input={"args": args, "kwargs": kwargs},
|
|
144
|
-
raw_output={"response": str(
|
|
156
|
+
raw_output={"response": str(error)},
|
|
145
157
|
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
158
|
+
else:
|
|
159
|
+
# General execution error handling
|
|
160
|
+
content = f"Tool {self.metadata.name} Malfunction: {str(error)}"
|
|
161
|
+
if include_traceback:
|
|
162
|
+
content += f", traceback: {traceback.format_exc()}"
|
|
163
|
+
|
|
164
|
+
return ToolOutput(
|
|
149
165
|
tool_name=self.metadata.name,
|
|
150
|
-
content=
|
|
166
|
+
content=content,
|
|
151
167
|
raw_input={"args": args, "kwargs": kwargs},
|
|
152
|
-
raw_output={"response": str(
|
|
168
|
+
raw_output={"response": str(error)},
|
|
153
169
|
)
|
|
154
|
-
return err_output
|
|
155
170
|
|
|
156
|
-
|
|
171
|
+
def call(
|
|
157
172
|
self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
|
|
158
173
|
) -> ToolOutput:
|
|
159
174
|
try:
|
|
160
|
-
|
|
175
|
+
# Only pass ctx if it's not None to avoid passing unwanted kwargs to the function
|
|
176
|
+
if ctx is not None:
|
|
177
|
+
result = super().call(*args, ctx=ctx, **kwargs)
|
|
178
|
+
else:
|
|
179
|
+
result = super().call(*args, **kwargs)
|
|
161
180
|
return self._format_tool_output(result)
|
|
162
|
-
except TypeError as e:
|
|
163
|
-
sig = inspect.signature(self.metadata.fn_schema)
|
|
164
|
-
valid_parameters = list(sig.parameters.keys())
|
|
165
|
-
params_str = ", ".join(valid_parameters)
|
|
166
|
-
|
|
167
|
-
err_output = ToolOutput(
|
|
168
|
-
tool_name=self.metadata.name,
|
|
169
|
-
content=(
|
|
170
|
-
f"Wrong argument used when calling {self.metadata.name}: {str(e)}. "
|
|
171
|
-
f"Valid arguments: {params_str}. please call the tool again with the correct arguments."
|
|
172
|
-
),
|
|
173
|
-
raw_input={"args": args, "kwargs": kwargs},
|
|
174
|
-
raw_output={"response": str(e)},
|
|
175
|
-
)
|
|
176
|
-
return err_output
|
|
177
181
|
except Exception as e:
|
|
178
|
-
|
|
182
|
+
return self._create_tool_error_output(e, args, kwargs)
|
|
179
183
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
async def acall(
|
|
185
|
+
self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
|
|
186
|
+
) -> ToolOutput:
|
|
187
|
+
try:
|
|
188
|
+
# Only pass ctx if it's not None to avoid passing unwanted kwargs to the function
|
|
189
|
+
if ctx is not None:
|
|
190
|
+
result = await super().acall(*args, ctx=ctx, **kwargs)
|
|
191
|
+
else:
|
|
192
|
+
result = await super().acall(*args, **kwargs)
|
|
193
|
+
return self._format_tool_output(result)
|
|
194
|
+
except Exception as e:
|
|
195
|
+
return self._create_tool_error_output(
|
|
196
|
+
e, args, kwargs, include_traceback=True
|
|
185
197
|
)
|
|
186
|
-
return err_output
|
|
187
198
|
|
|
188
199
|
def _format_tool_output(self, result: ToolOutput) -> ToolOutput:
|
|
189
|
-
"""Format tool output
|
|
190
|
-
|
|
200
|
+
"""Format tool output by converting human-readable wrappers to formatted content immediately."""
|
|
201
|
+
import logging
|
|
202
|
+
|
|
203
|
+
# If the raw_output has human-readable formatting, use it for the content
|
|
204
|
+
if hasattr(result, "raw_output") and _is_human_readable_output(
|
|
205
|
+
result.raw_output
|
|
206
|
+
):
|
|
191
207
|
try:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
return ToolOutput(
|
|
196
|
-
tool_name=result.tool_name,
|
|
197
|
-
content=human_readable_content,
|
|
198
|
-
raw_input=result.raw_input,
|
|
199
|
-
raw_output=raw_output,
|
|
200
|
-
)
|
|
208
|
+
formatted_content = result.raw_output.to_human_readable()
|
|
209
|
+
# Replace the content with the formatted version
|
|
210
|
+
result.content = formatted_content
|
|
201
211
|
except Exception as e:
|
|
202
|
-
# If formatting fails, fall back to original content with error info
|
|
203
|
-
import logging
|
|
204
|
-
|
|
205
212
|
logging.warning(
|
|
206
|
-
f"Failed to
|
|
207
|
-
)
|
|
208
|
-
return ToolOutput(
|
|
209
|
-
tool_name=result.tool_name,
|
|
210
|
-
content=f"[Formatting Error] {str(result.content)}",
|
|
211
|
-
raw_input=result.raw_input,
|
|
212
|
-
raw_output={"error": str(e), "original_content": result.content},
|
|
213
|
+
f"{self.metadata.name}: Failed to convert to human-readable: {e}"
|
|
213
214
|
)
|
|
215
|
+
|
|
214
216
|
return result
|
|
215
217
|
|
|
216
218
|
|
|
@@ -257,7 +259,6 @@ def _make_docstring(
|
|
|
257
259
|
tool_description: str,
|
|
258
260
|
fn_schema: Type[BaseModel],
|
|
259
261
|
all_params: List[inspect.Parameter],
|
|
260
|
-
compact_docstring: bool,
|
|
261
262
|
) -> str:
|
|
262
263
|
"""
|
|
263
264
|
Generates a docstring for a function based on its signature, description,
|
|
@@ -269,7 +270,6 @@ def _make_docstring(
|
|
|
269
270
|
tool_description: The main description of the tool/function.
|
|
270
271
|
fn_schema: The Pydantic model representing the function's arguments schema.
|
|
271
272
|
all_params: A list of inspect.Parameter objects for the function signature.
|
|
272
|
-
compact_docstring: If True, omits the signature line in the main description.
|
|
273
273
|
|
|
274
274
|
Returns:
|
|
275
275
|
A formatted docstring string.
|
|
@@ -282,10 +282,7 @@ def _make_docstring(
|
|
|
282
282
|
params_str = ", ".join(params_str_parts)
|
|
283
283
|
signature_line = f"{tool_name}({params_str}) -> dict[str, Any]"
|
|
284
284
|
|
|
285
|
-
|
|
286
|
-
doc_lines = [tool_description.strip()]
|
|
287
|
-
else:
|
|
288
|
-
doc_lines = [signature_line, "", tool_description.strip()]
|
|
285
|
+
doc_lines = [signature_line, "", tool_description.strip()]
|
|
289
286
|
|
|
290
287
|
full_schema = fn_schema.model_json_schema()
|
|
291
288
|
props = full_schema.get("properties", {})
|
|
@@ -339,14 +336,61 @@ def _make_docstring(
|
|
|
339
336
|
return final_docstring
|
|
340
337
|
|
|
341
338
|
|
|
339
|
+
def _auto_fix_field_if_needed(
|
|
340
|
+
field_name: str, field_info, annotation
|
|
341
|
+
) -> Tuple[Any, Any]:
|
|
342
|
+
"""
|
|
343
|
+
Auto-fix problematic Field definitions: convert non-Optional types with any default value to Optional.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
field_name: Name of the field
|
|
347
|
+
field_info: The Pydantic FieldInfo object
|
|
348
|
+
annotation: The type annotation for the field
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
Tuple of (possibly_modified_annotation, possibly_modified_field_info)
|
|
352
|
+
"""
|
|
353
|
+
# Check for problematic pattern: non-Optional type with any default value
|
|
354
|
+
if (
|
|
355
|
+
field_info.default is not PydanticUndefined
|
|
356
|
+
and annotation is not None
|
|
357
|
+
and get_origin(annotation) is not Union
|
|
358
|
+
):
|
|
359
|
+
|
|
360
|
+
# Convert to Optional[OriginalType] and keep the original default value
|
|
361
|
+
new_annotation = Union[annotation, type(None)]
|
|
362
|
+
# Create new field_info preserving the original default value
|
|
363
|
+
new_field_info = Field(
|
|
364
|
+
default=field_info.default,
|
|
365
|
+
description=field_info.description,
|
|
366
|
+
examples=getattr(field_info, "examples", None),
|
|
367
|
+
title=getattr(field_info, "title", None),
|
|
368
|
+
alias=getattr(field_info, "alias", None),
|
|
369
|
+
json_schema_extra=getattr(field_info, "json_schema_extra", None),
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
# Optional: Log the auto-fix for debugging
|
|
373
|
+
import logging
|
|
374
|
+
|
|
375
|
+
logging.debug(
|
|
376
|
+
f"Auto-fixed field '{field_name}': "
|
|
377
|
+
f"converted {annotation} with default={field_info.default} to Optional[{annotation.__name__}]"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
return new_annotation, new_field_info
|
|
381
|
+
else:
|
|
382
|
+
# Keep original field definition
|
|
383
|
+
return annotation, field_info
|
|
384
|
+
|
|
385
|
+
|
|
342
386
|
def create_tool_from_dynamic_function(
|
|
343
387
|
function: Callable[..., ToolOutput],
|
|
344
388
|
tool_name: str,
|
|
345
389
|
tool_description: str,
|
|
346
390
|
base_params_model: Type[BaseModel],
|
|
347
391
|
tool_args_schema: Type[BaseModel],
|
|
348
|
-
compact_docstring: bool = False,
|
|
349
392
|
return_direct: bool = False,
|
|
393
|
+
vhc_eligible: bool = True,
|
|
350
394
|
) -> VectaraTool:
|
|
351
395
|
"""
|
|
352
396
|
Create a VectaraTool from a dynamic function.
|
|
@@ -356,7 +400,7 @@ def create_tool_from_dynamic_function(
|
|
|
356
400
|
tool_description (str): The description of the tool.
|
|
357
401
|
base_params_model (Type[BaseModel]): The Pydantic model for the base parameters.
|
|
358
402
|
tool_args_schema (Type[BaseModel]): The Pydantic model for the tool arguments.
|
|
359
|
-
|
|
403
|
+
return_direct (bool): Whether to return the tool output directly.
|
|
360
404
|
Returns:
|
|
361
405
|
VectaraTool: The created VectaraTool.
|
|
362
406
|
"""
|
|
@@ -371,6 +415,11 @@ def create_tool_from_dynamic_function(
|
|
|
371
415
|
fields: Dict[str, Any] = {}
|
|
372
416
|
base_params = []
|
|
373
417
|
for field_name, field_info in base_params_model.model_fields.items():
|
|
418
|
+
# Apply auto-conversion if needed
|
|
419
|
+
annotation, field_info = _auto_fix_field_if_needed(
|
|
420
|
+
field_name, field_info, field_info.annotation
|
|
421
|
+
)
|
|
422
|
+
|
|
374
423
|
default = (
|
|
375
424
|
Ellipsis if field_info.default is PydanticUndefined else field_info.default
|
|
376
425
|
)
|
|
@@ -378,16 +427,21 @@ def create_tool_from_dynamic_function(
|
|
|
378
427
|
field_name,
|
|
379
428
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
380
429
|
default=default if default is not Ellipsis else inspect.Parameter.empty,
|
|
381
|
-
annotation=
|
|
430
|
+
annotation=annotation,
|
|
382
431
|
)
|
|
383
432
|
base_params.append(param)
|
|
384
|
-
fields[field_name] = (
|
|
433
|
+
fields[field_name] = (annotation, field_info)
|
|
385
434
|
|
|
386
435
|
# Add tool_args_schema fields to the fields dict if not already included.
|
|
387
436
|
for field_name, field_info in tool_args_schema.model_fields.items():
|
|
388
437
|
if field_name in fields:
|
|
389
438
|
continue
|
|
390
439
|
|
|
440
|
+
# Apply auto-conversion if needed
|
|
441
|
+
annotation, field_info = _auto_fix_field_if_needed(
|
|
442
|
+
field_name, field_info, field_info.annotation
|
|
443
|
+
)
|
|
444
|
+
|
|
391
445
|
default = (
|
|
392
446
|
Ellipsis if field_info.default is PydanticUndefined else field_info.default
|
|
393
447
|
)
|
|
@@ -395,12 +449,12 @@ def create_tool_from_dynamic_function(
|
|
|
395
449
|
field_name,
|
|
396
450
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
397
451
|
default=default if default is not Ellipsis else inspect.Parameter.empty,
|
|
398
|
-
annotation=
|
|
452
|
+
annotation=annotation,
|
|
399
453
|
)
|
|
400
454
|
base_params.append(param)
|
|
401
|
-
fields[field_name] = (
|
|
455
|
+
fields[field_name] = (annotation, field_info)
|
|
402
456
|
|
|
403
|
-
# Create the dynamic schema with both base_params_model and tool_args_schema fields
|
|
457
|
+
# Create the dynamic schema with both base_params_model and tool_args_schema fields (auto-fixed)
|
|
404
458
|
fn_schema = create_model(f"{tool_name}_schema", **fields)
|
|
405
459
|
|
|
406
460
|
# Combine parameters into a function signature.
|
|
@@ -414,7 +468,7 @@ def create_tool_from_dynamic_function(
|
|
|
414
468
|
function.__name__ = re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
|
|
415
469
|
|
|
416
470
|
function.__doc__ = _make_docstring(
|
|
417
|
-
function, tool_name, tool_description, fn_schema, all_params
|
|
471
|
+
function, tool_name, tool_description, fn_schema, all_params
|
|
418
472
|
)
|
|
419
473
|
tool = VectaraTool.from_defaults(
|
|
420
474
|
fn=function,
|
|
@@ -423,6 +477,7 @@ def create_tool_from_dynamic_function(
|
|
|
423
477
|
fn_schema=fn_schema,
|
|
424
478
|
tool_type=ToolType.QUERY,
|
|
425
479
|
return_direct=return_direct,
|
|
480
|
+
vhc_eligible=vhc_eligible,
|
|
426
481
|
)
|
|
427
482
|
return tool
|
|
428
483
|
|
vectara_agentic/tools.py
CHANGED
|
@@ -74,20 +74,16 @@ class VectaraToolFactory:
|
|
|
74
74
|
self,
|
|
75
75
|
vectara_corpus_key: str = str(os.environ.get("VECTARA_CORPUS_KEY", "")),
|
|
76
76
|
vectara_api_key: str = str(os.environ.get("VECTARA_API_KEY", "")),
|
|
77
|
-
compact_docstring: bool = False,
|
|
78
77
|
) -> None:
|
|
79
78
|
"""
|
|
80
79
|
Initialize the VectaraToolFactory
|
|
81
80
|
Args:
|
|
82
81
|
vectara_corpus_key (str): The Vectara corpus key (or comma separated list of keys).
|
|
83
82
|
vectara_api_key (str): The Vectara API key.
|
|
84
|
-
compact_docstring (bool): Whether to use a compact docstring format for tools
|
|
85
|
-
This is useful if OpenAI complains on the 1024 token limit.
|
|
86
83
|
"""
|
|
87
84
|
self.vectara_corpus_key = vectara_corpus_key
|
|
88
85
|
self.vectara_api_key = vectara_api_key
|
|
89
86
|
self.num_corpora = len(vectara_corpus_key.split(","))
|
|
90
|
-
self.compact_docstring = compact_docstring
|
|
91
87
|
|
|
92
88
|
def create_search_tool(
|
|
93
89
|
self,
|
|
@@ -116,6 +112,7 @@ class VectaraToolFactory:
|
|
|
116
112
|
verbose: bool = False,
|
|
117
113
|
vectara_base_url: str = "https://api.vectara.io",
|
|
118
114
|
vectara_verify_ssl: bool = True,
|
|
115
|
+
vhc_eligible: bool = True,
|
|
119
116
|
) -> VectaraTool:
|
|
120
117
|
"""
|
|
121
118
|
Creates a Vectara search/retrieval tool
|
|
@@ -280,7 +277,7 @@ class VectaraToolFactory:
|
|
|
280
277
|
# Add all matching text if available
|
|
281
278
|
matches = result["metadata"]["matching_text"]
|
|
282
279
|
if matches:
|
|
283
|
-
result_str +=
|
|
280
|
+
result_str += "".join(
|
|
284
281
|
f"Match #{inx} Text: {match}\n"
|
|
285
282
|
for inx, match in enumerate(matches, 1)
|
|
286
283
|
)
|
|
@@ -312,7 +309,7 @@ class VectaraToolFactory:
|
|
|
312
309
|
description="The search query to perform, in the form of a question.",
|
|
313
310
|
)
|
|
314
311
|
top_k: int = Field(
|
|
315
|
-
10, description="The number of top documents to retrieve."
|
|
312
|
+
default=10, description="The number of top documents to retrieve."
|
|
316
313
|
)
|
|
317
314
|
|
|
318
315
|
search_tool_extra_desc = (
|
|
@@ -331,8 +328,8 @@ class VectaraToolFactory:
|
|
|
331
328
|
else SearchToolBaseParamsWithoutSummarize
|
|
332
329
|
),
|
|
333
330
|
tool_args_schema,
|
|
334
|
-
compact_docstring=self.compact_docstring,
|
|
335
331
|
return_direct=return_direct,
|
|
332
|
+
vhc_eligible=vhc_eligible,
|
|
336
333
|
)
|
|
337
334
|
return tool
|
|
338
335
|
|
|
@@ -376,6 +373,7 @@ class VectaraToolFactory:
|
|
|
376
373
|
verbose: bool = False,
|
|
377
374
|
vectara_base_url: str = "https://api.vectara.io",
|
|
378
375
|
vectara_verify_ssl: bool = True,
|
|
376
|
+
vhc_eligible: bool = True,
|
|
379
377
|
) -> VectaraTool:
|
|
380
378
|
"""
|
|
381
379
|
Creates a RAG (Retrieve and Generate) tool.
|
|
@@ -426,7 +424,7 @@ class VectaraToolFactory:
|
|
|
426
424
|
citation_url_pattern (str, optional): The pattern for the citations in the response.
|
|
427
425
|
Default is "{doc.url}" which uses the document URL.
|
|
428
426
|
If include_citations is False, this parameter is ignored.
|
|
429
|
-
citation_pattern (str, optional): old name for citation_url_pattern.
|
|
427
|
+
citation_pattern (str, optional): old name for citation_url_pattern. Deprecated.
|
|
430
428
|
citation_text_pattern (str, optional): The text pattern for citations in the response.
|
|
431
429
|
Default is "{doc.title}" which uses the title of the document.
|
|
432
430
|
If include_citations is False, this parameter is ignored.
|
|
@@ -475,6 +473,15 @@ class VectaraToolFactory:
|
|
|
475
473
|
)
|
|
476
474
|
return {"text": msg, "metadata": {"args": args, "kwargs": kwargs}}
|
|
477
475
|
|
|
476
|
+
citations_url_pattern = (
|
|
477
|
+
(
|
|
478
|
+
citation_url_pattern
|
|
479
|
+
if citation_url_pattern is not None
|
|
480
|
+
else citation_pattern
|
|
481
|
+
)
|
|
482
|
+
if include_citations
|
|
483
|
+
else None
|
|
484
|
+
)
|
|
478
485
|
vectara_query_engine = vectara.as_query_engine(
|
|
479
486
|
summary_enabled=True,
|
|
480
487
|
similarity_top_k=summary_num_results,
|
|
@@ -507,8 +514,10 @@ class VectaraToolFactory:
|
|
|
507
514
|
frequency_penalty=frequency_penalty,
|
|
508
515
|
presence_penalty=presence_penalty,
|
|
509
516
|
citations_style="markdown" if include_citations else None,
|
|
510
|
-
citations_url_pattern=
|
|
511
|
-
citations_text_pattern=
|
|
517
|
+
citations_url_pattern=citations_url_pattern,
|
|
518
|
+
citations_text_pattern=(
|
|
519
|
+
citation_text_pattern if include_citations else None
|
|
520
|
+
),
|
|
512
521
|
save_history=save_history,
|
|
513
522
|
x_source_str="vectara-agentic",
|
|
514
523
|
verbose=verbose,
|
|
@@ -520,9 +529,11 @@ class VectaraToolFactory:
|
|
|
520
529
|
"Tool failed to generate a response since no matches were found. "
|
|
521
530
|
"Please check the arguments and try again."
|
|
522
531
|
)
|
|
532
|
+
kwargs["query"] = query
|
|
523
533
|
return {"text": msg, "metadata": {"args": args, "kwargs": kwargs}}
|
|
524
534
|
if str(response) == "None":
|
|
525
535
|
msg = "Tool failed to generate a response."
|
|
536
|
+
kwargs["query"] = query
|
|
526
537
|
return {"text": msg, "metadata": {"args": args, "kwargs": kwargs}}
|
|
527
538
|
|
|
528
539
|
# Extract citation metadata
|
|
@@ -564,11 +575,8 @@ class VectaraToolFactory:
|
|
|
564
575
|
if key.isdigit():
|
|
565
576
|
doc = value.get("document", {})
|
|
566
577
|
doc_metadata = f"{key}: " + "; ".join(
|
|
567
|
-
[
|
|
568
|
-
|
|
569
|
-
for k, v in doc.items()
|
|
570
|
-
] +
|
|
571
|
-
[
|
|
578
|
+
[f"{k}='{v}'" for k, v in doc.items()]
|
|
579
|
+
+ [
|
|
572
580
|
f"{k}='{v}'"
|
|
573
581
|
for k, v in value.items()
|
|
574
582
|
if k not in ["document"] + keys_to_ignore
|
|
@@ -596,8 +604,8 @@ class VectaraToolFactory:
|
|
|
596
604
|
tool_description,
|
|
597
605
|
RagToolBaseParams,
|
|
598
606
|
tool_args_schema,
|
|
599
|
-
compact_docstring=self.compact_docstring,
|
|
600
607
|
return_direct=return_direct,
|
|
608
|
+
vhc_eligible=vhc_eligible,
|
|
601
609
|
)
|
|
602
610
|
return tool
|
|
603
611
|
|
|
@@ -611,7 +619,10 @@ class ToolsFactory:
|
|
|
611
619
|
self.agent_config = agent_config
|
|
612
620
|
|
|
613
621
|
def create_tool(
|
|
614
|
-
self,
|
|
622
|
+
self,
|
|
623
|
+
function: Callable,
|
|
624
|
+
tool_type: ToolType = ToolType.QUERY,
|
|
625
|
+
vhc_eligible: bool = True,
|
|
615
626
|
) -> VectaraTool:
|
|
616
627
|
"""
|
|
617
628
|
Create a tool from a function.
|
|
@@ -623,7 +634,9 @@ class ToolsFactory:
|
|
|
623
634
|
Returns:
|
|
624
635
|
VectaraTool: A VectaraTool object.
|
|
625
636
|
"""
|
|
626
|
-
return VectaraTool.from_defaults(
|
|
637
|
+
return VectaraTool.from_defaults(
|
|
638
|
+
tool_type=tool_type, fn=function, vhc_eligible=vhc_eligible
|
|
639
|
+
)
|
|
627
640
|
|
|
628
641
|
def get_llama_index_tools(
|
|
629
642
|
self,
|
|
@@ -684,7 +697,7 @@ class ToolsFactory:
|
|
|
684
697
|
"""
|
|
685
698
|
tc = ToolsCatalog(self.agent_config)
|
|
686
699
|
return [
|
|
687
|
-
self.create_tool(tool)
|
|
700
|
+
self.create_tool(tool, vhc_eligible=True)
|
|
688
701
|
for tool in [tc.summarize_text, tc.rephrase_text, tc.critique_text]
|
|
689
702
|
]
|
|
690
703
|
|
|
@@ -692,7 +705,7 @@ class ToolsFactory:
|
|
|
692
705
|
"""
|
|
693
706
|
Create a list of guardrail tools to avoid controversial topics.
|
|
694
707
|
"""
|
|
695
|
-
return [self.create_tool(get_bad_topics)]
|
|
708
|
+
return [self.create_tool(get_bad_topics, vhc_eligible=False)]
|
|
696
709
|
|
|
697
710
|
def financial_tools(self):
|
|
698
711
|
"""
|
|
@@ -733,7 +746,8 @@ class ToolsFactory:
|
|
|
733
746
|
)
|
|
734
747
|
|
|
735
748
|
return [
|
|
736
|
-
self.create_tool(tool
|
|
749
|
+
self.create_tool(tool, vhc_eligible=False)
|
|
750
|
+
for tool in [summarize_legal_text, critique_as_judge]
|
|
737
751
|
]
|
|
738
752
|
|
|
739
753
|
def database_tools(
|
|
@@ -808,6 +822,7 @@ class ToolsFactory:
|
|
|
808
822
|
fn=tool.fn,
|
|
809
823
|
async_fn=tool.async_fn,
|
|
810
824
|
metadata=tool.metadata,
|
|
825
|
+
vhc_eligible=True,
|
|
811
826
|
)
|
|
812
827
|
vtools.append(vtool)
|
|
813
828
|
return vtools
|
vectara_agentic/tools_catalog.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module contains the tools catalog for the Vectara Agentic.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
from typing import List
|
|
5
6
|
from datetime import date
|
|
6
7
|
|
|
7
|
-
import requests
|
|
8
|
-
|
|
9
8
|
from pydantic import Field
|
|
10
9
|
|
|
11
10
|
from .types import LLMRole
|
|
@@ -13,16 +12,6 @@ from .agent_config import AgentConfig
|
|
|
13
12
|
from .llm_utils import get_llm
|
|
14
13
|
from .utils import remove_self_from_signature
|
|
15
14
|
|
|
16
|
-
req_session = requests.Session()
|
|
17
|
-
|
|
18
|
-
get_headers = {
|
|
19
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
|
|
20
|
-
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
|
21
|
-
"Accept-Language": "en-US,en;q=0.5",
|
|
22
|
-
"Accept-Encoding": "gzip, deflate",
|
|
23
|
-
"Connection": "keep-alive",
|
|
24
|
-
}
|
|
25
|
-
|
|
26
15
|
def get_current_date() -> str:
|
|
27
16
|
"""
|
|
28
17
|
Returns the current date as a string.
|
|
@@ -35,6 +24,7 @@ class ToolsCatalog:
|
|
|
35
24
|
"""
|
|
36
25
|
A curated set of tools for vectara-agentic
|
|
37
26
|
"""
|
|
27
|
+
|
|
38
28
|
def __init__(self, agent_config: AgentConfig):
|
|
39
29
|
self.agent_config = agent_config
|
|
40
30
|
|
|
@@ -76,7 +66,9 @@ class ToolsCatalog:
|
|
|
76
66
|
def rephrase_text(
|
|
77
67
|
self,
|
|
78
68
|
text: str = Field(description="the original text."),
|
|
79
|
-
instructions: str = Field(
|
|
69
|
+
instructions: str = Field(
|
|
70
|
+
description="the specific instructions for how to rephrase the text."
|
|
71
|
+
),
|
|
80
72
|
) -> str:
|
|
81
73
|
"""
|
|
82
74
|
This is a helper tool.
|
|
@@ -103,8 +95,13 @@ class ToolsCatalog:
|
|
|
103
95
|
def critique_text(
|
|
104
96
|
self,
|
|
105
97
|
text: str = Field(description="the original text."),
|
|
106
|
-
role: str = Field(
|
|
107
|
-
|
|
98
|
+
role: str = Field(
|
|
99
|
+
default=None, description="the role of the person providing critique."
|
|
100
|
+
),
|
|
101
|
+
point_of_view: str = Field(
|
|
102
|
+
default=None,
|
|
103
|
+
description="the point of view with which to provide critique.",
|
|
104
|
+
),
|
|
108
105
|
) -> str:
|
|
109
106
|
"""
|
|
110
107
|
This is a helper tool.
|
|
@@ -121,13 +118,16 @@ class ToolsCatalog:
|
|
|
121
118
|
if role:
|
|
122
119
|
prompt = f"As a {role}, critique the provided text from the point of view of {point_of_view}."
|
|
123
120
|
else:
|
|
124
|
-
prompt =
|
|
121
|
+
prompt = (
|
|
122
|
+
f"Critique the provided text from the point of view of {point_of_view}."
|
|
123
|
+
)
|
|
125
124
|
prompt += "\nStructure the critique as bullet points.\n"
|
|
126
125
|
prompt += f"Original text: {text}\nCritique:"
|
|
127
126
|
llm = get_llm(LLMRole.TOOL, config=self.agent_config)
|
|
128
127
|
response = llm.complete(prompt)
|
|
129
128
|
return response.text
|
|
130
129
|
|
|
130
|
+
|
|
131
131
|
#
|
|
132
132
|
# Guardrails tool: returns list of topics to avoid
|
|
133
133
|
#
|