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.

Files changed (53) hide show
  1. tests/__init__.py +7 -0
  2. tests/conftest.py +312 -0
  3. tests/endpoint.py +54 -17
  4. tests/run_tests.py +111 -0
  5. tests/test_agent.py +10 -5
  6. tests/test_agent_type.py +82 -143
  7. tests/test_api_endpoint.py +4 -0
  8. tests/test_bedrock.py +4 -0
  9. tests/test_fallback.py +4 -0
  10. tests/test_gemini.py +28 -45
  11. tests/test_groq.py +4 -0
  12. tests/test_private_llm.py +11 -2
  13. tests/test_return_direct.py +6 -2
  14. tests/test_serialization.py +4 -0
  15. tests/test_streaming.py +88 -0
  16. tests/test_tools.py +10 -82
  17. tests/test_vectara_llms.py +4 -0
  18. tests/test_vhc.py +66 -0
  19. tests/test_workflow.py +4 -0
  20. vectara_agentic/__init__.py +27 -4
  21. vectara_agentic/_callback.py +65 -67
  22. vectara_agentic/_observability.py +30 -30
  23. vectara_agentic/_version.py +1 -1
  24. vectara_agentic/agent.py +375 -848
  25. vectara_agentic/agent_config.py +15 -14
  26. vectara_agentic/agent_core/__init__.py +22 -0
  27. vectara_agentic/agent_core/factory.py +501 -0
  28. vectara_agentic/{_prompts.py → agent_core/prompts.py} +3 -35
  29. vectara_agentic/agent_core/serialization.py +345 -0
  30. vectara_agentic/agent_core/streaming.py +495 -0
  31. vectara_agentic/agent_core/utils/__init__.py +34 -0
  32. vectara_agentic/agent_core/utils/hallucination.py +202 -0
  33. vectara_agentic/agent_core/utils/logging.py +52 -0
  34. vectara_agentic/agent_core/utils/prompt_formatting.py +56 -0
  35. vectara_agentic/agent_core/utils/schemas.py +87 -0
  36. vectara_agentic/agent_core/utils/tools.py +125 -0
  37. vectara_agentic/agent_endpoint.py +4 -6
  38. vectara_agentic/db_tools.py +37 -12
  39. vectara_agentic/llm_utils.py +41 -42
  40. vectara_agentic/sub_query_workflow.py +9 -14
  41. vectara_agentic/tool_utils.py +138 -83
  42. vectara_agentic/tools.py +36 -21
  43. vectara_agentic/tools_catalog.py +16 -16
  44. vectara_agentic/types.py +98 -6
  45. {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/METADATA +69 -30
  46. vectara_agentic-0.4.0.dist-info/RECORD +50 -0
  47. tests/test_agent_planning.py +0 -64
  48. tests/test_hhem.py +0 -100
  49. vectara_agentic/hhem.py +0 -82
  50. vectara_agentic-0.3.3.dist-info/RECORD +0 -39
  51. {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/WHEEL +0 -0
  52. {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/licenses/LICENSE +0 -0
  53. {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.0.dist-info}/top_level.txt +0 -0
@@ -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 attribute.
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, including the tool_type attribute.
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 f"{base_repr}, tool_type={self.tool_type}"
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.dict() if hasattr(metadata, "dict") else metadata.__dict__
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 call(
127
- self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
140
+ def _create_tool_error_output(
141
+ self, error: Exception, args: Any, kwargs: Any, include_traceback: bool = False
128
142
  ) -> ToolOutput:
129
- try:
130
- result = super().call(*args, ctx=ctx, **kwargs)
131
- return self._format_tool_output(result)
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(e)}."
141
- f"Valid arguments: {params_str}. please call the tool again with the correct arguments."
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(e)},
156
+ raw_output={"response": str(error)},
145
157
  )
146
- return err_output
147
- except Exception as e:
148
- err_output = ToolOutput(
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=f"Tool {self.metadata.name} Malfunction: {str(e)}",
166
+ content=content,
151
167
  raw_input={"args": args, "kwargs": kwargs},
152
- raw_output={"response": str(e)},
168
+ raw_output={"response": str(error)},
153
169
  )
154
- return err_output
155
170
 
156
- async def acall(
171
+ def call(
157
172
  self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
158
173
  ) -> ToolOutput:
159
174
  try:
160
- result = await super().acall(*args, ctx=ctx, **kwargs)
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
- import traceback
182
+ return self._create_tool_error_output(e, args, kwargs)
179
183
 
180
- err_output = ToolOutput(
181
- tool_name=self.metadata.name,
182
- content=f"Tool {self.metadata.name} Malfunction: {str(e)}, traceback: {traceback.format_exc()}",
183
- raw_input={"args": args, "kwargs": kwargs},
184
- raw_output={"response": str(e)},
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 to use human-readable representation if available."""
190
- if hasattr(result, "content") and _is_human_readable_output(result.content):
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
- # Use human-readable format for content, keep raw output
193
- human_readable_content = result.content.to_human_readable()
194
- raw_output = result.content.get_raw_output()
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 format tool output for {result.tool_name}: {e}"
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
- if compact_docstring:
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
- compact_docstring (bool): Whether to use a compact docstring format.
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=field_info.annotation,
430
+ annotation=annotation,
382
431
  )
383
432
  base_params.append(param)
384
- fields[field_name] = (field_info.annotation, field_info)
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=field_info.annotation,
452
+ annotation=annotation,
399
453
  )
400
454
  base_params.append(param)
401
- fields[field_name] = (field_info.annotation, field_info)
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, compact_docstring
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 += ''.join(
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. Will be deprecated in future.
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=(citation_pattern if citation_pattern is not None else citation_url_pattern) if include_citations else None,
511
- citations_text_pattern=citation_text_pattern if include_citations else None,
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
- f"{k}='{v}'"
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, function: Callable, tool_type: ToolType = ToolType.QUERY
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(tool_type=tool_type, fn=function)
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) for tool in [summarize_legal_text, critique_as_judge]
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
@@ -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(description="the specific instructions for how to rephrase the text."),
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(default=None, description="the role of the person providing critique."),
107
- point_of_view: str = Field(default=None, description="the point of view with which to provide critique."),
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 = f"Critique the provided text from the point of view of {point_of_view}."
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
  #