vectara-agentic 0.2.15__tar.gz → 0.2.16__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.
- {vectara_agentic-0.2.15/vectara_agentic.egg-info → vectara_agentic-0.2.16}/PKG-INFO +5 -5
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/requirements.txt +4 -4
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_agent.py +2 -2
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_agent_planning.py +1 -1
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_groq.py +3 -1
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_tools.py +119 -17
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/_observability.py +1 -1
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/_prompts.py +4 -2
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/_version.py +1 -1
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/agent.py +97 -41
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/db_tools.py +2 -2
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/llm_utils.py +10 -6
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/tool_utils.py +110 -84
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/tools.py +1 -1
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/tools_catalog.py +1 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16/vectara_agentic.egg-info}/PKG-INFO +5 -5
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic.egg-info/requires.txt +4 -4
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/LICENSE +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/MANIFEST.in +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/README.md +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/setup.cfg +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/setup.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/__init__.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/endpoint.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_agent_type.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_fallback.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_private_llm.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_return_direct.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_serialization.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_vectara_llms.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/tests/test_workflow.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/__init__.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/_callback.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/agent_config.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/agent_endpoint.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/sub_query_workflow.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/types.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic/utils.py +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic.egg-info/SOURCES.txt +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic.egg-info/dependency_links.txt +0 -0
- {vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/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.
|
|
3
|
+
Version: 0.2.16
|
|
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,18 +16,18 @@ 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.
|
|
20
|
-
Requires-Dist: llama-index-indices-managed-vectara==0.4.
|
|
19
|
+
Requires-Dist: llama-index==0.12.34
|
|
20
|
+
Requires-Dist: llama-index-indices-managed-vectara==0.4.5
|
|
21
21
|
Requires-Dist: llama-index-agent-llm-compiler==0.3.0
|
|
22
22
|
Requires-Dist: llama-index-agent-lats==0.3.0
|
|
23
|
-
Requires-Dist: llama-index-agent-openai==0.4.
|
|
23
|
+
Requires-Dist: llama-index-agent-openai==0.4.7
|
|
24
24
|
Requires-Dist: llama-index-llms-openai==0.3.38
|
|
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
29
|
Requires-Dist: llama-index-llms-cohere==0.4.1
|
|
30
|
-
Requires-Dist: llama-index-llms-google-genai==0.1.
|
|
30
|
+
Requires-Dist: llama-index-llms-google-genai==0.1.12
|
|
31
31
|
Requires-Dist: llama-index-llms-bedrock==0.3.8
|
|
32
32
|
Requires-Dist: llama-index-tools-yahoo-finance==0.3.0
|
|
33
33
|
Requires-Dist: llama-index-tools-arxiv==0.3.0
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
llama-index==0.12.
|
|
2
|
-
llama-index-indices-managed-vectara==0.4.
|
|
1
|
+
llama-index==0.12.34
|
|
2
|
+
llama-index-indices-managed-vectara==0.4.5
|
|
3
3
|
llama-index-agent-llm-compiler==0.3.0
|
|
4
4
|
llama-index-agent-lats==0.3.0
|
|
5
|
-
llama-index-agent-openai==0.4.
|
|
5
|
+
llama-index-agent-openai==0.4.7
|
|
6
6
|
llama-index-llms-openai==0.3.38
|
|
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
11
|
llama-index-llms-cohere==0.4.1
|
|
12
|
-
llama-index-llms-google-genai ==0.1.
|
|
12
|
+
llama-index-llms-google-genai ==0.1.12
|
|
13
13
|
llama-index-llms-bedrock==0.3.8
|
|
14
14
|
llama-index-tools-yahoo-finance==0.3.0
|
|
15
15
|
llama-index-tools-arxiv==0.3.0
|
|
@@ -124,7 +124,7 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
124
124
|
self.assertEqual(res.response, "1050")
|
|
125
125
|
|
|
126
126
|
def test_custom_general_instruction(self):
|
|
127
|
-
general_instructions = "Always respond with
|
|
127
|
+
general_instructions = "Always respond with: I DIDN'T DO IT"
|
|
128
128
|
agent = Agent.from_corpus(
|
|
129
129
|
tool_name="RAG Tool",
|
|
130
130
|
vectara_corpus_key="corpus_key",
|
|
@@ -135,7 +135,7 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
res = agent.chat("What is the meaning of the universe?")
|
|
138
|
-
self.assertEqual(res.response, "I
|
|
138
|
+
self.assertEqual(res.response, "I DIDN'T DO IT")
|
|
139
139
|
|
|
140
140
|
|
|
141
141
|
if __name__ == "__main__":
|
|
@@ -4,7 +4,7 @@ from vectara_agentic.agent_config import AgentConfig
|
|
|
4
4
|
from vectara_agentic.agent import Agent
|
|
5
5
|
from vectara_agentic.tools import VectaraToolFactory
|
|
6
6
|
|
|
7
|
-
# SETUP
|
|
7
|
+
# SETUP special test account credentials for vectara
|
|
8
8
|
# It's okay to expose these credentials in the test code
|
|
9
9
|
vectara_corpus_key = "vectara-docs_1"
|
|
10
10
|
vectara_api_key = 'zqt_UXrBcnI2UXINZkrv4g1tQPhzj02vfdtqYJIDiA'
|
|
@@ -113,7 +113,9 @@ class TestGROQ(unittest.TestCase):
|
|
|
113
113
|
agent_config=fc_config_groq,
|
|
114
114
|
)
|
|
115
115
|
res = agent.chat("What is the stock price?")
|
|
116
|
-
self.
|
|
116
|
+
self.assertTrue(
|
|
117
|
+
any(sub in str(res) for sub in ["I don't know", "I do not have"])
|
|
118
|
+
)
|
|
117
119
|
|
|
118
120
|
|
|
119
121
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from pydantic import Field, BaseModel
|
|
3
|
-
|
|
3
|
+
from unittest.mock import patch, MagicMock
|
|
4
|
+
import requests
|
|
4
5
|
from vectara_agentic.tools import (
|
|
5
6
|
VectaraTool,
|
|
6
7
|
VectaraToolFactory,
|
|
@@ -17,6 +18,7 @@ from llama_index.core.tools import FunctionTool
|
|
|
17
18
|
vectara_corpus_key = "vectara-docs_1"
|
|
18
19
|
vectara_api_key = "zqt_UXrBcnI2UXINZkrv4g1tQPhzj02vfdtqYJIDiA"
|
|
19
20
|
|
|
21
|
+
from typing import Optional
|
|
20
22
|
|
|
21
23
|
class TestToolsPackage(unittest.TestCase):
|
|
22
24
|
|
|
@@ -89,7 +91,7 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
89
91
|
description="The ticker symbol for the company",
|
|
90
92
|
examples=["AAPL", "GOOG"],
|
|
91
93
|
)
|
|
92
|
-
year: int | str = Field(
|
|
94
|
+
year: Optional[int | str] = Field(
|
|
93
95
|
default=None,
|
|
94
96
|
description="The year this query relates to. An integer between 2015 and 2024 or a string specifying a condition on the year",
|
|
95
97
|
examples=[
|
|
@@ -109,6 +111,7 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
109
111
|
tool_args_schema=QueryToolArgs,
|
|
110
112
|
)
|
|
111
113
|
|
|
114
|
+
# test an invalid argument name
|
|
112
115
|
res = query_tool(
|
|
113
116
|
query="What is the stock price?",
|
|
114
117
|
the_year=2023,
|
|
@@ -126,6 +129,86 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
126
129
|
)
|
|
127
130
|
self.assertIn("got an unexpected keyword argument 'the_year'", str(res))
|
|
128
131
|
|
|
132
|
+
@patch.object(requests.Session, "post")
|
|
133
|
+
def test_vectara_tool_ranges(self, mock_post):
|
|
134
|
+
# Configure the mock to return a dummy response.
|
|
135
|
+
response_text = "ALL GOOD"
|
|
136
|
+
mock_response = MagicMock()
|
|
137
|
+
mock_response.status_code = 200
|
|
138
|
+
mock_response.json.return_value = {
|
|
139
|
+
'summary': response_text,
|
|
140
|
+
'search_results': [
|
|
141
|
+
{'text': 'ALL GOOD', 'document_id': '12345', 'score': 0.9},
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
mock_post.return_value = mock_response
|
|
145
|
+
|
|
146
|
+
vec_factory = VectaraToolFactory(vectara_corpus_key, vectara_api_key)
|
|
147
|
+
|
|
148
|
+
class QueryToolArgs(BaseModel):
|
|
149
|
+
ticker: str = Field(
|
|
150
|
+
description="The ticker symbol for the company",
|
|
151
|
+
examples=["AAPL", "GOOG"],
|
|
152
|
+
)
|
|
153
|
+
year: int | str = Field(
|
|
154
|
+
default=None,
|
|
155
|
+
description="The year this query relates to. An integer between 2015 and 2024 or a string specifying a condition on the year",
|
|
156
|
+
examples=[
|
|
157
|
+
2020,
|
|
158
|
+
">2021",
|
|
159
|
+
"<2023",
|
|
160
|
+
">=2021",
|
|
161
|
+
"<=2023",
|
|
162
|
+
"[2021, 2023]",
|
|
163
|
+
"[2021, 2023)",
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
query_tool = vec_factory.create_rag_tool(
|
|
168
|
+
tool_name="rag_tool",
|
|
169
|
+
tool_description="Returns a response (str) to the user query based on the data in this corpus.",
|
|
170
|
+
tool_args_schema=QueryToolArgs,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# test an invalid argument name
|
|
174
|
+
res = query_tool(
|
|
175
|
+
query="What is the stock price?",
|
|
176
|
+
year=">2023"
|
|
177
|
+
)
|
|
178
|
+
self.assertIn(response_text, str(res))
|
|
179
|
+
|
|
180
|
+
# Test a valid range
|
|
181
|
+
res = query_tool(
|
|
182
|
+
query="What is the stock price?",
|
|
183
|
+
year="[2021, 2023]",
|
|
184
|
+
)
|
|
185
|
+
self.assertIn(response_text, str(res))
|
|
186
|
+
|
|
187
|
+
# Test a valid half closed range
|
|
188
|
+
res = query_tool(
|
|
189
|
+
query="What is the stock price?",
|
|
190
|
+
year="[2020, 2023)",
|
|
191
|
+
)
|
|
192
|
+
self.assertIn(response_text, str(res))
|
|
193
|
+
|
|
194
|
+
# Test an operator
|
|
195
|
+
res = query_tool(
|
|
196
|
+
query="What is the stock price?",
|
|
197
|
+
year=">2022",
|
|
198
|
+
)
|
|
199
|
+
self.assertIn(response_text, str(res))
|
|
200
|
+
|
|
201
|
+
search_tool = vec_factory.create_search_tool(
|
|
202
|
+
tool_name="search_tool",
|
|
203
|
+
tool_description="Returns a list of documents (str) that match the user query.",
|
|
204
|
+
tool_args_schema=QueryToolArgs,
|
|
205
|
+
)
|
|
206
|
+
res = search_tool(
|
|
207
|
+
query="What is the stock price?",
|
|
208
|
+
the_year=2023,
|
|
209
|
+
)
|
|
210
|
+
self.assertIn("got an unexpected keyword argument 'the_year'", str(res))
|
|
211
|
+
|
|
129
212
|
def test_tool_factory(self):
|
|
130
213
|
def mult(x: float, y: float) -> float:
|
|
131
214
|
return x * y
|
|
@@ -152,8 +235,6 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
152
235
|
self.assertEqual(tool.metadata.tool_type, ToolType.QUERY)
|
|
153
236
|
|
|
154
237
|
def test_tool_with_many_arguments(self):
|
|
155
|
-
vectara_corpus_key = "corpus_key"
|
|
156
|
-
vectara_api_key = "api_key"
|
|
157
238
|
vec_factory = VectaraToolFactory(vectara_corpus_key, vectara_api_key)
|
|
158
239
|
|
|
159
240
|
class QueryToolArgs(BaseModel):
|
|
@@ -169,24 +250,18 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
169
250
|
arg10: str = Field(description="the tenth argument", examples=["val10"])
|
|
170
251
|
arg11: str = Field(description="the eleventh argument", examples=["val11"])
|
|
171
252
|
arg12: str = Field(description="the twelfth argument", examples=["val12"])
|
|
172
|
-
arg13: str = Field(
|
|
173
|
-
description="the thirteenth argument", examples=["val13"]
|
|
174
|
-
)
|
|
175
|
-
arg14: str = Field(
|
|
176
|
-
description="the fourteenth argument", examples=["val14"]
|
|
177
|
-
)
|
|
178
|
-
arg15: str = Field(description="the fifteenth argument", examples=["val15"])
|
|
253
|
+
arg13: str = Field(description="the thirteenth argument", examples=["val13"])
|
|
179
254
|
|
|
180
255
|
query_tool_1 = vec_factory.create_rag_tool(
|
|
181
256
|
tool_name="rag_tool",
|
|
182
257
|
tool_description="""
|
|
183
|
-
A dummy tool that takes
|
|
258
|
+
A dummy tool that takes 13 arguments and returns a response (str) to the user query based on the data in this corpus.
|
|
184
259
|
We are using this tool to test the tool factory works and does not crash with OpenAI.
|
|
185
260
|
""",
|
|
186
261
|
tool_args_schema=QueryToolArgs,
|
|
187
262
|
)
|
|
188
263
|
|
|
189
|
-
# Test with
|
|
264
|
+
# Test with 13 arguments which go over the 1024 limit.
|
|
190
265
|
config = AgentConfig(
|
|
191
266
|
agent_type=AgentType.OPENAI
|
|
192
267
|
)
|
|
@@ -208,7 +283,7 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
208
283
|
agent = Agent(
|
|
209
284
|
tools=[query_tool_1],
|
|
210
285
|
topic="Sample topic",
|
|
211
|
-
custom_instructions="Call the tool with
|
|
286
|
+
custom_instructions="Call the tool with 13 arguments for GROQ",
|
|
212
287
|
agent_config=config,
|
|
213
288
|
)
|
|
214
289
|
res = agent.chat("What is the stock price?")
|
|
@@ -223,14 +298,14 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
223
298
|
agent = Agent(
|
|
224
299
|
tools=[query_tool_1],
|
|
225
300
|
topic="Sample topic",
|
|
226
|
-
custom_instructions="Call the tool with
|
|
301
|
+
custom_instructions="Call the tool with 13 arguments for ANTHROPIC",
|
|
227
302
|
agent_config=config,
|
|
228
303
|
)
|
|
229
304
|
res = agent.chat("What is the stock price?")
|
|
230
305
|
# ANTHROPIC does not have that 1024 limit
|
|
231
306
|
self.assertIn("stock price", str(res))
|
|
232
307
|
|
|
233
|
-
# But using Compact_docstring=True, we can pass
|
|
308
|
+
# But using Compact_docstring=True, we can pass 13 arguments successfully.
|
|
234
309
|
vec_factory = VectaraToolFactory(
|
|
235
310
|
vectara_corpus_key, vectara_api_key, compact_docstring=True
|
|
236
311
|
)
|
|
@@ -251,7 +326,9 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
251
326
|
agent_config=config,
|
|
252
327
|
)
|
|
253
328
|
res = agent.chat("What is the stock price?")
|
|
254
|
-
self.
|
|
329
|
+
self.assertTrue(
|
|
330
|
+
any(sub in str(res) for sub in ["I don't know", "stock price"])
|
|
331
|
+
)
|
|
255
332
|
|
|
256
333
|
def test_public_repo(self):
|
|
257
334
|
vectara_corpus_key = "vectara-docs_1"
|
|
@@ -297,6 +374,31 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
297
374
|
"50",
|
|
298
375
|
)
|
|
299
376
|
|
|
377
|
+
def test_vectara_tool_docstring(self):
|
|
378
|
+
class DummyArgs(BaseModel):
|
|
379
|
+
foo: int = Field(..., description="how many foos", examples=[1, 2, 3])
|
|
380
|
+
bar: str = Field(
|
|
381
|
+
"baz",
|
|
382
|
+
description="what bar to use",
|
|
383
|
+
examples=["x", "y"],
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
vec_factory = VectaraToolFactory(vectara_corpus_key, vectara_api_key)
|
|
387
|
+
dummy_tool = vec_factory.create_rag_tool(
|
|
388
|
+
tool_name="dummy_tool",
|
|
389
|
+
tool_description="A dummy tool.",
|
|
390
|
+
tool_args_schema=DummyArgs,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
doc = dummy_tool.metadata.description
|
|
394
|
+
self.assertTrue(doc.startswith("dummy_tool(query: str, foo: int, bar: str) -> dict[str, Any]"))
|
|
395
|
+
self.assertIn("Args:", doc)
|
|
396
|
+
self.assertIn("query (str): The search query to perform, in the form of a question", doc)
|
|
397
|
+
self.assertIn("foo (int): how many foos (e.g., 1, 2, 3)", doc)
|
|
398
|
+
self.assertIn("bar (str, default='baz'): what bar to use (e.g., 'x', 'y')", doc)
|
|
399
|
+
self.assertIn("Returns:", doc)
|
|
400
|
+
self.assertIn("dict[str, Any]: A dictionary containing the result data.", doc)
|
|
401
|
+
|
|
300
402
|
|
|
301
403
|
if __name__ == "__main__":
|
|
302
404
|
unittest.main()
|
|
@@ -48,7 +48,7 @@ def setup_observer(config: AgentConfig, verbose: bool) -> bool:
|
|
|
48
48
|
reg_kwargs = {
|
|
49
49
|
"endpoint": phoenix_endpoint or 'http://localhost:6006/v1/traces',
|
|
50
50
|
"project_name": "vectara-agentic",
|
|
51
|
-
"batch":
|
|
51
|
+
"batch": False,
|
|
52
52
|
"set_global_tracer_provider": False,
|
|
53
53
|
}
|
|
54
54
|
tracer_provider = register(**reg_kwargs)
|
|
@@ -4,11 +4,13 @@ This file contains the prompt templates for the different types of agents.
|
|
|
4
4
|
|
|
5
5
|
# General (shared) instructions
|
|
6
6
|
GENERAL_INSTRUCTIONS = """
|
|
7
|
-
- Use tools as your main source of information, do not respond without using a tool
|
|
7
|
+
- Use tools as your main source of information, do not respond without using a tool at least once.
|
|
8
|
+
- Do not respond based on pre-trained knowledge, unless repeated calls to the tools fail or do not provide the information needed.
|
|
8
9
|
- Use the 'get_bad_topics' (if it exists) tool to determine the topics you are not allowed to discuss or respond to.
|
|
9
10
|
- Before responding to a user query that requires knowledge of the current date, call the 'get_current_date' tool to get the current date.
|
|
10
11
|
Never rely on previous knowledge of the current date.
|
|
11
12
|
Example queries that require the current date: "What is the revenue of Apple last october?" or "What was the stock price 5 days ago?".
|
|
13
|
+
Never call 'get_current_date' more than once for the same user query.
|
|
12
14
|
- When using a tool with arguments, simplify the query as much as possible if you use the tool with arguments.
|
|
13
15
|
For example, if the original query is "revenue for apple in 2021", you can use the tool with a query "revenue" with arguments year=2021 and company=apple.
|
|
14
16
|
- If a tool responds with "I do not have enough information", try one or more of the following strategies:
|
|
@@ -24,7 +26,7 @@ GENERAL_INSTRUCTIONS = """
|
|
|
24
26
|
- If a tool provides citations or references in markdown as part of its response, include the references in your response.
|
|
25
27
|
- Ensure that every URL in your response includes descriptive anchor text that clearly explains what the user can expect from the linked content.
|
|
26
28
|
Avoid using generic terms like “source” or “reference”, or the full URL, as the anchor text.
|
|
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
|
|
29
|
+
- 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 your response.
|
|
28
30
|
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
31
|
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.
|
|
30
32
|
- All URLs provided in your response must be obtained from tool output, and cannot be "https://example.com" or empty strings, and should open in a new tab.
|
|
@@ -14,14 +14,11 @@ import importlib
|
|
|
14
14
|
from collections import Counter
|
|
15
15
|
import inspect
|
|
16
16
|
from inspect import Signature, Parameter, ismethod
|
|
17
|
-
|
|
17
|
+
from pydantic import Field, create_model, ValidationError, BaseModel
|
|
18
18
|
import cloudpickle as pickle
|
|
19
19
|
|
|
20
20
|
from dotenv import load_dotenv
|
|
21
21
|
|
|
22
|
-
from pydantic import Field, create_model, ValidationError
|
|
23
|
-
|
|
24
|
-
|
|
25
22
|
from llama_index.core.memory import ChatMemoryBuffer
|
|
26
23
|
from llama_index.core.llms import ChatMessage, MessageRole
|
|
27
24
|
from llama_index.core.tools import FunctionTool
|
|
@@ -145,21 +142,53 @@ def get_field_type(field_schema: dict) -> Any:
|
|
|
145
142
|
"array": list,
|
|
146
143
|
"object": dict,
|
|
147
144
|
"number": float,
|
|
145
|
+
"null": type(None),
|
|
148
146
|
}
|
|
147
|
+
if not field_schema: # Handles empty schema {}
|
|
148
|
+
return Any
|
|
149
|
+
|
|
149
150
|
if "anyOf" in field_schema:
|
|
150
151
|
types = []
|
|
151
|
-
for
|
|
152
|
-
#
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
else:
|
|
156
|
-
types.append(Any)
|
|
157
|
-
# Return a Union of the types. For example, Union[str, int]
|
|
152
|
+
for option_schema in field_schema["anyOf"]:
|
|
153
|
+
types.append(get_field_type(option_schema)) # Recursive call
|
|
154
|
+
if not types:
|
|
155
|
+
return Any
|
|
158
156
|
return Union[tuple(types)]
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
|
|
158
|
+
if "type" in field_schema and isinstance(field_schema["type"], list):
|
|
159
|
+
types = []
|
|
160
|
+
for type_name in field_schema["type"]:
|
|
161
|
+
if type_name == "array":
|
|
162
|
+
item_schema = field_schema.get("items", {})
|
|
163
|
+
types.append(List[get_field_type(item_schema)])
|
|
164
|
+
elif type_name in json_type_to_python:
|
|
165
|
+
types.append(json_type_to_python[type_name])
|
|
166
|
+
else:
|
|
167
|
+
types.append(Any) # Fallback for unknown types in the list
|
|
168
|
+
if not types:
|
|
169
|
+
return Any
|
|
170
|
+
return Union[tuple(types)] # type: ignore
|
|
171
|
+
|
|
172
|
+
if "type" in field_schema:
|
|
173
|
+
schema_type_name = field_schema["type"]
|
|
174
|
+
if schema_type_name == "array":
|
|
175
|
+
item_schema = field_schema.get(
|
|
176
|
+
"items", {}
|
|
177
|
+
) # Default to Any if "items" is missing
|
|
178
|
+
return List[get_field_type(item_schema)]
|
|
179
|
+
|
|
180
|
+
return json_type_to_python.get(schema_type_name, Any)
|
|
181
|
+
|
|
182
|
+
# If only "items" is present (implies array by some conventions, but less standard)
|
|
183
|
+
# Or if it's a schema with other keywords like 'properties' (implying object)
|
|
184
|
+
# For simplicity, if no "type" or "anyOf" at this point, default to Any or add more specific handling.
|
|
185
|
+
# If 'properties' in field_schema or 'additionalProperties' in field_schema, it's likely an object.
|
|
186
|
+
if "properties" in field_schema or "additionalProperties" in field_schema:
|
|
187
|
+
# This path might need to reconstruct a nested Pydantic model if you encounter such schemas.
|
|
188
|
+
# For now, treating as 'dict' or 'Any' might be a simpler placeholder.
|
|
189
|
+
return dict # Or Any, or more sophisticated object reconstruction.
|
|
190
|
+
|
|
191
|
+
return Any
|
|
163
192
|
|
|
164
193
|
|
|
165
194
|
class Agent:
|
|
@@ -264,7 +293,9 @@ class Agent:
|
|
|
264
293
|
bad_tools_str = llm.complete(prompt).text
|
|
265
294
|
if bad_tools_str and bad_tools_str != "<OKAY>":
|
|
266
295
|
bad_tools = [tool.strip() for tool in bad_tools_str.split(",")]
|
|
267
|
-
numbered = ", ".join(
|
|
296
|
+
numbered = ", ".join(
|
|
297
|
+
f"({i}) {tool}" for i, tool in enumerate(bad_tools, 1)
|
|
298
|
+
)
|
|
268
299
|
raise ValueError(
|
|
269
300
|
f"The Agent custom instructions mention these invalid tools: {numbered}"
|
|
270
301
|
)
|
|
@@ -1143,41 +1174,66 @@ class Agent:
|
|
|
1143
1174
|
tools = []
|
|
1144
1175
|
|
|
1145
1176
|
for tool_data in data["tools"]:
|
|
1146
|
-
|
|
1177
|
+
query_args_model = None
|
|
1147
1178
|
if tool_data.get("fn_schema"):
|
|
1148
1179
|
schema_info = tool_data["fn_schema"]
|
|
1149
1180
|
try:
|
|
1150
1181
|
module_name = schema_info["metadata"]["module"]
|
|
1151
1182
|
class_name = schema_info["metadata"]["class"]
|
|
1152
1183
|
mod = importlib.import_module(module_name)
|
|
1153
|
-
|
|
1154
|
-
|
|
1184
|
+
candidate_cls = getattr(mod, class_name)
|
|
1185
|
+
if inspect.isclass(candidate_cls) and issubclass(
|
|
1186
|
+
candidate_cls, BaseModel
|
|
1187
|
+
):
|
|
1188
|
+
query_args_model = candidate_cls
|
|
1189
|
+
else:
|
|
1190
|
+
# It's not the Pydantic model class we expected (e.g., it's the function itself)
|
|
1191
|
+
# Force fallback to JSON schema reconstruction by raising an error.
|
|
1192
|
+
raise ImportError(
|
|
1193
|
+
f"Retrieved '{class_name}' from '{module_name}' is not a Pydantic BaseModel class. "
|
|
1194
|
+
"Falling back to JSON schema reconstruction."
|
|
1195
|
+
)
|
|
1155
1196
|
except Exception:
|
|
1156
1197
|
# Fallback: rebuild using the JSON schema
|
|
1157
1198
|
field_definitions = {}
|
|
1158
|
-
|
|
1159
|
-
|
|
1199
|
+
json_schema_to_rebuild = schema_info.get("schema")
|
|
1200
|
+
if json_schema_to_rebuild and isinstance(
|
|
1201
|
+
json_schema_to_rebuild, dict
|
|
1160
1202
|
):
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1203
|
+
for field, values in json_schema_to_rebuild.get(
|
|
1204
|
+
"properties", {}
|
|
1205
|
+
).items():
|
|
1206
|
+
field_type = get_field_type(values)
|
|
1207
|
+
field_description = values.get(
|
|
1208
|
+
"description"
|
|
1209
|
+
) # Defaults to None
|
|
1210
|
+
if "default" in values:
|
|
1211
|
+
field_definitions[field] = (
|
|
1212
|
+
field_type,
|
|
1213
|
+
Field(
|
|
1214
|
+
description=field_description,
|
|
1215
|
+
default=values["default"],
|
|
1216
|
+
),
|
|
1217
|
+
)
|
|
1218
|
+
else:
|
|
1219
|
+
field_definitions[field] = (
|
|
1220
|
+
field_type,
|
|
1221
|
+
Field(description=field_description),
|
|
1222
|
+
)
|
|
1223
|
+
query_args_model = create_model(
|
|
1224
|
+
json_schema_to_rebuild.get(
|
|
1225
|
+
"title", f"{tool_data['name']}_QueryArgs"
|
|
1226
|
+
),
|
|
1227
|
+
**field_definitions,
|
|
1228
|
+
)
|
|
1229
|
+
else: # If schema part is missing or not a dict, create a default empty model
|
|
1230
|
+
query_args_model = create_model(
|
|
1231
|
+
f"{tool_data['name']}_QueryArgs"
|
|
1232
|
+
)
|
|
1233
|
+
|
|
1234
|
+
# If fn_schema was not in tool_data or reconstruction failed badly, default to empty pydantic model
|
|
1235
|
+
if query_args_model is None:
|
|
1236
|
+
query_args_model = create_model(f"{tool_data['name']}_QueryArgs")
|
|
1181
1237
|
|
|
1182
1238
|
fn = (
|
|
1183
1239
|
pickle.loads(tool_data["fn"].encode("latin-1"))
|
|
@@ -112,7 +112,7 @@ class DatabaseTools:
|
|
|
112
112
|
List[str]: a list of Document objects from the database.
|
|
113
113
|
"""
|
|
114
114
|
if sql_query is None:
|
|
115
|
-
raise ValueError("A query parameter is necessary to filter the data")
|
|
115
|
+
raise ValueError("A query parameter is necessary to filter the data.")
|
|
116
116
|
|
|
117
117
|
count_query = f"SELECT COUNT(*) FROM ({sql_query})"
|
|
118
118
|
try:
|
|
@@ -123,7 +123,7 @@ class DatabaseTools:
|
|
|
123
123
|
if num_rows > self.max_rows:
|
|
124
124
|
return [
|
|
125
125
|
f"The query is expected to return more than {self.max_rows} rows. "
|
|
126
|
-
"Please refactor your query to make it return less rows. "
|
|
126
|
+
"Please refactor your query to make it return less rows and try again. "
|
|
127
127
|
]
|
|
128
128
|
try:
|
|
129
129
|
res = self._load_data(sql_query)
|
|
@@ -69,12 +69,16 @@ def get_tokenizer_for_model(
|
|
|
69
69
|
"""
|
|
70
70
|
Get the tokenizer for the specified model, as determined by the role & config.
|
|
71
71
|
"""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
try:
|
|
73
|
+
model_provider, model_name = _get_llm_params_for_role(role, config)
|
|
74
|
+
if model_provider == ModelProvider.OPENAI:
|
|
75
|
+
# This might raise an exception if the model_name is unknown to tiktoken
|
|
76
|
+
return tiktoken.encoding_for_model(model_name).encode
|
|
77
|
+
if model_provider == ModelProvider.ANTHROPIC:
|
|
78
|
+
return Anthropic().tokenizer
|
|
79
|
+
except Exception:
|
|
80
|
+
print(f"Error getting tokenizer for model {model_name}, ignoring")
|
|
81
|
+
return None
|
|
78
82
|
return None
|
|
79
83
|
|
|
80
84
|
|
|
@@ -7,7 +7,7 @@ import re
|
|
|
7
7
|
|
|
8
8
|
from typing import (
|
|
9
9
|
Callable, List, Dict, Any, Optional, Union, Type, Tuple,
|
|
10
|
-
Sequence
|
|
10
|
+
Sequence, get_origin, get_args
|
|
11
11
|
)
|
|
12
12
|
from pydantic import BaseModel, create_model
|
|
13
13
|
from pydantic_core import PydanticUndefined
|
|
@@ -140,37 +140,20 @@ class VectaraTool(FunctionTool):
|
|
|
140
140
|
return str(self)
|
|
141
141
|
|
|
142
142
|
def __eq__(self, other):
|
|
143
|
-
if not isinstance(other, VectaraTool):
|
|
144
|
-
return False
|
|
145
|
-
|
|
146
|
-
if self.metadata.tool_type != other.metadata.tool_type:
|
|
147
|
-
return False
|
|
148
|
-
|
|
149
|
-
if self.metadata.name != other.metadata.name:
|
|
150
|
-
return False
|
|
151
|
-
|
|
152
|
-
# If schema is a dict-like object, compare the dict representation
|
|
153
143
|
try:
|
|
154
144
|
# Try to get schema as dict if possible
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
other_schema = other.metadata.fn_schema.schema
|
|
158
|
-
|
|
159
|
-
# Compare only properties and required fields
|
|
160
|
-
self_props = self_schema.get("properties", {})
|
|
161
|
-
other_props = other_schema.get("properties", {})
|
|
162
|
-
|
|
163
|
-
self_required = self_schema.get("required", [])
|
|
164
|
-
other_required = other_schema.get("required", [])
|
|
165
|
-
|
|
166
|
-
return self_props.keys() == other_props.keys() and set(
|
|
167
|
-
self_required
|
|
168
|
-
) == set(other_required)
|
|
145
|
+
self_schema = self.metadata.fn_schema.model_json_schema()
|
|
146
|
+
other_schema = other.metadata.fn_schema.model_json_schema()
|
|
169
147
|
except Exception:
|
|
170
|
-
|
|
171
|
-
pass
|
|
148
|
+
return False
|
|
172
149
|
|
|
173
|
-
|
|
150
|
+
is_equal = (
|
|
151
|
+
isinstance(other, VectaraTool)
|
|
152
|
+
and self.metadata.tool_type == other.metadata.tool_type
|
|
153
|
+
and self.metadata.name == other.metadata.name
|
|
154
|
+
and self_schema == other_schema
|
|
155
|
+
)
|
|
156
|
+
return is_equal
|
|
174
157
|
|
|
175
158
|
def call(
|
|
176
159
|
self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
|
|
@@ -185,7 +168,7 @@ class VectaraTool(FunctionTool):
|
|
|
185
168
|
err_output = ToolOutput(
|
|
186
169
|
tool_name=self.metadata.name,
|
|
187
170
|
content=(
|
|
188
|
-
f"Wrong argument used when calling {self.metadata.name}: {str(e)}.
|
|
171
|
+
f"Wrong argument used when calling {self.metadata.name}: {str(e)}."
|
|
189
172
|
f"Valid arguments: {params_str}. please call the tool again with the correct arguments."
|
|
190
173
|
),
|
|
191
174
|
raw_input={"args": args, "kwargs": kwargs},
|
|
@@ -222,9 +205,10 @@ class VectaraTool(FunctionTool):
|
|
|
222
205
|
)
|
|
223
206
|
return err_output
|
|
224
207
|
except Exception as e:
|
|
208
|
+
import traceback
|
|
225
209
|
err_output = ToolOutput(
|
|
226
210
|
tool_name=self.metadata.name,
|
|
227
|
-
content=f"Tool {self.metadata.name} Malfunction: {str(e)}",
|
|
211
|
+
content=f"Tool {self.metadata.name} Malfunction: {str(e)}, traceback: {traceback.format_exc()}",
|
|
228
212
|
raw_input={"args": args, "kwargs": kwargs},
|
|
229
213
|
raw_output={"response": str(e)},
|
|
230
214
|
)
|
|
@@ -234,13 +218,36 @@ class VectaraTool(FunctionTool):
|
|
|
234
218
|
class EmptyBaseModel(BaseModel):
|
|
235
219
|
"""empty base model"""
|
|
236
220
|
|
|
237
|
-
def
|
|
238
|
-
|
|
239
|
-
|
|
221
|
+
def _clean_type_repr(type_repr: str) -> str:
|
|
222
|
+
"""Cleans the string representation of a type."""
|
|
223
|
+
# Replace <class 'somename'> with somename
|
|
224
|
+
match = re.match(r"<class '(\w+)'>", type_repr)
|
|
225
|
+
if match:
|
|
226
|
+
type_repr = match.group(1)
|
|
240
227
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
228
|
+
type_repr = type_repr.replace("typing.", "")
|
|
229
|
+
return type_repr
|
|
230
|
+
|
|
231
|
+
def _format_type(annotation) -> str:
|
|
232
|
+
"""
|
|
233
|
+
Turn things like Union[int, str, NoneType] into 'int | str | None',
|
|
234
|
+
and replace any leftover 'NoneType' → 'None'.
|
|
235
|
+
"""
|
|
236
|
+
origin = get_origin(annotation)
|
|
237
|
+
if origin is Union:
|
|
238
|
+
parts = []
|
|
239
|
+
for arg in get_args(annotation):
|
|
240
|
+
if arg is type(None):
|
|
241
|
+
parts.append("None")
|
|
242
|
+
else:
|
|
243
|
+
# recurse in case of nested unions
|
|
244
|
+
parts.append(_format_type(arg))
|
|
245
|
+
return " | ".join(parts)
|
|
246
|
+
|
|
247
|
+
# Fallback
|
|
248
|
+
type_repr = str(annotation)
|
|
249
|
+
type_repr = _clean_type_repr(type_repr)
|
|
250
|
+
return type_repr.replace("NoneType", "None")
|
|
244
251
|
|
|
245
252
|
def _make_docstring(
|
|
246
253
|
function: Callable[..., ToolOutput],
|
|
@@ -250,46 +257,68 @@ def _make_docstring(
|
|
|
250
257
|
all_params: List[inspect.Parameter],
|
|
251
258
|
compact_docstring: bool,
|
|
252
259
|
) -> str:
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
"""
|
|
261
|
+
Generates a docstring for a function based on its signature, description,
|
|
262
|
+
and Pydantic schema, correctly handling complex type annotations.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
function: The function for which to generate the docstring.
|
|
266
|
+
tool_name: The desired name for the tool/function in the docstring.
|
|
267
|
+
tool_description: The main description of the tool/function.
|
|
268
|
+
fn_schema: The Pydantic model representing the function's arguments schema.
|
|
269
|
+
all_params: A list of inspect.Parameter objects for the function signature.
|
|
270
|
+
compact_docstring: If True, omits the signature line in the main description.
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
A formatted docstring string.
|
|
274
|
+
"""
|
|
275
|
+
params_str_parts = []
|
|
276
|
+
for p in all_params:
|
|
277
|
+
type_repr = _format_type(p.annotation)
|
|
278
|
+
params_str_parts.append(f"{p.name}: {type_repr}")
|
|
279
|
+
|
|
280
|
+
params_str = ", ".join(params_str_parts)
|
|
257
281
|
signature_line = f"{tool_name}({params_str}) -> dict[str, Any]"
|
|
282
|
+
|
|
258
283
|
if compact_docstring:
|
|
259
284
|
doc_lines = [tool_description.strip()]
|
|
260
285
|
else:
|
|
261
286
|
doc_lines = [signature_line, "", tool_description.strip()]
|
|
262
|
-
doc_lines += [
|
|
263
|
-
"",
|
|
264
|
-
"Args:",
|
|
265
|
-
]
|
|
266
287
|
|
|
267
288
|
full_schema = fn_schema.model_json_schema()
|
|
268
289
|
props = full_schema.get("properties", {})
|
|
269
|
-
for prop_name, schema_prop in props.items():
|
|
270
|
-
desc = schema_prop.get("description", "")
|
|
271
|
-
|
|
272
|
-
# pick up any examples you declared on the Field or via schema_extra
|
|
273
|
-
examples = schema_prop.get("examples", [])
|
|
274
|
-
default = schema_prop.get("default", PydanticUndefined)
|
|
275
|
-
|
|
276
|
-
# format the type, default, description, examples
|
|
277
|
-
# find the matching inspect.Parameter so you get its annotation
|
|
278
|
-
param = next((p for p in all_params if p.name == prop_name), None)
|
|
279
|
-
if param and hasattr(param.annotation, "__name__"):
|
|
280
|
-
ty = param.annotation.__name__
|
|
281
|
-
else:
|
|
282
|
-
ty = schema_prop.get("type", "")
|
|
283
|
-
|
|
284
|
-
# inline default if present
|
|
285
|
-
default_txt = f", default={default!r}" if default is not PydanticUndefined else ""
|
|
286
|
-
|
|
287
|
-
# inline examples if any
|
|
288
|
-
if examples:
|
|
289
|
-
examples_txt = ", ".join(repr(e) for e in examples)
|
|
290
|
-
desc = f"{desc} (e.g., {examples_txt})"
|
|
291
290
|
|
|
292
|
-
|
|
291
|
+
if props:
|
|
292
|
+
doc_lines.extend(["", "Args:"])
|
|
293
|
+
for prop_name, schema_prop in props.items():
|
|
294
|
+
desc = schema_prop.get("description", "")
|
|
295
|
+
|
|
296
|
+
# pick up any examples you declared on the Field or via schema_extra
|
|
297
|
+
examples = schema_prop.get("examples", [])
|
|
298
|
+
default = schema_prop.get("default", PydanticUndefined)
|
|
299
|
+
|
|
300
|
+
# format the type, default, description, examples
|
|
301
|
+
# find the matching inspect.Parameter so you get its annotation
|
|
302
|
+
param = next((p for p in all_params if p.name == prop_name), None)
|
|
303
|
+
ty_str = ""
|
|
304
|
+
if param:
|
|
305
|
+
ty_str = _format_type(param.annotation)
|
|
306
|
+
elif "type" in schema_prop:
|
|
307
|
+
ty_info = schema_prop["type"]
|
|
308
|
+
if isinstance(ty_info, str):
|
|
309
|
+
ty_str = _clean_type_repr(ty_info)
|
|
310
|
+
elif isinstance(ty_info, list): # Handle JSON schema array type e.g., ["integer", "string"]
|
|
311
|
+
ty_str = " | ".join([_clean_type_repr(t) for t in ty_info])
|
|
312
|
+
|
|
313
|
+
# inline default if present
|
|
314
|
+
default_txt = f", default={default!r}" if default is not PydanticUndefined else ""
|
|
315
|
+
|
|
316
|
+
# inline examples if any
|
|
317
|
+
if examples:
|
|
318
|
+
examples_txt = ", ".join(repr(e) for e in examples)
|
|
319
|
+
desc = f"{desc} (e.g., {examples_txt})"
|
|
320
|
+
|
|
321
|
+
doc_lines.append(f" - {prop_name} ({ty_str}{default_txt}): {desc}")
|
|
293
322
|
|
|
294
323
|
doc_lines.append("")
|
|
295
324
|
doc_lines.append("Returns:")
|
|
@@ -331,36 +360,33 @@ def create_tool_from_dynamic_function(
|
|
|
331
360
|
if not isinstance(tool_args_schema, type) or not issubclass(tool_args_schema, BaseModel):
|
|
332
361
|
raise TypeError("tool_args_schema must be a Pydantic BaseModel subclass")
|
|
333
362
|
|
|
334
|
-
fields = {}
|
|
363
|
+
fields: Dict[str, Any] = {}
|
|
335
364
|
base_params = []
|
|
336
365
|
for field_name, field_info in base_params_model.model_fields.items():
|
|
337
|
-
|
|
338
|
-
default_value = _unwrap_default(field_info.default)
|
|
366
|
+
default = Ellipsis if field_info.default is PydanticUndefined else field_info.default
|
|
339
367
|
param = inspect.Parameter(
|
|
340
368
|
field_name,
|
|
341
369
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
342
|
-
default=
|
|
343
|
-
annotation=
|
|
370
|
+
default=default if default is not Ellipsis else inspect.Parameter.empty,
|
|
371
|
+
annotation=field_info.annotation,
|
|
344
372
|
)
|
|
345
373
|
base_params.append(param)
|
|
346
|
-
fields[field_name] = (
|
|
374
|
+
fields[field_name] = (field_info.annotation, field_info)
|
|
347
375
|
|
|
348
376
|
# Add tool_args_schema fields to the fields dict if not already included.
|
|
349
|
-
# Also add them to the function signature by creating new inspect.Parameter objects.
|
|
350
377
|
for field_name, field_info in tool_args_schema.model_fields.items():
|
|
351
378
|
if field_name in fields:
|
|
352
379
|
continue
|
|
353
380
|
|
|
354
|
-
|
|
355
|
-
default_value = _unwrap_default(field_info.default)
|
|
381
|
+
default = Ellipsis if field_info.default is PydanticUndefined else field_info.default
|
|
356
382
|
param = inspect.Parameter(
|
|
357
383
|
field_name,
|
|
358
384
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
359
|
-
default=
|
|
360
|
-
annotation=
|
|
385
|
+
default=default if default is not Ellipsis else inspect.Parameter.empty,
|
|
386
|
+
annotation=field_info.annotation,
|
|
361
387
|
)
|
|
362
388
|
base_params.append(param)
|
|
363
|
-
fields[field_name] = (
|
|
389
|
+
fields[field_name] = (field_info.annotation, field_info)
|
|
364
390
|
|
|
365
391
|
# Create the dynamic schema with both base_params_model and tool_args_schema fields.
|
|
366
392
|
fn_schema = create_model(f"{tool_name}_schema", **fields)
|
|
@@ -402,7 +428,7 @@ _PARSE_RANGE_REGEX = re.compile(
|
|
|
402
428
|
)
|
|
403
429
|
|
|
404
430
|
|
|
405
|
-
def _parse_range(val_str: str) -> Tuple[
|
|
431
|
+
def _parse_range(val_str: str) -> Tuple[str, str, bool, bool]:
|
|
406
432
|
"""
|
|
407
433
|
Parses '[1,10)' or '(0.5, 5]' etc.
|
|
408
434
|
Returns (start, end, start_incl, end_incl) or raises ValueError.
|
|
@@ -411,10 +437,10 @@ def _parse_range(val_str: str) -> Tuple[float, float, bool, bool]:
|
|
|
411
437
|
if not m:
|
|
412
438
|
raise ValueError(f"Invalid range syntax: {val_str!r}")
|
|
413
439
|
start_inc = m.group(1) == "["
|
|
414
|
-
end_inc = m.group(
|
|
415
|
-
start =
|
|
416
|
-
end =
|
|
417
|
-
if start > end:
|
|
440
|
+
end_inc = m.group(6) == "]"
|
|
441
|
+
start = m.group(2)
|
|
442
|
+
end = m.group(4)
|
|
443
|
+
if float(start) > float(end):
|
|
418
444
|
raise ValueError(f"Range lower bound greater than upper bound: {val_str!r}")
|
|
419
445
|
return start, end, start_inc, end_inc
|
|
420
446
|
|
|
@@ -219,7 +219,7 @@ class VectaraToolFactory:
|
|
|
219
219
|
response = vectara_retriever.retrieve(query)
|
|
220
220
|
|
|
221
221
|
if len(response) == 0:
|
|
222
|
-
msg = "Vectara Tool failed to
|
|
222
|
+
msg = "Vectara Tool failed to retrieve any results for the query."
|
|
223
223
|
return ToolOutput(
|
|
224
224
|
tool_name=search_function.__name__,
|
|
225
225
|
content=msg,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vectara_agentic
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
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,18 +16,18 @@ 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.
|
|
20
|
-
Requires-Dist: llama-index-indices-managed-vectara==0.4.
|
|
19
|
+
Requires-Dist: llama-index==0.12.34
|
|
20
|
+
Requires-Dist: llama-index-indices-managed-vectara==0.4.5
|
|
21
21
|
Requires-Dist: llama-index-agent-llm-compiler==0.3.0
|
|
22
22
|
Requires-Dist: llama-index-agent-lats==0.3.0
|
|
23
|
-
Requires-Dist: llama-index-agent-openai==0.4.
|
|
23
|
+
Requires-Dist: llama-index-agent-openai==0.4.7
|
|
24
24
|
Requires-Dist: llama-index-llms-openai==0.3.38
|
|
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
29
|
Requires-Dist: llama-index-llms-cohere==0.4.1
|
|
30
|
-
Requires-Dist: llama-index-llms-google-genai==0.1.
|
|
30
|
+
Requires-Dist: llama-index-llms-google-genai==0.1.12
|
|
31
31
|
Requires-Dist: llama-index-llms-bedrock==0.3.8
|
|
32
32
|
Requires-Dist: llama-index-tools-yahoo-finance==0.3.0
|
|
33
33
|
Requires-Dist: llama-index-tools-arxiv==0.3.0
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
llama-index==0.12.
|
|
2
|
-
llama-index-indices-managed-vectara==0.4.
|
|
1
|
+
llama-index==0.12.34
|
|
2
|
+
llama-index-indices-managed-vectara==0.4.5
|
|
3
3
|
llama-index-agent-llm-compiler==0.3.0
|
|
4
4
|
llama-index-agent-lats==0.3.0
|
|
5
|
-
llama-index-agent-openai==0.4.
|
|
5
|
+
llama-index-agent-openai==0.4.7
|
|
6
6
|
llama-index-llms-openai==0.3.38
|
|
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
11
|
llama-index-llms-cohere==0.4.1
|
|
12
|
-
llama-index-llms-google-genai==0.1.
|
|
12
|
+
llama-index-llms-google-genai==0.1.12
|
|
13
13
|
llama-index-llms-bedrock==0.3.8
|
|
14
14
|
llama-index-tools-yahoo-finance==0.3.0
|
|
15
15
|
llama-index-tools-arxiv==0.3.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vectara_agentic-0.2.15 → vectara_agentic-0.2.16}/vectara_agentic.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|