vectara-agentic 0.2.10__tar.gz → 0.2.12__tar.gz

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 (36) hide show
  1. {vectara_agentic-0.2.10/vectara_agentic.egg-info → vectara_agentic-0.2.12}/PKG-INFO +6 -6
  2. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/README.md +2 -2
  3. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/requirements.txt +3 -3
  4. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/_callback.py +2 -2
  5. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/_prompts.py +7 -6
  6. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/_version.py +1 -1
  7. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/agent.py +1 -1
  8. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/db_tools.py +35 -15
  9. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/sub_query_workflow.py +35 -10
  10. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/tools.py +254 -99
  11. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/utils.py +3 -2
  12. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12/vectara_agentic.egg-info}/PKG-INFO +6 -6
  13. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic.egg-info/requires.txt +3 -3
  14. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/LICENSE +0 -0
  15. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/MANIFEST.in +0 -0
  16. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/setup.cfg +0 -0
  17. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/setup.py +0 -0
  18. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/__init__.py +0 -0
  19. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/endpoint.py +0 -0
  20. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_agent.py +0 -0
  21. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_agent_planning.py +0 -0
  22. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_agent_type.py +0 -0
  23. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_fallback.py +0 -0
  24. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_private_llm.py +0 -0
  25. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_serialization.py +0 -0
  26. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_tools.py +0 -0
  27. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/tests/test_workflow.py +0 -0
  28. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/__init__.py +0 -0
  29. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/_observability.py +0 -0
  30. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/agent_config.py +0 -0
  31. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/agent_endpoint.py +0 -0
  32. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/tools_catalog.py +0 -0
  33. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic/types.py +0 -0
  34. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic.egg-info/SOURCES.txt +0 -0
  35. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic.egg-info/dependency_links.txt +0 -0
  36. {vectara_agentic-0.2.10 → vectara_agentic-0.2.12}/vectara_agentic.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vectara_agentic
3
- Version: 0.2.10
3
+ Version: 0.2.12
4
4
  Summary: A Python package for creating AI Assistants and AI Agents with Vectara
5
5
  Home-page: https://github.com/vectara/py-vectara-agentic
6
6
  Author: Ofer Mendelevitch
@@ -16,17 +16,17 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
16
  Requires-Python: >=3.10
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: llama-index==0.12.29
19
+ Requires-Dist: llama-index==0.12.30
20
20
  Requires-Dist: llama-index-indices-managed-vectara==0.4.2
21
21
  Requires-Dist: llama-index-agent-llm-compiler==0.3.0
22
22
  Requires-Dist: llama-index-agent-lats==0.3.0
23
23
  Requires-Dist: llama-index-agent-openai==0.4.6
24
- Requires-Dist: llama-index-llms-openai==0.3.32
24
+ Requires-Dist: llama-index-llms-openai==0.3.35
25
25
  Requires-Dist: llama-index-llms-anthropic==0.6.10
26
26
  Requires-Dist: llama-index-llms-together==0.3.1
27
27
  Requires-Dist: llama-index-llms-groq==0.3.1
28
28
  Requires-Dist: llama-index-llms-fireworks==0.3.2
29
- Requires-Dist: llama-index-llms-cohere==0.4.0
29
+ Requires-Dist: llama-index-llms-cohere==0.4.1
30
30
  Requires-Dist: llama-index-llms-gemini==0.4.14
31
31
  Requires-Dist: llama-index-llms-bedrock==0.3.8
32
32
  Requires-Dist: llama-index-tools-yahoo-finance==0.3.0
@@ -141,7 +141,6 @@ from vectara_agentic.tools import VectaraToolFactory
141
141
 
142
142
  vec_factory = VectaraToolFactory(
143
143
  vectara_api_key=os.environ['VECTARA_API_KEY'],
144
- vectara_customer_id=os.environ['VECTARA_CUSTOMER_ID'],
145
144
  vectara_corpus_key=os.environ['VECTARA_CORPUS_KEY']
146
145
  )
147
146
  ```
@@ -162,7 +161,6 @@ tickers = {
162
161
  }
163
162
 
164
163
  class QueryFinancialReportsArgs(BaseModel):
165
- query: str = Field(..., description="The user query.")
166
164
  year: int | str = Field(..., description=f"The year this query relates to. An integer between {min(years)} and {max(years)} or a string specifying a condition on the year (example: '>2020').")
167
165
  ticker: str = Field(..., description=f"The company ticker. Must be a valid ticket symbol from the list {tickers.keys()}.")
168
166
 
@@ -176,6 +174,8 @@ query_financial_reports_tool = vec_factory.create_rag_tool(
176
174
  )
177
175
  ```
178
176
 
177
+ Note that we only defined the `year` and `ticker` arguments. The `query` argument is automatically added by `vectara-agentic`.
178
+
179
179
  See the [docs](https://vectara.github.io/py-vectara-agentic/latest/) for additional arguments to customize your Vectara RAG tool.
180
180
 
181
181
  ### 3. Create other tools (optional)
@@ -73,7 +73,6 @@ from vectara_agentic.tools import VectaraToolFactory
73
73
 
74
74
  vec_factory = VectaraToolFactory(
75
75
  vectara_api_key=os.environ['VECTARA_API_KEY'],
76
- vectara_customer_id=os.environ['VECTARA_CUSTOMER_ID'],
77
76
  vectara_corpus_key=os.environ['VECTARA_CORPUS_KEY']
78
77
  )
79
78
  ```
@@ -94,7 +93,6 @@ tickers = {
94
93
  }
95
94
 
96
95
  class QueryFinancialReportsArgs(BaseModel):
97
- query: str = Field(..., description="The user query.")
98
96
  year: int | str = Field(..., description=f"The year this query relates to. An integer between {min(years)} and {max(years)} or a string specifying a condition on the year (example: '>2020').")
99
97
  ticker: str = Field(..., description=f"The company ticker. Must be a valid ticket symbol from the list {tickers.keys()}.")
100
98
 
@@ -108,6 +106,8 @@ query_financial_reports_tool = vec_factory.create_rag_tool(
108
106
  )
109
107
  ```
110
108
 
109
+ Note that we only defined the `year` and `ticker` arguments. The `query` argument is automatically added by `vectara-agentic`.
110
+
111
111
  See the [docs](https://vectara.github.io/py-vectara-agentic/latest/) for additional arguments to customize your Vectara RAG tool.
112
112
 
113
113
  ### 3. Create other tools (optional)
@@ -1,14 +1,14 @@
1
- llama-index==0.12.29
1
+ llama-index==0.12.30
2
2
  llama-index-indices-managed-vectara==0.4.2
3
3
  llama-index-agent-llm-compiler==0.3.0
4
4
  llama-index-agent-lats==0.3.0
5
5
  llama-index-agent-openai==0.4.6
6
- llama-index-llms-openai==0.3.32
6
+ llama-index-llms-openai==0.3.35
7
7
  llama-index-llms-anthropic==0.6.10
8
8
  llama-index-llms-together==0.3.1
9
9
  llama-index-llms-groq==0.3.1
10
10
  llama-index-llms-fireworks==0.3.2
11
- llama-index-llms-cohere==0.4.0
11
+ llama-index-llms-cohere==0.4.1
12
12
  llama-index-llms-gemini==0.4.14
13
13
  llama-index-llms-bedrock==0.3.8
14
14
  llama-index-tools-yahoo-finance==0.3.0
@@ -154,7 +154,7 @@ class AgentCallbackHandler(BaseCallbackHandler):
154
154
  elif event_type == CBEventType.AGENT_STEP:
155
155
  self._handle_agent_step(payload, event_id)
156
156
  elif event_type == CBEventType.EXCEPTION:
157
- print(f"Exception: {payload.get(EventPayload.EXCEPTION)}")
157
+ print(f"Exception in handle_event: {payload.get(EventPayload.EXCEPTION)}")
158
158
  else:
159
159
  print(f"Unknown event type: {event_type}, payload={payload}")
160
160
 
@@ -168,7 +168,7 @@ class AgentCallbackHandler(BaseCallbackHandler):
168
168
  elif event_type == CBEventType.AGENT_STEP:
169
169
  await self._ahandle_agent_step(payload, event_id)
170
170
  elif event_type == CBEventType.EXCEPTION:
171
- print(f"Exception: {payload.get(EventPayload.EXCEPTION)}")
171
+ print(f"Exception in ahandle_event: {payload.get(EventPayload.EXCEPTION)}")
172
172
  else:
173
173
  print(f"Unknown event type: {event_type}, payload={payload}")
174
174
 
@@ -22,8 +22,8 @@ GENERAL_INSTRUCTIONS = """
22
22
  3) If a tool fails, try other tools that might be appropriate to gain the information you need.
23
23
  - If after retrying you can't get the information or answer the question, respond with "I don't know".
24
24
  - If a tool provides citations or references in markdown as part of its response, include the references in your response.
25
- - Ensure that every URL in your responses includes descriptive anchor text that clearly explains what the user can expect from the linked content.
26
- Avoid using generic terms like “source” or “reference as the anchor text.
25
+ - Ensure that every URL in your response includes descriptive anchor text that clearly explains what the user can expect from the linked content.
26
+ Avoid using generic terms like “source” or “reference”, or the full URL, as the anchor text.
27
27
  - If a tool returns in the metadata a valid URL pointing to a PDF file, along with page number - then combine the URL and page number in the response.
28
28
  For example, if the URL returned from the tool is "https://example.com/doc.pdf" and "page=5", then the combined URL would be "https://example.com/doc.pdf#page=5".
29
29
  If a tool returns in the metadata invalid URLs or an URL empty (e.g. "[[1]()]"), ignore it and do not include that citation or reference in your response.
@@ -37,10 +37,11 @@ GENERAL_INSTRUCTIONS = """
37
37
  - If including latex equations in the markdown response, make sure the equations are on a separate line and enclosed in double dollar signs.
38
38
  - Always respond in the language of the question, and in text (no images, videos or code).
39
39
  - If you are provided with database tools use them for analytical queries (such as counting, calculating max, min, average, sum, or other statistics).
40
- For each database, the database tools include: x_list_tables, x_load_data, x_describe_tables, and x_load_sample_data, where 'x' in the database name.
41
- The x_list_tables tool provides a list of available tables in the x database. Always use x_list_tables before using other database tools, to understand valid table names.
42
- Before using the x_load_data with a SQL query, always follow these steps:
43
- - Use the x_describe_tables tool to understand the schema of each table.
40
+ For each database, the database tools include: x_list_tables, x_load_data, x_describe_tables, x_load_unique_values, and x_load_sample_data, where 'x' in the database name.
41
+ for example, if the database name is "ev", the tools are: ev_list_tables, ev_load_data, ev_describe_tables, ev_load_unique_values, and ev_load_sample_data.
42
+ Before using the x_load_data with a SQL query, always follow these discovery steps:
43
+ - call the x_list_tables tool to list of available tables in the x database.
44
+ - Call the x_describe_tables tool to understand the schema of each table you want to query data from.
44
45
  - Use the x_load_unique_values tool to understand the unique values in each column.
45
46
  Sometimes the user may ask for a specific column value, but the actual value in the table may be different, and you will need to use the correct value.
46
47
  - Use the x_load_sample_data tool to understand the column names, and typical values in each column.
@@ -1,4 +1,4 @@
1
1
  """
2
2
  Define the version of the package.
3
3
  """
4
- __version__ = "0.2.10"
4
+ __version__ = "0.2.12"
@@ -661,7 +661,7 @@ class Agent:
661
661
  for tool in self.tools:
662
662
  if hasattr(tool, 'metadata'):
663
663
  if detailed:
664
- print(f"- {tool.metadata.name} - {tool.metadata.description}")
664
+ print(f"- {tool.metadata.description}")
665
665
  else:
666
666
  print(f"- {tool.metadata.name}")
667
667
  else:
@@ -15,7 +15,6 @@ from sqlalchemy.engine import Engine
15
15
  from sqlalchemy.exc import NoSuchTableError
16
16
  from sqlalchemy.schema import CreateTable
17
17
 
18
- from llama_index.core.readers.base import BaseReader
19
18
  from llama_index.core.utilities.sql_wrapper import SQLDatabase
20
19
  from llama_index.core.schema import Document
21
20
  from llama_index.core.tools.function_tool import FunctionTool
@@ -25,7 +24,7 @@ from llama_index.core.tools.utils import create_schema_from_function
25
24
 
26
25
  AsyncCallable = Callable[..., Awaitable[Any]]
27
26
 
28
- class DatabaseTools(BaseReader):
27
+ class DatabaseTools:
29
28
  """Database tools for vectara-agentic
30
29
  This class provides a set of tools to interact with a database.
31
30
  It allows you to load data, list tables, describe tables, and load unique values.
@@ -49,9 +48,11 @@ class DatabaseTools(BaseReader):
49
48
  user: Optional[str] = None,
50
49
  password: Optional[str] = None,
51
50
  dbname: Optional[str] = None,
51
+ tool_name_prefix: str = "db",
52
52
  **kwargs: Any,
53
53
  ) -> None:
54
54
  self.max_rows = max_rows
55
+ self.tool_name_prefix = tool_name_prefix
55
56
 
56
57
  if sql_database:
57
58
  self.sql_database = sql_database
@@ -86,39 +87,38 @@ class DatabaseTools(BaseReader):
86
87
  func = getattr(self, fn_name)
87
88
  except AttributeError:
88
89
  return None
89
- name = fn_name
90
+ name = self.tool_name_prefix + "_" + fn_name if self.tool_name_prefix else fn_name
90
91
  docstring = func.__doc__ or ""
91
92
  description = f"{name}{signature(func)}\n{docstring}"
92
93
  fn_schema = create_schema_from_function(fn_name, getattr(self, fn_name))
93
94
  return ToolMetadata(name=name, description=description, fn_schema=fn_schema)
94
95
 
95
- def _load_data(self, query: str) -> List[Document]:
96
+ def _load_data(self, sql_query: str) -> List[Document]:
96
97
  documents = []
97
98
  with self.sql_database.engine.connect() as connection:
98
- if query is None:
99
+ if sql_query is None:
99
100
  raise ValueError("A query parameter is necessary to filter the data")
100
- result = connection.execute(text(query))
101
+ result = connection.execute(text(sql_query))
101
102
  for item in result.fetchall():
102
103
  doc_str = ", ".join([str(entry) for entry in item])
103
104
  documents.append(Document(text=doc_str))
104
105
  return documents
105
106
 
106
- def load_data(self, *args: Any, **load_kwargs: Any) -> List[str]:
107
+ def load_data(self, sql_query: str) -> List[str]:
107
108
  """Query and load data from the Database, returning a list of Documents.
108
109
  Args:
109
- query (str): an SQL query to filter tables and rows.
110
+ sql_query (str): an SQL query to filter tables and rows.
110
111
  Returns:
111
- List[Document]: a list of Document objects from the database.
112
+ List[str]: a list of Document objects from the database.
112
113
  """
113
- query = args[0] if args else load_kwargs.get("args",{}).get("query")
114
- if query is None:
114
+ if sql_query is None:
115
115
  raise ValueError("A query parameter is necessary to filter the data")
116
116
 
117
- count_query = f"SELECT COUNT(*) FROM ({query})"
117
+ count_query = f"SELECT COUNT(*) FROM ({sql_query})"
118
118
  try:
119
119
  count_rows = self._load_data(count_query)
120
120
  except Exception as e:
121
- return [f"Error ({str(e)}) occurred while counting number of rows"]
121
+ return [f"Error ({str(e)}) occurred while counting number of rows, check your query."]
122
122
  num_rows = int(count_rows[0].text)
123
123
  if num_rows > self.max_rows:
124
124
  return [
@@ -126,9 +126,9 @@ class DatabaseTools(BaseReader):
126
126
  "Please refactor your query to make it return less rows. "
127
127
  ]
128
128
  try:
129
- res = self._load_data(query)
129
+ res = self._load_data(sql_query)
130
130
  except Exception as e:
131
- return [f"Error ({str(e)}) occurred while executing the query {query}"]
131
+ return [f"Error ({str(e)}) occurred while executing the query {sql_query}, check your query."]
132
132
  return [d.text for d in res]
133
133
 
134
134
  def load_sample_data(self, table_name: str, num_rows: int = 25) -> Any:
@@ -141,6 +141,11 @@ class DatabaseTools(BaseReader):
141
141
  Returns:
142
142
  Any: The result of the database query.
143
143
  """
144
+ if table_name not in self.list_tables():
145
+ return (
146
+ f"Table {table_name} does not exist in the database."
147
+ f"Valid table names are: {self.list_tables()}"
148
+ )
144
149
  try:
145
150
  res = self._load_data(f"SELECT * FROM {table_name} LIMIT {num_rows}")
146
151
  except Exception as e:
@@ -162,6 +167,15 @@ class DatabaseTools(BaseReader):
162
167
  str: A string representation of the table schemas.
163
168
  """
164
169
  table_names = tables or [table.name for table in self._metadata.sorted_tables]
170
+ if len(table_names) == 0:
171
+ return "You must specify at least one table name to describe."
172
+ for table_name in table_names:
173
+ if table_name not in self.list_tables():
174
+ return (
175
+ f"Table {table_name} does not exist in the database."
176
+ f"Valid table names are: {self.list_tables()}"
177
+ )
178
+
165
179
  table_schemas = []
166
180
  for table_name in table_names:
167
181
  table = next(
@@ -186,6 +200,12 @@ class DatabaseTools(BaseReader):
186
200
  Returns:
187
201
  Any: the result of the database query
188
202
  """
203
+ if table_name not in self.list_tables():
204
+ return (
205
+ f"Table {table_name} does not exist in the database."
206
+ f"Valid table names are: {self.list_tables()}"
207
+ )
208
+
189
209
  res = {}
190
210
  try:
191
211
  for column in columns:
@@ -3,6 +3,7 @@ This module contains the SubQuestionQueryEngine workflow, which is a workflow
3
3
  that takes a user question and a list of tools, and outputs a list of sub-questions.
4
4
  """
5
5
 
6
+ import re
6
7
  import json
7
8
  from pydantic import BaseModel
8
9
 
@@ -109,17 +110,27 @@ class SubQuestionQueryWorkflow(Workflow):
109
110
  if await ctx.get("verbose"):
110
111
  print(f"Sub-questions are {response}")
111
112
 
112
- if not str(response):
113
+ response_str = str(response)
114
+ if not response_str:
113
115
  raise ValueError(
114
116
  f"No response from LLM when generating sub-questions for query {original_query}"
115
117
  )
116
-
117
118
  try:
118
- sub_questions = json.loads(str(response))["sub_questions"]
119
- if not sub_questions:
120
- raise ValueError("LLM returned empty sub-questions list")
121
- except (json.JSONDecodeError, KeyError) as e:
122
- raise ValueError(f"Invalid LLM response format: {response}") from e
119
+ data = json.loads(response_str)
120
+ except json.JSONDecodeError as e1:
121
+ match = re.search(r"\{.*\}", response_str, re.DOTALL)
122
+ if not match:
123
+ raise ValueError(f"Invalid LLM response format: {response_str}") from e1
124
+ try:
125
+ data = json.loads(match.group(0))
126
+ except json.JSONDecodeError as e2:
127
+ raise ValueError(f"Invalid LLM response format: {response_str}") from e2
128
+
129
+ sub_questions = data.get("sub_questions")
130
+ if sub_questions is None:
131
+ raise ValueError(f"Invalid LLM response format: {response_str}")
132
+ if not sub_questions:
133
+ raise ValueError("LLM returned empty sub-questions list")
123
134
 
124
135
  await ctx.set("sub_question_count", len(sub_questions))
125
136
  for question in sub_questions:
@@ -273,8 +284,23 @@ class SequentialSubQuestionsWorkflow(Workflow):
273
284
  if not str(response):
274
285
  raise ValueError(f"No response from LLM for query {original_query}")
275
286
 
276
- response_obj = json.loads(str(response))
277
- sub_questions = response_obj["sub_questions"]
287
+ response_str = str(response)
288
+ try:
289
+ response_obj = json.loads(response_str)
290
+ except json.JSONDecodeError as e1:
291
+ match = re.search(r"\{.*\}", response_str, re.DOTALL)
292
+ if not match:
293
+ raise ValueError(
294
+ f"Failed to extract JSON object with subquestions from LLM response: {response_str}"
295
+ ) from e1
296
+ try:
297
+ response_obj = json.loads(match.group(0))
298
+ except json.JSONDecodeError as e2:
299
+ raise ValueError(
300
+ f"Failed to extract JSON object with subquestions from LLM response: {response_str}"
301
+ ) from e2
302
+
303
+ sub_questions = response_obj.get("sub_questions")
278
304
 
279
305
  await ctx.set("sub_questions", sub_questions)
280
306
  if await ctx.get("verbose"):
@@ -305,7 +331,6 @@ class SequentialSubQuestionsWorkflow(Workflow):
305
331
  if await ctx.get("verbose"):
306
332
  print(f"Answer is {response}")
307
333
 
308
- sub_questions = await ctx.get("sub_questions")
309
334
  if ev.num + 1 < len(sub_questions):
310
335
  return self.QueryEvent(
311
336
  question=sub_questions[ev.num + 1],
@@ -55,13 +55,15 @@ LI_packages = {
55
55
  "send_message": ToolType.ACTION,
56
56
  "fetch_channel": ToolType.QUERY,
57
57
  }
58
- }
58
+ },
59
59
  }
60
60
 
61
+
61
62
  class VectaraToolMetadata(ToolMetadata):
62
63
  """
63
64
  A subclass of ToolMetadata adding the tool_type attribute.
64
65
  """
66
+
65
67
  tool_type: ToolType
66
68
 
67
69
  def __init__(self, tool_type: ToolType, **kwargs):
@@ -88,7 +90,9 @@ class VectaraTool(FunctionTool):
88
90
  fn: Optional[Callable[..., Any]] = None,
89
91
  async_fn: Optional[AsyncCallable] = None,
90
92
  ) -> None:
91
- metadata_dict = metadata.dict() if hasattr(metadata, 'dict') else metadata.__dict__
93
+ metadata_dict = (
94
+ metadata.dict() if hasattr(metadata, "dict") else metadata.__dict__
95
+ )
92
96
  vm = VectaraToolMetadata(tool_type=tool_type, **metadata_dict)
93
97
  super().__init__(fn, vm, async_fn)
94
98
 
@@ -107,19 +111,26 @@ class VectaraTool(FunctionTool):
107
111
  tool_type: ToolType = ToolType.QUERY,
108
112
  ) -> "VectaraTool":
109
113
  tool = FunctionTool.from_defaults(
110
- fn, name, description, return_direct, fn_schema, async_fn, tool_metadata,
111
- callback, async_callback
114
+ fn,
115
+ name,
116
+ description,
117
+ return_direct,
118
+ fn_schema,
119
+ async_fn,
120
+ tool_metadata,
121
+ callback,
122
+ async_callback,
112
123
  )
113
124
  vectara_tool = cls(
114
- tool_type=tool_type, fn=tool.fn, metadata=tool.metadata, async_fn=tool.async_fn,
125
+ tool_type=tool_type,
126
+ fn=tool.fn,
127
+ metadata=tool.metadata,
128
+ async_fn=tool.async_fn,
115
129
  )
116
130
  return vectara_tool
117
131
 
118
132
  def __str__(self) -> str:
119
- return (
120
- f"Tool(name={self.metadata.name}, "
121
- f"Tool metadata={self.metadata})"
122
- )
133
+ return f"Tool(name={self.metadata.name}, " f"Tool metadata={self.metadata})"
123
134
 
124
135
  def __repr__(self) -> str:
125
136
  return str(self)
@@ -137,19 +148,20 @@ class VectaraTool(FunctionTool):
137
148
  # If schema is a dict-like object, compare the dict representation
138
149
  try:
139
150
  # Try to get schema as dict if possible
140
- if hasattr(self.metadata.fn_schema, 'schema'):
151
+ if hasattr(self.metadata.fn_schema, "schema"):
141
152
  self_schema = self.metadata.fn_schema.schema
142
153
  other_schema = other.metadata.fn_schema.schema
143
154
 
144
155
  # Compare only properties and required fields
145
- self_props = self_schema.get('properties', {})
146
- other_props = other_schema.get('properties', {})
156
+ self_props = self_schema.get("properties", {})
157
+ other_props = other_schema.get("properties", {})
147
158
 
148
- self_required = self_schema.get('required', [])
149
- other_required = other_schema.get('required', [])
159
+ self_required = self_schema.get("required", [])
160
+ other_required = other_schema.get("required", [])
150
161
 
151
- return (self_props.keys() == other_props.keys() and
152
- set(self_required) == set(other_required))
162
+ return self_props.keys() == other_props.keys() and set(
163
+ self_required
164
+ ) == set(other_required)
153
165
  except Exception:
154
166
  # If any exception occurs during schema comparison, fall back to name comparison
155
167
  pass
@@ -161,6 +173,21 @@ class VectaraTool(FunctionTool):
161
173
  ) -> ToolOutput:
162
174
  try:
163
175
  return super().call(*args, ctx=ctx, **kwargs)
176
+ except TypeError as e:
177
+ sig = inspect.signature(self.metadata.fn_schema)
178
+ valid_parameters = list(sig.parameters.keys())
179
+ params_str = ", ".join(valid_parameters)
180
+
181
+ err_output = ToolOutput(
182
+ tool_name=self.metadata.name,
183
+ content=(
184
+ f"Wrong argument used when calling {self.metadata.name}: {str(e)}. "
185
+ f"Valid arguments: {params_str}. please call the tool again with the correct arguments."
186
+ ),
187
+ raw_input={"args": args, "kwargs": kwargs},
188
+ raw_output={"response": str(e)},
189
+ )
190
+ return err_output
164
191
  except Exception as e:
165
192
  err_output = ToolOutput(
166
193
  tool_name=self.metadata.name,
@@ -175,6 +202,21 @@ class VectaraTool(FunctionTool):
175
202
  ) -> ToolOutput:
176
203
  try:
177
204
  return await super().acall(*args, ctx=ctx, **kwargs)
205
+ except TypeError as e:
206
+ sig = inspect.signature(self.metadata.fn_schema)
207
+ valid_parameters = list(sig.parameters.keys())
208
+ params_str = ", ".join(valid_parameters)
209
+
210
+ err_output = ToolOutput(
211
+ tool_name=self.metadata.name,
212
+ content=(
213
+ f"Wrong argument used when calling {self.metadata.name}: {str(e)}. "
214
+ f"Valid arguments: {params_str}. please call the tool again with the correct arguments."
215
+ ),
216
+ raw_input={"args": args, "kwargs": kwargs},
217
+ raw_output={"response": str(e)},
218
+ )
219
+ return err_output
178
220
  except Exception as e:
179
221
  err_output = ToolOutput(
180
222
  tool_name=self.metadata.name,
@@ -184,66 +226,129 @@ class VectaraTool(FunctionTool):
184
226
  )
185
227
  return err_output
186
228
 
229
+
187
230
  def _create_tool_from_dynamic_function(
188
231
  function: Callable[..., ToolOutput],
189
232
  tool_name: str,
190
233
  tool_description: str,
191
- base_params: list[inspect.Parameter],
192
- tool_args_schema: type[BaseModel],
234
+ base_params_model: Type[BaseModel], # Now a Pydantic BaseModel
235
+ tool_args_schema: Type[BaseModel],
193
236
  ) -> VectaraTool:
194
- """
195
- Create a VectaraTool from a dynamic function, including
196
- setting the function signature and creating the tool schema.
197
- """
198
237
  fields = {}
199
- for param in base_params:
200
- default_value = param.default if param.default != inspect.Parameter.empty else ...
201
- fields[param.name] = (param.annotation, default_value)
238
+ base_params = []
239
+
240
+ # Create inspect.Parameter objects for base_params_model fields.
241
+ for param_name, model_field in base_params_model.model_fields.items():
242
+ field_type = base_params_model.__annotations__.get(
243
+ param_name, str
244
+ ) # default to str if not found
245
+ default_value = (
246
+ model_field.default
247
+ if model_field.default is not None
248
+ else inspect.Parameter.empty
249
+ )
250
+ base_params.append(
251
+ inspect.Parameter(
252
+ param_name,
253
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
254
+ default=default_value,
255
+ annotation=field_type,
256
+ )
257
+ )
258
+ fields[param_name] = (
259
+ field_type,
260
+ model_field.default if model_field.default is not None else ...,
261
+ )
262
+
263
+ # Add tool_args_schema fields to the fields dict if not already included.
264
+ # Also add them to the function signature by creating new inspect.Parameter objects.
202
265
  for field_name, field_info in tool_args_schema.model_fields.items():
203
266
  if field_name not in fields:
204
- default_value = field_info.default if field_info.default is not PydanticUndefined else ...
205
- fields[field_name] = (field_info.annotation, default_value)
206
- fn_schema = create_model(f"{tool_name}", **fields)
207
-
208
- schema_params = [
209
- inspect.Parameter(
210
- name=field_name,
211
- kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
212
- default=field_info.default if field_info.default is not PydanticUndefined else inspect.Parameter.empty,
213
- annotation=field_info.annotation if hasattr(field_info, 'annotation') else field_info,
214
- )
215
- for field_name, field_info in tool_args_schema.model_fields.items()
216
- if field_name not in [p.name for p in base_params]
217
- ]
218
- all_params = base_params + schema_params
267
+ default_value = (
268
+ field_info.default if field_info.default is not None else ...
269
+ )
270
+ field_type = tool_args_schema.__annotations__.get(field_name, None)
271
+ fields[field_name] = (field_type, default_value)
272
+ # Append these fields to the signature.
273
+ base_params.append(
274
+ inspect.Parameter(
275
+ field_name,
276
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
277
+ default=(
278
+ default_value
279
+ if default_value is not ...
280
+ else inspect.Parameter.empty
281
+ ),
282
+ annotation=field_type,
283
+ )
284
+ )
219
285
 
286
+ # Create the dynamic schema with both base_params_model and tool_args_schema fields.
287
+ fn_schema = create_model(f"{tool_name}_schema", **fields)
288
+
289
+ # Combine parameters into a function signature.
290
+ all_params = base_params[:] # Now all_params contains parameters from both models.
220
291
  required_params = [p for p in all_params if p.default is inspect.Parameter.empty]
221
- optional_params = [p for p in all_params if p.default is not inspect.Parameter.empty]
222
- sig = inspect.Signature(required_params + optional_params)
223
- function.__signature__ = sig
292
+ optional_params = [
293
+ p for p in all_params if p.default is not inspect.Parameter.empty
294
+ ]
295
+ function.__signature__ = inspect.Signature(required_params + optional_params)
224
296
  function.__annotations__["return"] = dict[str, Any]
225
- function.__name__ = "_" + re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
297
+ function.__name__ = re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
226
298
 
227
- # Create the tool function signature string
228
- param_strs = []
299
+ # Build a docstring using parameter descriptions from the BaseModels.
300
+ params_str = ",\n ".join(
301
+ f"{p.name}: {p.annotation.__name__ if hasattr(p.annotation, '__name__') else p.annotation}"
302
+ for p in all_params
303
+ )
304
+ signature_line = f"{tool_name}(\n {params_str}\n) -> dict[str, Any]"
305
+ doc_lines = [
306
+ signature_line,
307
+ "",
308
+ tool_description.strip(),
309
+ "",
310
+ "Args:",
311
+ ]
229
312
  for param in all_params:
230
- annotation = param.annotation
231
- type_name = annotation.__name__ if hasattr(annotation, '__name__') else str(annotation)
232
- param_strs.append(f"{param.name}: {type_name}")
233
- args_str = ", ".join(param_strs)
234
- function_str = f"{tool_name}({args_str}) -> str"
313
+ description = ""
314
+ if param.name in base_params_model.model_fields:
315
+ description = base_params_model.model_fields[param.name].description
316
+ elif param.name in tool_args_schema.model_fields:
317
+ description = tool_args_schema.model_fields[param.name].description
318
+ if not description:
319
+ description = "No description provided."
320
+ type_name = (
321
+ param.annotation.__name__
322
+ if hasattr(param.annotation, "__name__")
323
+ else str(param.annotation)
324
+ )
325
+ default_text = (
326
+ f", default={param.default!r}"
327
+ if param.default is not inspect.Parameter.empty
328
+ else ""
329
+ )
330
+ doc_lines.append(f" {param.name} ({type_name}){default_text}: {description}")
331
+ doc_lines.append("")
332
+ doc_lines.append("Returns:")
333
+ return_desc = getattr(
334
+ function, "__return_description__", "A dictionary containing the result data."
335
+ )
336
+ doc_lines.append(f" dict[str, Any]: {return_desc}")
337
+ function.__doc__ = "\n".join(doc_lines)
235
338
 
236
- # Create the tool
237
339
  tool = VectaraTool.from_defaults(
238
340
  fn=function,
239
341
  name=tool_name,
240
- description=function_str + "\n" + tool_description,
342
+ description=function.__doc__,
241
343
  fn_schema=fn_schema,
242
344
  tool_type=ToolType.QUERY,
243
345
  )
244
346
  return tool
245
347
 
246
- def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict], fixed_filter: str) -> str:
348
+
349
+ def _build_filter_string(
350
+ kwargs: Dict[str, Any], tool_args_type: Dict[str, dict], fixed_filter: str
351
+ ) -> str:
247
352
  """
248
353
  Build filter string for Vectara from kwargs
249
354
  """
@@ -257,9 +362,9 @@ def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict]
257
362
 
258
363
  # Determine the prefix for the key. Valid values are "doc" or "part"
259
364
  # default to 'doc' if not specified
260
- tool_args_dict = tool_args_type.get(key, {'type': 'doc', 'is_list': False})
365
+ tool_args_dict = tool_args_type.get(key, {"type": "doc", "is_list": False})
261
366
  prefix = tool_args_dict.get(key, "doc")
262
- is_list = tool_args_dict.get('is_list', False)
367
+ is_list = tool_args_dict.get("is_list", False)
263
368
 
264
369
  if prefix not in ["doc", "part"]:
265
370
  raise ValueError(
@@ -312,12 +417,10 @@ def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict]
312
417
  range_conditions.append(f"{prefix}.{key} {operator} {end_val}")
313
418
 
314
419
  # Join the range conditions with AND
315
- filter_parts.append('( ' + " AND ".join(range_conditions) + ' )')
420
+ filter_parts.append("( " + " AND ".join(range_conditions) + " )")
316
421
  continue
317
422
 
318
- raise ValueError(
319
- f"Range operator requires two values for {key}: {value}"
320
- )
423
+ raise ValueError(f"Range operator requires two values for {key}: {value}")
321
424
 
322
425
  # Check if value contains a known comparison operator at the start
323
426
  matched_operator = None
@@ -329,7 +432,7 @@ def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict]
329
432
  # Break down operator from value
330
433
  # e.g. val_str = ">2022" --> operator = ">", rhs = "2022"
331
434
  if matched_operator:
332
- rhs = val_str[len(matched_operator):].strip()
435
+ rhs = val_str[len(matched_operator) :].strip()
333
436
 
334
437
  if matched_operator in numeric_only_ops:
335
438
  # Must be numeric
@@ -343,7 +446,9 @@ def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict]
343
446
  if rhs.isdigit() or is_float(rhs):
344
447
  filter_parts.append(f"{prefix}.{key}{matched_operator}{rhs}")
345
448
  elif rhs.lower() in ["true", "false"]:
346
- filter_parts.append(f"{prefix}.{key}{matched_operator}{rhs.lower()}")
449
+ filter_parts.append(
450
+ f"{prefix}.{key}{matched_operator}{rhs.lower()}"
451
+ )
347
452
  else:
348
453
  # For string operands, wrap them in quotes
349
454
  filter_parts.append(f"{prefix}.{key}{matched_operator}'{rhs}'")
@@ -373,6 +478,7 @@ def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict]
373
478
  else:
374
479
  return fixed_filter or filter_str
375
480
 
481
+
376
482
  class VectaraToolFactory:
377
483
  """
378
484
  A factory class for creating Vectara RAG tools.
@@ -480,7 +586,9 @@ class VectaraToolFactory:
480
586
  top_k = kwargs.pop("top_k", 10)
481
587
  summarize = kwargs.pop("summarize", True)
482
588
  try:
483
- filter_string = _build_filter_string(kwargs, tool_args_type, fixed_filter)
589
+ filter_string = _build_filter_string(
590
+ kwargs, tool_args_type, fixed_filter
591
+ )
484
592
  except ValueError as e:
485
593
  return ToolOutput(
486
594
  tool_name=search_function.__name__,
@@ -493,7 +601,11 @@ class VectaraToolFactory:
493
601
  summary_enabled=False,
494
602
  similarity_top_k=top_k,
495
603
  reranker=reranker,
496
- rerank_k=rerank_k if rerank_k * self.num_corpora <= 100 else int(100 / self.num_corpora),
604
+ rerank_k=(
605
+ rerank_k
606
+ if rerank_k * self.num_corpora <= 100
607
+ else int(100 / self.num_corpora)
608
+ ),
497
609
  rerank_limit=rerank_limit,
498
610
  rerank_cutoff=rerank_cutoff,
499
611
  mmr_diversity_bias=mmr_diversity_bias,
@@ -531,9 +643,7 @@ class VectaraToolFactory:
531
643
  if summarize:
532
644
  summaries_dict = asyncio.run(
533
645
  summarize_documents(
534
- self.vectara_corpus_key,
535
- self.vectara_api_key,
536
- list(unique_ids)
646
+ self.vectara_corpus_key, self.vectara_api_key, list(unique_ids)
537
647
  )
538
648
  )
539
649
  for doc_id, metadata in docs:
@@ -541,7 +651,9 @@ class VectaraToolFactory:
541
651
  tool_output += f"document_id: '{doc_id}'\nmetadata: '{metadata}'\nsummary: '{summary}'\n\n"
542
652
  else:
543
653
  for doc_id, metadata in docs:
544
- tool_output += f"document_id: '{doc_id}'\nmetadata: '{metadata}'\n\n"
654
+ tool_output += (
655
+ f"document_id: '{doc_id}'\nmetadata: '{metadata}'\n\n"
656
+ )
545
657
 
546
658
  out = ToolOutput(
547
659
  tool_name=search_function.__name__,
@@ -551,23 +663,31 @@ class VectaraToolFactory:
551
663
  )
552
664
  return out
553
665
 
554
- base_params = [
555
- inspect.Parameter("query", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
556
- inspect.Parameter("top_k", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=int),
557
- inspect.Parameter("summarize", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=True, annotation=bool),
558
- ]
559
- search_tool_extra_desc = tool_description + "\n" + """
560
- This tool is meant to perform a search for relevant documents, it is not meant for asking questions.
561
- The response includes metadata about each relevant document.
562
- If summarize=True, it also includes a summary of each document, but takes a lot longer to respond,
563
- so avoid using it unless necessary.
564
- """
666
+ class SearchToolBaseParams(BaseModel):
667
+ """Model for the base parameters of the search tool."""
668
+ query: str = Field(
669
+ ...,
670
+ description="The search query to perform, always in the form of a question.",
671
+ )
672
+ top_k: int = Field(
673
+ 10, description="The number of top documents to retrieve."
674
+ )
675
+ summarize: bool = Field(
676
+ True,
677
+ description="Flag that indicates whether to summarize the retrieved documents.",
678
+ )
679
+
680
+ search_tool_extra_desc = (
681
+ tool_description
682
+ + "\n"
683
+ + "This tool is meant to perform a search for relevant documents, it is not meant for asking questions."
684
+ )
565
685
 
566
686
  tool = _create_tool_from_dynamic_function(
567
687
  search_function,
568
688
  tool_name,
569
689
  search_tool_extra_desc,
570
- base_params,
690
+ SearchToolBaseParams,
571
691
  tool_args_schema,
572
692
  )
573
693
  return tool
@@ -684,7 +804,9 @@ class VectaraToolFactory:
684
804
 
685
805
  query = kwargs.pop("query")
686
806
  try:
687
- filter_string = _build_filter_string(kwargs, tool_args_type, fixed_filter)
807
+ filter_string = _build_filter_string(
808
+ kwargs, tool_args_type, fixed_filter
809
+ )
688
810
  except ValueError as e:
689
811
  return ToolOutput(
690
812
  tool_name=rag_function.__name__,
@@ -701,7 +823,11 @@ class VectaraToolFactory:
701
823
  summary_prompt_name=vectara_summarizer,
702
824
  prompt_text=vectara_prompt_text,
703
825
  reranker=reranker,
704
- rerank_k=rerank_k if rerank_k * self.num_corpora <= 100 else int(100 / self.num_corpora),
826
+ rerank_k=(
827
+ rerank_k
828
+ if rerank_k * self.num_corpora <= 100
829
+ else int(100 / self.num_corpora)
830
+ ),
705
831
  rerank_limit=rerank_limit,
706
832
  rerank_cutoff=rerank_cutoff,
707
833
  mmr_diversity_bias=mmr_diversity_bias,
@@ -792,18 +918,23 @@ class VectaraToolFactory:
792
918
  )
793
919
  return out
794
920
 
795
- base_params = [
796
- inspect.Parameter("query", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
797
- ]
921
+ class RagToolBaseParams(BaseModel):
922
+ """Model for the base parameters of the RAG tool."""
923
+ query: str = Field(
924
+ ...,
925
+ description="The search query to perform, always in the form of a question",
926
+ )
927
+
798
928
  tool = _create_tool_from_dynamic_function(
799
929
  rag_function,
800
930
  tool_name,
801
931
  tool_description,
802
- base_params,
932
+ RagToolBaseParams,
803
933
  tool_args_schema,
804
934
  )
805
935
  return tool
806
936
 
937
+
807
938
  class ToolsFactory:
808
939
  """
809
940
  A factory class for creating agent tools.
@@ -812,7 +943,9 @@ class ToolsFactory:
812
943
  def __init__(self, agent_config: AgentConfig = None) -> None:
813
944
  self.agent_config = agent_config
814
945
 
815
- def create_tool(self, function: Callable, tool_type: ToolType = ToolType.QUERY) -> VectaraTool:
946
+ def create_tool(
947
+ self, function: Callable, tool_type: ToolType = ToolType.QUERY
948
+ ) -> VectaraTool:
816
949
  """
817
950
  Create a tool from a function.
818
951
 
@@ -846,7 +979,9 @@ class ToolsFactory:
846
979
  """
847
980
  # Dynamically install and import the module
848
981
  if tool_package_name not in LI_packages:
849
- raise ValueError(f"Tool package {tool_package_name} from LlamaIndex not supported by Vectara-agentic.")
982
+ raise ValueError(
983
+ f"Tool package {tool_package_name} from LlamaIndex not supported by Vectara-agentic."
984
+ )
850
985
 
851
986
  module_name = f"llama_index.tools.{tool_package_name}"
852
987
  module = importlib.import_module(module_name)
@@ -861,11 +996,18 @@ class ToolsFactory:
861
996
  tool.metadata.name = tool_name_prefix + "_" + tool.metadata.name
862
997
  if isinstance(func_type, dict):
863
998
  if tool_spec_name not in func_type.keys():
864
- raise ValueError(f"Tool spec {tool_spec_name} not found in package {tool_package_name}.")
999
+ raise ValueError(
1000
+ f"Tool spec {tool_spec_name} not found in package {tool_package_name}."
1001
+ )
865
1002
  tool_type = func_type[tool_spec_name]
866
1003
  else:
867
1004
  tool_type = func_type
868
- vtool = VectaraTool(tool_type=tool_type, fn=tool.fn, metadata=tool.metadata, async_fn=tool.async_fn)
1005
+ vtool = VectaraTool(
1006
+ tool_type=tool_type,
1007
+ fn=tool.fn,
1008
+ metadata=tool.metadata,
1009
+ async_fn=tool.async_fn,
1010
+ )
869
1011
  vtools.append(vtool)
870
1012
  return vtools
871
1013
 
@@ -874,7 +1016,10 @@ class ToolsFactory:
874
1016
  Create a list of standard tools.
875
1017
  """
876
1018
  tc = ToolsCatalog(self.agent_config)
877
- return [self.create_tool(tool) for tool in [tc.summarize_text, tc.rephrase_text, tc.critique_text]]
1019
+ return [
1020
+ self.create_tool(tool)
1021
+ for tool in [tc.summarize_text, tc.rephrase_text, tc.critique_text]
1022
+ ]
878
1023
 
879
1024
  def guardrail_tools(self) -> List[FunctionTool]:
880
1025
  """
@@ -886,7 +1031,9 @@ class ToolsFactory:
886
1031
  """
887
1032
  Create a list of financial tools.
888
1033
  """
889
- return self.get_llama_index_tools(tool_package_name="yahoo_finance", tool_spec_name="YahooFinanceToolSpec")
1034
+ return self.get_llama_index_tools(
1035
+ tool_package_name="yahoo_finance", tool_spec_name="YahooFinanceToolSpec"
1036
+ )
890
1037
 
891
1038
  def legal_tools(self) -> List[FunctionTool]:
892
1039
  """
@@ -918,7 +1065,9 @@ class ToolsFactory:
918
1065
  """,
919
1066
  )
920
1067
 
921
- return [self.create_tool(tool) for tool in [summarize_legal_text, critique_as_judge]]
1068
+ return [
1069
+ self.create_tool(tool) for tool in [summarize_legal_text, critique_as_judge]
1070
+ ]
922
1071
 
923
1072
  def database_tools(
924
1073
  self,
@@ -955,16 +1104,22 @@ class ToolsFactory:
955
1104
  List[VectaraTool]: A list of VectaraTool objects.
956
1105
  """
957
1106
  if sql_database:
958
- dbt = DatabaseTools(sql_database=sql_database)
1107
+ dbt = DatabaseTools(
1108
+ tool_name_prefix=tool_name_prefix,
1109
+ sql_database=sql_database,
1110
+ max_rows=max_rows,
1111
+ )
959
1112
  else:
960
1113
  if scheme in ["postgresql", "mysql", "sqlite", "mssql", "oracle"]:
961
1114
  dbt = DatabaseTools(
1115
+ tool_name_prefix=tool_name_prefix,
962
1116
  scheme=scheme,
963
1117
  host=host,
964
1118
  port=port,
965
1119
  user=user,
966
1120
  password=password,
967
1121
  dbname=dbname,
1122
+ max_rows=max_rows,
968
1123
  )
969
1124
  else:
970
1125
  raise ValueError(
@@ -978,14 +1133,14 @@ class ToolsFactory:
978
1133
  for tool in tools:
979
1134
  if content_description:
980
1135
  tool.metadata.description = (
981
- tool.metadata.description + f"The database tables include data about {content_description}."
1136
+ tool.metadata.description
1137
+ + f"The database tables include data about {content_description}."
982
1138
  )
983
- if len(tool_name_prefix) > 0:
984
- tool.metadata.name = tool_name_prefix + "_" + tool.metadata.name
985
1139
  vtool = VectaraTool(
986
1140
  tool_type=ToolType.QUERY,
987
- fn=tool.fn, async_fn=tool.async_fn,
988
- metadata=tool.metadata
1141
+ fn=tool.fn,
1142
+ async_fn=tool.async_fn,
1143
+ metadata=tool.metadata,
989
1144
  )
990
1145
  vtools.append(vtool)
991
1146
  return vtools
@@ -103,7 +103,7 @@ def get_llm(
103
103
  elif model_provider == ModelProvider.ANTHROPIC:
104
104
  llm = Anthropic(
105
105
  model=model_name, temperature=0,
106
- max_tokens=max_tokens, cache_idx=2,
106
+ max_tokens=max_tokens,
107
107
  )
108
108
  elif model_provider == ModelProvider.GEMINI:
109
109
  from llama_index.llms.gemini import Gemini
@@ -124,7 +124,8 @@ def get_llm(
124
124
  from llama_index.llms.groq import Groq
125
125
  llm = Groq(
126
126
  model=model_name, temperature=0,
127
- is_function_calling_model=True, max_tokens=max_tokens
127
+ is_function_calling_model=True,
128
+ max_tokens=max_tokens
128
129
  )
129
130
  elif model_provider == ModelProvider.FIREWORKS:
130
131
  from llama_index.llms.fireworks import Fireworks
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vectara_agentic
3
- Version: 0.2.10
3
+ Version: 0.2.12
4
4
  Summary: A Python package for creating AI Assistants and AI Agents with Vectara
5
5
  Home-page: https://github.com/vectara/py-vectara-agentic
6
6
  Author: Ofer Mendelevitch
@@ -16,17 +16,17 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
16
  Requires-Python: >=3.10
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: llama-index==0.12.29
19
+ Requires-Dist: llama-index==0.12.30
20
20
  Requires-Dist: llama-index-indices-managed-vectara==0.4.2
21
21
  Requires-Dist: llama-index-agent-llm-compiler==0.3.0
22
22
  Requires-Dist: llama-index-agent-lats==0.3.0
23
23
  Requires-Dist: llama-index-agent-openai==0.4.6
24
- Requires-Dist: llama-index-llms-openai==0.3.32
24
+ Requires-Dist: llama-index-llms-openai==0.3.35
25
25
  Requires-Dist: llama-index-llms-anthropic==0.6.10
26
26
  Requires-Dist: llama-index-llms-together==0.3.1
27
27
  Requires-Dist: llama-index-llms-groq==0.3.1
28
28
  Requires-Dist: llama-index-llms-fireworks==0.3.2
29
- Requires-Dist: llama-index-llms-cohere==0.4.0
29
+ Requires-Dist: llama-index-llms-cohere==0.4.1
30
30
  Requires-Dist: llama-index-llms-gemini==0.4.14
31
31
  Requires-Dist: llama-index-llms-bedrock==0.3.8
32
32
  Requires-Dist: llama-index-tools-yahoo-finance==0.3.0
@@ -141,7 +141,6 @@ from vectara_agentic.tools import VectaraToolFactory
141
141
 
142
142
  vec_factory = VectaraToolFactory(
143
143
  vectara_api_key=os.environ['VECTARA_API_KEY'],
144
- vectara_customer_id=os.environ['VECTARA_CUSTOMER_ID'],
145
144
  vectara_corpus_key=os.environ['VECTARA_CORPUS_KEY']
146
145
  )
147
146
  ```
@@ -162,7 +161,6 @@ tickers = {
162
161
  }
163
162
 
164
163
  class QueryFinancialReportsArgs(BaseModel):
165
- query: str = Field(..., description="The user query.")
166
164
  year: int | str = Field(..., description=f"The year this query relates to. An integer between {min(years)} and {max(years)} or a string specifying a condition on the year (example: '>2020').")
167
165
  ticker: str = Field(..., description=f"The company ticker. Must be a valid ticket symbol from the list {tickers.keys()}.")
168
166
 
@@ -176,6 +174,8 @@ query_financial_reports_tool = vec_factory.create_rag_tool(
176
174
  )
177
175
  ```
178
176
 
177
+ Note that we only defined the `year` and `ticker` arguments. The `query` argument is automatically added by `vectara-agentic`.
178
+
179
179
  See the [docs](https://vectara.github.io/py-vectara-agentic/latest/) for additional arguments to customize your Vectara RAG tool.
180
180
 
181
181
  ### 3. Create other tools (optional)
@@ -1,14 +1,14 @@
1
- llama-index==0.12.29
1
+ llama-index==0.12.30
2
2
  llama-index-indices-managed-vectara==0.4.2
3
3
  llama-index-agent-llm-compiler==0.3.0
4
4
  llama-index-agent-lats==0.3.0
5
5
  llama-index-agent-openai==0.4.6
6
- llama-index-llms-openai==0.3.32
6
+ llama-index-llms-openai==0.3.35
7
7
  llama-index-llms-anthropic==0.6.10
8
8
  llama-index-llms-together==0.3.1
9
9
  llama-index-llms-groq==0.3.1
10
10
  llama-index-llms-fireworks==0.3.2
11
- llama-index-llms-cohere==0.4.0
11
+ llama-index-llms-cohere==0.4.1
12
12
  llama-index-llms-gemini==0.4.14
13
13
  llama-index-llms-bedrock==0.3.8
14
14
  llama-index-tools-yahoo-finance==0.3.0