vectara-agentic 0.2.16__tar.gz → 0.2.18__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 (45) hide show
  1. {vectara_agentic-0.2.16/vectara_agentic.egg-info → vectara_agentic-0.2.18}/PKG-INFO +62 -18
  2. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/README.md +52 -11
  3. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/requirements.txt +9 -6
  4. vectara_agentic-0.2.18/tests/test_api_endpoint.py +126 -0
  5. vectara_agentic-0.2.18/tests/test_gemini.py +115 -0
  6. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_groq.py +0 -7
  7. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_tools.py +9 -33
  8. vectara_agentic-0.2.18/tests/test_workflow.py +134 -0
  9. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/_version.py +1 -1
  10. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/agent.py +50 -28
  11. vectara_agentic-0.2.18/vectara_agentic/agent_endpoint.py +252 -0
  12. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/llm_utils.py +0 -17
  13. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/sub_query_workflow.py +5 -2
  14. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/tool_utils.py +3 -43
  15. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/tools.py +2 -0
  16. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/utils.py +1 -1
  17. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18/vectara_agentic.egg-info}/PKG-INFO +62 -18
  18. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic.egg-info/SOURCES.txt +2 -0
  19. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic.egg-info/requires.txt +9 -6
  20. vectara_agentic-0.2.16/tests/test_workflow.py +0 -67
  21. vectara_agentic-0.2.16/vectara_agentic/agent_endpoint.py +0 -62
  22. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/LICENSE +0 -0
  23. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/MANIFEST.in +0 -0
  24. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/setup.cfg +0 -0
  25. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/setup.py +0 -0
  26. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/__init__.py +0 -0
  27. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/endpoint.py +0 -0
  28. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_agent.py +0 -0
  29. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_agent_planning.py +0 -0
  30. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_agent_type.py +0 -0
  31. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_fallback.py +0 -0
  32. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_private_llm.py +0 -0
  33. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_return_direct.py +0 -0
  34. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_serialization.py +0 -0
  35. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/tests/test_vectara_llms.py +0 -0
  36. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/__init__.py +0 -0
  37. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/_callback.py +0 -0
  38. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/_observability.py +0 -0
  39. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/_prompts.py +0 -0
  40. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/agent_config.py +0 -0
  41. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/db_tools.py +0 -0
  42. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/tools_catalog.py +0 -0
  43. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic/types.py +0 -0
  44. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/vectara_agentic.egg-info/dependency_links.txt +0 -0
  45. {vectara_agentic-0.2.16 → vectara_agentic-0.2.18}/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.16
3
+ Version: 0.2.18
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,12 +16,13 @@ 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.34
19
+ Requires-Dist: llama-index==0.12.35
20
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.7
24
- Requires-Dist: llama-index-llms-openai==0.3.38
23
+ Requires-Dist: llama-index-agent-openai==0.4.8
24
+ Requires-Dist: llama-index-llms-openai==0.3.42
25
+ Requires-Dist: llama-index-llms-openai-like>=0.3.5
25
26
  Requires-Dist: llama-index-llms-anthropic==0.6.10
26
27
  Requires-Dist: llama-index-llms-together==0.3.1
27
28
  Requires-Dist: llama-index-llms-groq==0.3.1
@@ -36,15 +37,17 @@ Requires-Dist: llama-index-tools-google==0.3.0
36
37
  Requires-Dist: llama-index-tools-tavily_research==0.3.0
37
38
  Requires-Dist: llama_index.tools.brave_search==0.3.0
38
39
  Requires-Dist: llama-index-tools-neo4j==0.3.0
40
+ Requires-Dist: llama-index-tools-waii==0.3.0
39
41
  Requires-Dist: llama-index-graph-stores-kuzu==0.7.0
42
+ Requires-Dist: llama-index-tools-salesforce==0.3.0
40
43
  Requires-Dist: llama-index-tools-slack==0.3.0
41
44
  Requires-Dist: llama-index-tools-exa==0.3.0
42
45
  Requires-Dist: llama-index-tools-wikipedia==0.3.0
43
46
  Requires-Dist: llama-index-tools-bing-search==0.3.0
44
- Requires-Dist: tavily-python==0.5.4
45
- Requires-Dist: exa-py==1.12.0
47
+ Requires-Dist: tavily-python==0.7.2
48
+ Requires-Dist: exa-py==1.12.1
46
49
  Requires-Dist: openinference-instrumentation-llama-index==4.2.1
47
- Requires-Dist: opentelemetry-proto==1.32.1
50
+ Requires-Dist: opentelemetry-proto>=1.31.0
48
51
  Requires-Dist: arize-phoenix==8.26.1
49
52
  Requires-Dist: arize-phoenix-otel==0.9.2
50
53
  Requires-Dist: protobuf==5.29.3
@@ -365,51 +368,92 @@ vectara-agentic includes various other tools from LlamaIndex ToolSpecs:
365
368
  * Tavily Search: Real-time web search using [Tavily API](https://tavily.com/)
366
369
  ```python
367
370
  from vectara_agentic.tools_catalog import ToolsCatalog
368
- tavily_tool = ToolsCatalog(agent_config).tavily_search
371
+ tools_factory = ToolsFactory()
372
+ tavily_tools = tools_factory.get_llama_index_tools(
373
+ tool_package_name="tavily_research",
374
+ tool_spec_name="TavilyToolSpec",
375
+ api_key=str(os.environ["TAVILY_API_KEY"]),
376
+ )
369
377
  ```
370
378
  * EXA.AI: Advanced web search and data extraction
371
379
  ```python
372
- exa_tool = ToolsCatalog(agent_config).exa_search
380
+ exa_tools = tools_factory.get_llama_index_tools(
381
+ tool_package_name="exa.ai",
382
+ tool_spec_name="ExaToolSpec",
383
+ api_key=str(os.environ["EXA_API_KEY"]),
384
+ )
373
385
  ```
374
386
  * Brave Search: Web search using Brave's search engine
375
387
  ```python
376
- brave_tool = ToolsCatalog(agent_config).brave_search
388
+ brave_tools = tools_factory.get_llama_index_tools(
389
+ tool_package_name="brave_search",
390
+ tool_spec_name="BraveSearchToolSpec",
391
+ api_key=str(os.environ["BRAVE_API_KEY"]),
392
+ )
377
393
  ```
378
394
 
379
395
  * **Academic Tools**
380
396
  * arXiv: Search and retrieve academic papers
381
397
  ```python
382
- arxiv_tool = ToolsCatalog(agent_config).arxiv_search
398
+ arxiv_tools = tools_factory.get_llama_index_tools(
399
+ tool_package_name="arxiv",
400
+ tool_spec_name="ArxivToolSpec",
401
+ )
383
402
  ```
384
403
 
385
- * **Graph Database Tools**
404
+ * **Database Tools**
386
405
  * Neo4j: Graph database integration
387
406
  ```python
388
- neo4j_tool = ToolsCatalog(agent_config).neo4j_query
407
+ neo4j_tools = tools_factory.get_llama_index_tools(
408
+ tool_package_name="neo4j",
409
+ tool_spec_name="Neo4jQueryToolSpec",
410
+ )
389
411
  ```
390
412
  * Kuzu: Lightweight graph database
391
413
  ```python
392
- kuzu_tool = ToolsCatalog(agent_config).kuzu_query
414
+ kuzu_tools = tools_factory.get_llama_index_tools(
415
+ tool_package_name="kuzu",
416
+ tool_spec_name="KuzuGraphStore",
417
+ )
418
+ ```
419
+ * Waii: tools for natural langauge query of a relational database
420
+ ```python
421
+ waii_tools = tools_factory.get_llama_index_tools(
422
+ tool_package_name="waii",
423
+ tool_spec_name="WaiiToolSpec",
424
+ )
393
425
  ```
394
426
 
395
427
  * **Google Tools**
396
428
  * Gmail: Read and send emails
397
429
  ```python
398
- gmail_tool = ToolsCatalog(agent_config).gmail
430
+ gmail_tools = tools_factory.get_llama_index_tools(
431
+ tool_package_name="google",
432
+ tool_spec_name="GmailToolSpec",
433
+ )
399
434
  ```
400
435
  * Calendar: Manage calendar events
401
436
  ```python
402
- calendar_tool = ToolsCatalog(agent_config).calendar
437
+ calendar_tools = tools_factory.get_llama_index_tools(
438
+ tool_package_name="google",
439
+ tool_spec_name="GoogleCalendarToolSpec",
440
+ )
403
441
  ```
404
442
  * Search: Google search integration
405
443
  ```python
406
- google_search_tool = ToolsCatalog(agent_config).google_search
444
+ search_tools = tools_factory.get_llama_index_tools(
445
+ tool_package_name="google",
446
+ tool_spec_name="GoogleSearchToolSpec",
447
+ )
407
448
  ```
408
449
 
409
450
  * **Communication Tools**
410
451
  * Slack: Send messages and interact with Slack
411
452
  ```python
412
- slack_tool = ToolsCatalog(agent_config).slack
453
+ slack_tools = tools_factory.get_llama_index_tools(
454
+ tool_package_name="slack",
455
+ tool_spec_name="SlackToolSpec",
456
+ )
413
457
  ```
414
458
 
415
459
  For detailed setup instructions and API key requirements, please refer the instructions on [LlamaIndex hub](https://llamahub.ai/?tab=tools) for the specific tool.
@@ -295,51 +295,92 @@ vectara-agentic includes various other tools from LlamaIndex ToolSpecs:
295
295
  * Tavily Search: Real-time web search using [Tavily API](https://tavily.com/)
296
296
  ```python
297
297
  from vectara_agentic.tools_catalog import ToolsCatalog
298
- tavily_tool = ToolsCatalog(agent_config).tavily_search
298
+ tools_factory = ToolsFactory()
299
+ tavily_tools = tools_factory.get_llama_index_tools(
300
+ tool_package_name="tavily_research",
301
+ tool_spec_name="TavilyToolSpec",
302
+ api_key=str(os.environ["TAVILY_API_KEY"]),
303
+ )
299
304
  ```
300
305
  * EXA.AI: Advanced web search and data extraction
301
306
  ```python
302
- exa_tool = ToolsCatalog(agent_config).exa_search
307
+ exa_tools = tools_factory.get_llama_index_tools(
308
+ tool_package_name="exa.ai",
309
+ tool_spec_name="ExaToolSpec",
310
+ api_key=str(os.environ["EXA_API_KEY"]),
311
+ )
303
312
  ```
304
313
  * Brave Search: Web search using Brave's search engine
305
314
  ```python
306
- brave_tool = ToolsCatalog(agent_config).brave_search
315
+ brave_tools = tools_factory.get_llama_index_tools(
316
+ tool_package_name="brave_search",
317
+ tool_spec_name="BraveSearchToolSpec",
318
+ api_key=str(os.environ["BRAVE_API_KEY"]),
319
+ )
307
320
  ```
308
321
 
309
322
  * **Academic Tools**
310
323
  * arXiv: Search and retrieve academic papers
311
324
  ```python
312
- arxiv_tool = ToolsCatalog(agent_config).arxiv_search
325
+ arxiv_tools = tools_factory.get_llama_index_tools(
326
+ tool_package_name="arxiv",
327
+ tool_spec_name="ArxivToolSpec",
328
+ )
313
329
  ```
314
330
 
315
- * **Graph Database Tools**
331
+ * **Database Tools**
316
332
  * Neo4j: Graph database integration
317
333
  ```python
318
- neo4j_tool = ToolsCatalog(agent_config).neo4j_query
334
+ neo4j_tools = tools_factory.get_llama_index_tools(
335
+ tool_package_name="neo4j",
336
+ tool_spec_name="Neo4jQueryToolSpec",
337
+ )
319
338
  ```
320
339
  * Kuzu: Lightweight graph database
321
340
  ```python
322
- kuzu_tool = ToolsCatalog(agent_config).kuzu_query
341
+ kuzu_tools = tools_factory.get_llama_index_tools(
342
+ tool_package_name="kuzu",
343
+ tool_spec_name="KuzuGraphStore",
344
+ )
345
+ ```
346
+ * Waii: tools for natural langauge query of a relational database
347
+ ```python
348
+ waii_tools = tools_factory.get_llama_index_tools(
349
+ tool_package_name="waii",
350
+ tool_spec_name="WaiiToolSpec",
351
+ )
323
352
  ```
324
353
 
325
354
  * **Google Tools**
326
355
  * Gmail: Read and send emails
327
356
  ```python
328
- gmail_tool = ToolsCatalog(agent_config).gmail
357
+ gmail_tools = tools_factory.get_llama_index_tools(
358
+ tool_package_name="google",
359
+ tool_spec_name="GmailToolSpec",
360
+ )
329
361
  ```
330
362
  * Calendar: Manage calendar events
331
363
  ```python
332
- calendar_tool = ToolsCatalog(agent_config).calendar
364
+ calendar_tools = tools_factory.get_llama_index_tools(
365
+ tool_package_name="google",
366
+ tool_spec_name="GoogleCalendarToolSpec",
367
+ )
333
368
  ```
334
369
  * Search: Google search integration
335
370
  ```python
336
- google_search_tool = ToolsCatalog(agent_config).google_search
371
+ search_tools = tools_factory.get_llama_index_tools(
372
+ tool_package_name="google",
373
+ tool_spec_name="GoogleSearchToolSpec",
374
+ )
337
375
  ```
338
376
 
339
377
  * **Communication Tools**
340
378
  * Slack: Send messages and interact with Slack
341
379
  ```python
342
- slack_tool = ToolsCatalog(agent_config).slack
380
+ slack_tools = tools_factory.get_llama_index_tools(
381
+ tool_package_name="slack",
382
+ tool_spec_name="SlackToolSpec",
383
+ )
343
384
  ```
344
385
 
345
386
  For detailed setup instructions and API key requirements, please refer the instructions on [LlamaIndex hub](https://llamahub.ai/?tab=tools) for the specific tool.
@@ -1,9 +1,10 @@
1
- llama-index==0.12.34
1
+ llama-index==0.12.35
2
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.7
6
- llama-index-llms-openai==0.3.38
5
+ llama-index-agent-openai==0.4.8
6
+ llama-index-llms-openai==0.3.42
7
+ llama-index-llms-openai-like>=0.3.5
7
8
  llama-index-llms-anthropic==0.6.10
8
9
  llama-index-llms-together==0.3.1
9
10
  llama-index-llms-groq==0.3.1
@@ -18,15 +19,17 @@ llama-index-tools-google==0.3.0
18
19
  llama-index-tools-tavily_research==0.3.0
19
20
  llama_index.tools.brave_search==0.3.0
20
21
  llama-index-tools-neo4j==0.3.0
22
+ llama-index-tools-waii==0.3.0
21
23
  llama-index-graph-stores-kuzu==0.7.0
24
+ llama-index-tools-salesforce==0.3.0
22
25
  llama-index-tools-slack==0.3.0
23
26
  llama-index-tools-exa==0.3.0
24
27
  llama-index-tools-wikipedia==0.3.0
25
28
  llama-index-tools-bing-search==0.3.0
26
- tavily-python==0.5.4
27
- exa-py==1.12.0
29
+ tavily-python==0.7.2
30
+ exa-py==1.12.1
28
31
  openinference-instrumentation-llama-index==4.2.1
29
- opentelemetry-proto==1.32.1
32
+ opentelemetry-proto>=1.31.0
30
33
  arize-phoenix==8.26.1
31
34
  arize-phoenix-otel==0.9.2
32
35
  protobuf==5.29.3
@@ -0,0 +1,126 @@
1
+ import unittest
2
+ from uuid import UUID
3
+
4
+ from fastapi.testclient import TestClient
5
+
6
+ # Adjust this import to point at the file where you put create_app
7
+ from vectara_agentic.agent_endpoint import create_app
8
+ from vectara_agentic.agent import Agent
9
+ from vectara_agentic.agent_config import AgentConfig
10
+
11
+
12
+ class DummyAgent(Agent):
13
+ def __init__(self):
14
+ # satisfy Agent.__init__(tools: ...)
15
+ super().__init__(tools=[])
16
+
17
+ def chat(self, message: str) -> str:
18
+ return f"Echo: {message}"
19
+
20
+ class APITestCase(unittest.TestCase):
21
+ @classmethod
22
+ def setUpClass(cls):
23
+ cls.agent = DummyAgent()
24
+ # Override only the endpoint_api_key, leave everything else as default
25
+ cls.config = AgentConfig(endpoint_api_key="testkey")
26
+ app = create_app(cls.agent, cls.config)
27
+ cls.client = TestClient(app)
28
+ cls.headers = {"X-API-Key": cls.config.endpoint_api_key}
29
+
30
+ def test_chat_success(self):
31
+ r = self.client.get("/chat", params={"message": "hello"}, headers=self.headers)
32
+ self.assertEqual(r.status_code, 200)
33
+ self.assertEqual(r.json(), {"response": "Echo: hello"})
34
+
35
+ def test_chat_empty_message(self):
36
+ r = self.client.get("/chat", params={"message": ""}, headers=self.headers)
37
+ self.assertEqual(r.status_code, 400)
38
+ self.assertIn("No message provided", r.json()["detail"])
39
+
40
+ def test_chat_unauthorized(self):
41
+ r = self.client.get("/chat", params={"message": "hello"}, headers={"X-API-Key": "bad"})
42
+ self.assertEqual(r.status_code, 403)
43
+
44
+ def test_completions_success(self):
45
+ payload = {"model": "m1", "prompt": "test"}
46
+ r = self.client.post("/v1/completions", json=payload, headers=self.headers)
47
+ self.assertEqual(r.status_code, 200)
48
+ data = r.json()
49
+
50
+ # ID prefix + valid UUID check
51
+ self.assertTrue(data["id"].startswith("cmpl-"))
52
+ UUID(data["id"].split("-", 1)[1])
53
+
54
+ self.assertEqual(data["model"], "m1")
55
+ self.assertEqual(data["choices"][0]["text"], "Echo: test")
56
+ # prompt_tokens=1, completion_tokens=2 ("Echo:", "test")
57
+ self.assertEqual(data["usage"]["prompt_tokens"], 1)
58
+ self.assertEqual(data["usage"]["completion_tokens"], 2)
59
+
60
+ def test_completions_no_prompt(self):
61
+ payload = {"model": "m1"} # missing prompt
62
+ r = self.client.post("/v1/completions", json=payload, headers=self.headers)
63
+ self.assertEqual(r.status_code, 400)
64
+ self.assertIn("`prompt` is required", r.json()["detail"])
65
+
66
+ def test_completions_unauthorized(self):
67
+ payload = {"model": "m1", "prompt": "hi"}
68
+ r = self.client.post("/v1/completions", json=payload, headers={"X-API-Key": "bad"})
69
+ self.assertEqual(r.status_code, 403)
70
+
71
+ def test_chat_completion_success(self):
72
+ payload = {
73
+ "model": "m1",
74
+ "messages": [{"role": "user", "content": "hello"}]
75
+ }
76
+ r = self.client.post("/v1/chat", json=payload, headers=self.headers)
77
+ self.assertEqual(r.status_code, 200)
78
+ data = r.json()
79
+
80
+ # ID prefix + valid UUID check
81
+ self.assertTrue(data["id"].startswith("chatcmpl-"))
82
+ UUID(data["id"].split("-", 1)[1])
83
+
84
+ self.assertEqual(data["model"], "m1")
85
+ self.assertEqual(data["choices"][0]["message"]["content"], "Echo: hello")
86
+
87
+ # prompt_tokens=1, completion_tokens=2 ("Echo:", "hello")
88
+ self.assertEqual(data["usage"]["prompt_tokens"], 1)
89
+ self.assertEqual(data["usage"]["completion_tokens"], 2)
90
+
91
+ def test_chat_completion_multiple_user_messages(self):
92
+ payload = {
93
+ "model": "m1",
94
+ "messages": [
95
+ {"role": "system", "content": "ignore me"},
96
+ {"role": "user", "content": "foo"},
97
+ {"role": "assistant", "content": "pong"},
98
+ {"role": "user", "content": "bar"}
99
+ ]
100
+ }
101
+ r = self.client.post("/v1/chat", json=payload, headers=self.headers)
102
+ self.assertEqual(r.status_code, 200)
103
+ data = r.json()
104
+
105
+ # Should concatenate only user messages: "foo bar"
106
+ self.assertEqual(data["choices"][0]["message"]["content"], "Echo: foo bar")
107
+ self.assertEqual(data["usage"]["prompt_tokens"], 2) # "foo","bar"
108
+ self.assertEqual(data["usage"]["completion_tokens"], 3) # "Echo:","foo","bar"
109
+
110
+ def test_chat_completion_no_messages(self):
111
+ payload = {"model": "m1", "messages": []}
112
+ r = self.client.post("/v1/chat", json=payload, headers=self.headers)
113
+ self.assertEqual(r.status_code, 400)
114
+ self.assertIn("`messages` is required", r.json()["detail"])
115
+
116
+ def test_chat_completion_unauthorized(self):
117
+ payload = {
118
+ "model": "m1",
119
+ "messages": [{"role": "user", "content": "oops"}]
120
+ }
121
+ r = self.client.post("/v1/chat", json=payload, headers={"X-API-Key": "bad"})
122
+ self.assertEqual(r.status_code, 403)
123
+
124
+
125
+ if __name__ == "__main__":
126
+ unittest.main()
@@ -0,0 +1,115 @@
1
+ import unittest
2
+
3
+ from pydantic import Field, BaseModel
4
+
5
+ from vectara_agentic.agent import Agent, AgentType
6
+ from vectara_agentic.agent_config import AgentConfig
7
+ from vectara_agentic.tools import VectaraToolFactory
8
+ from vectara_agentic.types import ModelProvider
9
+
10
+
11
+ import nest_asyncio
12
+ nest_asyncio.apply()
13
+
14
+ tickers = {
15
+ "C": "Citigroup",
16
+ "COF": "Capital One",
17
+ "JPM": "JPMorgan Chase",
18
+ "AAPL": "Apple Computer",
19
+ "GOOG": "Google",
20
+ "AMZN": "Amazon",
21
+ "SNOW": "Snowflake",
22
+ "TEAM": "Atlassian",
23
+ "TSLA": "Tesla",
24
+ "NVDA": "Nvidia",
25
+ "MSFT": "Microsoft",
26
+ "AMD": "Advanced Micro Devices",
27
+ "INTC": "Intel",
28
+ "NFLX": "Netflix",
29
+ "STT": "State Street",
30
+ "BK": "Bank of New York Mellon",
31
+ }
32
+ years = list(range(2015, 2025))
33
+
34
+
35
+ def mult(x: float, y: float) -> float:
36
+ "Multiply two numbers"
37
+ return x * y
38
+
39
+
40
+ def get_company_info() -> list[str]:
41
+ """
42
+ Returns a dictionary of companies you can query about. Always check this before using any other tool.
43
+ The output is a dictionary of valid ticker symbols mapped to company names.
44
+ You can use this to identify the companies you can query about, and their ticker information.
45
+ """
46
+ return tickers
47
+
48
+
49
+ def get_valid_years() -> list[str]:
50
+ """
51
+ Returns a list of the years for which financial reports are available.
52
+ Always check this before using any other tool.
53
+ """
54
+ return years
55
+
56
+
57
+ fc_config_gemini = AgentConfig(
58
+ agent_type=AgentType.FUNCTION_CALLING,
59
+ main_llm_provider=ModelProvider.GEMINI,
60
+ tool_llm_provider=ModelProvider.GEMINI,
61
+ )
62
+
63
+
64
+ class TestGEMINI(unittest.TestCase):
65
+
66
+ def test_tool_with_many_arguments(self):
67
+
68
+ vectara_corpus_key = "vectara-docs_1"
69
+ vectara_api_key = "zqt_UXrBcnI2UXINZkrv4g1tQPhzj02vfdtqYJIDiA"
70
+ vec_factory = VectaraToolFactory(vectara_corpus_key, vectara_api_key)
71
+
72
+ class QueryToolArgs(BaseModel):
73
+ arg1: str = Field(description="the first argument", examples=["val1"])
74
+ arg2: str = Field(description="the second argument", examples=["val2"])
75
+ arg3: str = Field(description="the third argument", examples=["val3"])
76
+ arg4: str = Field(description="the fourth argument", examples=["val4"])
77
+ arg5: str = Field(description="the fifth argument", examples=["val5"])
78
+ arg6: str = Field(description="the sixth argument", examples=["val6"])
79
+ arg7: str = Field(description="the seventh argument", examples=["val7"])
80
+ arg8: str = Field(description="the eighth argument", examples=["val8"])
81
+ arg9: str = Field(description="the ninth argument", examples=["val9"])
82
+ arg10: str = Field(description="the tenth argument", examples=["val10"])
83
+ arg11: str = Field(description="the eleventh argument", examples=["val11"])
84
+ arg12: str = Field(description="the twelfth argument", examples=["val12"])
85
+ arg13: str = Field(
86
+ description="the thirteenth argument", examples=["val13"]
87
+ )
88
+ arg14: str = Field(
89
+ description="the fourteenth argument", examples=["val14"]
90
+ )
91
+ arg15: str = Field(description="the fifteenth argument", examples=["val15"])
92
+
93
+ query_tool_1 = vec_factory.create_rag_tool(
94
+ tool_name="rag_tool",
95
+ tool_description="""
96
+ A dummy tool that takes 15 arguments and returns a response (str) to the user query based on the data in this corpus.
97
+ We are using this tool to test the tool factory works and does not crash with OpenAI.
98
+ """,
99
+ tool_args_schema=QueryToolArgs,
100
+ )
101
+
102
+ agent = Agent(
103
+ tools=[query_tool_1],
104
+ topic="Sample topic",
105
+ custom_instructions="Call the tool with 15 arguments",
106
+ agent_config=fc_config_gemini,
107
+ )
108
+ res = agent.chat("What is the stock price?")
109
+ self.assertTrue(
110
+ any(sub in str(res) for sub in ["I don't know", "I do not have"])
111
+ )
112
+
113
+
114
+ if __name__ == "__main__":
115
+ unittest.main()
@@ -54,13 +54,6 @@ def get_valid_years() -> list[str]:
54
54
  return years
55
55
 
56
56
 
57
- config_gemini = AgentConfig(
58
- agent_type=AgentType.FUNCTION_CALLING,
59
- main_llm_provider=ModelProvider.GEMINI,
60
- tool_llm_provider=ModelProvider.GEMINI,
61
- )
62
-
63
-
64
57
  fc_config_groq = AgentConfig(
65
58
  agent_type=AgentType.FUNCTION_CALLING,
66
59
  main_llm_provider=ModelProvider.GROQ,
@@ -251,17 +251,19 @@ class TestToolsPackage(unittest.TestCase):
251
251
  arg11: str = Field(description="the eleventh argument", examples=["val11"])
252
252
  arg12: str = Field(description="the twelfth argument", examples=["val12"])
253
253
  arg13: str = Field(description="the thirteenth argument", examples=["val13"])
254
+ arg14: str = Field(description="the fourteenth argument", examples=["val14"])
255
+ arg15: str = Field(description="the fifteenth argument", examples=["val15"])
254
256
 
255
257
  query_tool_1 = vec_factory.create_rag_tool(
256
258
  tool_name="rag_tool",
257
259
  tool_description="""
258
- A dummy tool that takes 13 arguments and returns a response (str) to the user query based on the data in this corpus.
260
+ A dummy tool that takes 15 arguments and returns a response (str) to the user query based on the data in this corpus.
259
261
  We are using this tool to test the tool factory works and does not crash with OpenAI.
260
262
  """,
261
263
  tool_args_schema=QueryToolArgs,
262
264
  )
263
265
 
264
- # Test with 13 arguments which go over the 1024 limit.
266
+ # Test with 15 arguments to make sure no issues occur
265
267
  config = AgentConfig(
266
268
  agent_type=AgentType.OPENAI
267
269
  )
@@ -272,9 +274,9 @@ class TestToolsPackage(unittest.TestCase):
272
274
  agent_config=config,
273
275
  )
274
276
  res = agent.chat("What is the stock price for Yahoo on 12/31/22?")
275
- self.assertIn("maximum length of 1024 characters", str(res))
277
+ self.assertNotIn("maximum length of 1024 characters", str(res))
276
278
 
277
- # Same test but with GROQ
279
+ # Same test but with GROQ, should not have this limit
278
280
  config = AgentConfig(
279
281
  agent_type=AgentType.FUNCTION_CALLING,
280
282
  main_llm_provider=ModelProvider.GROQ,
@@ -283,13 +285,13 @@ class TestToolsPackage(unittest.TestCase):
283
285
  agent = Agent(
284
286
  tools=[query_tool_1],
285
287
  topic="Sample topic",
286
- custom_instructions="Call the tool with 13 arguments for GROQ",
288
+ custom_instructions="Call the tool with 15 arguments for GROQ",
287
289
  agent_config=config,
288
290
  )
289
291
  res = agent.chat("What is the stock price?")
290
292
  self.assertNotIn("maximum length of 1024 characters", str(res))
291
293
 
292
- # Same test but with ANTHROPIC
294
+ # Same test but with ANTHROPIC, should not have this limit
293
295
  config = AgentConfig(
294
296
  agent_type=AgentType.FUNCTION_CALLING,
295
297
  main_llm_provider=ModelProvider.ANTHROPIC,
@@ -298,38 +300,12 @@ class TestToolsPackage(unittest.TestCase):
298
300
  agent = Agent(
299
301
  tools=[query_tool_1],
300
302
  topic="Sample topic",
301
- custom_instructions="Call the tool with 13 arguments for ANTHROPIC",
303
+ custom_instructions="Call the tool with 15 arguments for ANTHROPIC",
302
304
  agent_config=config,
303
305
  )
304
306
  res = agent.chat("What is the stock price?")
305
- # ANTHROPIC does not have that 1024 limit
306
307
  self.assertIn("stock price", str(res))
307
308
 
308
- # But using Compact_docstring=True, we can pass 13 arguments successfully.
309
- vec_factory = VectaraToolFactory(
310
- vectara_corpus_key, vectara_api_key, compact_docstring=True
311
- )
312
- query_tool_2 = vec_factory.create_rag_tool(
313
- tool_name="rag_tool",
314
- tool_description="""
315
- A dummy tool that takes 15 arguments and returns a response (str) to the user query based on the data in this corpus.
316
- We are using this tool to test the tool factory works and doesn not crash with OpenAI.
317
- """,
318
- tool_args_schema=QueryToolArgs,
319
- )
320
-
321
- config = AgentConfig()
322
- agent = Agent(
323
- tools=[query_tool_2],
324
- topic="Sample topic",
325
- custom_instructions="Call the tool with 15 arguments",
326
- agent_config=config,
327
- )
328
- res = agent.chat("What is the stock price?")
329
- self.assertTrue(
330
- any(sub in str(res) for sub in ["I don't know", "stock price"])
331
- )
332
-
333
309
  def test_public_repo(self):
334
310
  vectara_corpus_key = "vectara-docs_1"
335
311
  vectara_api_key = "zqt_UXrBcnI2UXINZkrv4g1tQPhzj02vfdtqYJIDiA"