vectara-agentic 0.4.0__tar.gz → 0.4.1__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.4.0/vectara_agentic.egg-info → vectara_agentic-0.4.1}/PKG-INFO +49 -8
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/README.md +45 -2
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/requirements.txt +3 -5
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/conftest.py +5 -1
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/run_tests.py +1 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_agent.py +26 -29
- vectara_agentic-0.4.1/tests/test_agent_fallback_memory.py +270 -0
- vectara_agentic-0.4.1/tests/test_agent_memory_consistency.py +229 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_agent_type.py +4 -0
- vectara_agentic-0.4.1/tests/test_bedrock.py +61 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_gemini.py +7 -22
- vectara_agentic-0.4.1/tests/test_groq.py +61 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_serialization.py +3 -6
- vectara_agentic-0.4.1/tests/test_session_memory.py +252 -0
- vectara_agentic-0.4.1/tests/test_streaming.py +109 -0
- vectara_agentic-0.4.1/tests/test_together.py +62 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_vhc.py +3 -2
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_workflow.py +9 -28
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/_version.py +1 -1
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent.py +212 -33
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/factory.py +30 -148
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/prompts.py +20 -13
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/serialization.py +3 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/streaming.py +22 -34
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/utils/__init__.py +0 -5
- vectara_agentic-0.4.1/vectara_agentic/agent_core/utils/hallucination.py +157 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/llm_utils.py +1 -1
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/types.py +9 -3
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1/vectara_agentic.egg-info}/PKG-INFO +49 -8
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic.egg-info/SOURCES.txt +4 -1
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic.egg-info/requires.txt +3 -5
- vectara_agentic-0.4.0/tests/test_bedrock.py +0 -46
- vectara_agentic-0.4.0/tests/test_groq.py +0 -46
- vectara_agentic-0.4.0/tests/test_streaming.py +0 -88
- vectara_agentic-0.4.0/vectara_agentic/agent_core/utils/hallucination.py +0 -202
- vectara_agentic-0.4.0/vectara_agentic/agent_core/utils/prompt_formatting.py +0 -56
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/LICENSE +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/MANIFEST.in +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/setup.cfg +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/setup.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/__init__.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/endpoint.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_api_endpoint.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_fallback.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_private_llm.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_return_direct.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_tools.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/tests/test_vectara_llms.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/__init__.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/_callback.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/_observability.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_config.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/__init__.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/utils/logging.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/utils/schemas.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_core/utils/tools.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/agent_endpoint.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/db_tools.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/sub_query_workflow.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/tool_utils.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/tools.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/tools_catalog.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic/utils.py +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/vectara_agentic.egg-info/dependency_links.txt +0 -0
- {vectara_agentic-0.4.0 → vectara_agentic-0.4.1}/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.4.
|
|
3
|
+
Version: 0.4.1
|
|
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,13 +16,11 @@ 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-core==0.12.
|
|
19
|
+
Requires-Dist: llama-index==0.12.52
|
|
20
|
+
Requires-Dist: llama-index-core==0.12.52.post1
|
|
21
21
|
Requires-Dist: llama-index-workflow==1.0.1
|
|
22
22
|
Requires-Dist: llama-index-cli==0.4.4
|
|
23
23
|
Requires-Dist: llama-index-indices-managed-vectara==0.4.5
|
|
24
|
-
Requires-Dist: llama-index-agent-llm-compiler==0.3.2
|
|
25
|
-
Requires-Dist: llama-index-agent-lats==0.3.2
|
|
26
24
|
Requires-Dist: llama-index-agent-openai==0.4.12
|
|
27
25
|
Requires-Dist: llama-index-llms-openai==0.4.7
|
|
28
26
|
Requires-Dist: llama-index-llms-openai-like==0.4.0
|
|
@@ -53,7 +51,7 @@ Requires-Dist: openinference-instrumentation-llama-index==4.3.1
|
|
|
53
51
|
Requires-Dist: opentelemetry-proto>=1.31.0
|
|
54
52
|
Requires-Dist: arize-phoenix==10.9.1
|
|
55
53
|
Requires-Dist: arize-phoenix-otel==0.10.3
|
|
56
|
-
Requires-Dist: protobuf==5.29.
|
|
54
|
+
Requires-Dist: protobuf==5.29.5
|
|
57
55
|
Requires-Dist: tokenizers>=0.20
|
|
58
56
|
Requires-Dist: pydantic==2.11.5
|
|
59
57
|
Requires-Dist: pandas==2.2.3
|
|
@@ -125,7 +123,7 @@ Dynamic: summary
|
|
|
125
123
|
- **Rapid Tool Creation:**
|
|
126
124
|
Build Vectara RAG tools or search tools with a single line of code.
|
|
127
125
|
- **Agent Flexibility:**
|
|
128
|
-
Supports multiple agent types including `ReAct
|
|
126
|
+
Supports multiple agent types including `ReAct` and `Function Calling`.
|
|
129
127
|
- **Pre-Built Domain Tools:**
|
|
130
128
|
Tools tailored for finance, legal, and other verticals.
|
|
131
129
|
- **Multi-LLM Integration:**
|
|
@@ -532,6 +530,49 @@ Built-in formatters include `format_as_table`, `format_as_json`, and `format_as_
|
|
|
532
530
|
|
|
533
531
|
The human-readable format, if available, is used when using Vectara Hallucination Correction.
|
|
534
532
|
|
|
533
|
+
## 🔍 Vectara Hallucination Correction (VHC)
|
|
534
|
+
|
|
535
|
+
`vectara-agentic` provides built-in support for Vectara Hallucination Correction (VHC), which analyzes agent responses and corrects any detected hallucinations based on the factual content retrieved by VHC-eligible tools.
|
|
536
|
+
|
|
537
|
+
### Computing VHC
|
|
538
|
+
|
|
539
|
+
After a chat interaction, you can compute VHC to analyze and correct the agent's response:
|
|
540
|
+
|
|
541
|
+
```python
|
|
542
|
+
# Chat with the agent
|
|
543
|
+
response = agent.chat("What was Apple's revenue in 2022?")
|
|
544
|
+
print(response.response)
|
|
545
|
+
|
|
546
|
+
# Compute VHC analysis
|
|
547
|
+
vhc_result = agent.compute_vhc()
|
|
548
|
+
|
|
549
|
+
# Access corrected text and corrections
|
|
550
|
+
if vhc_result["corrected_text"]:
|
|
551
|
+
print("Original:", response.response)
|
|
552
|
+
print("Corrected:", vhc_result["corrected_text"])
|
|
553
|
+
print("Corrections:", vhc_result["corrections"])
|
|
554
|
+
else:
|
|
555
|
+
print("No corrections needed or VHC not available")
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Async VHC Computation
|
|
559
|
+
|
|
560
|
+
For async applications, use `acompute_vhc()`:
|
|
561
|
+
|
|
562
|
+
```python
|
|
563
|
+
# Async chat
|
|
564
|
+
response = await agent.achat("What was Apple's revenue in 2022?")
|
|
565
|
+
|
|
566
|
+
# Async VHC computation
|
|
567
|
+
vhc_result = await agent.acompute_vhc()
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### VHC Requirements
|
|
571
|
+
|
|
572
|
+
- VHC requires a valid `VECTARA_API_KEY` environment variable
|
|
573
|
+
- Only VHC-eligible tools (those marked with `vhc_eligible=True`) contribute to the analysis
|
|
574
|
+
- VHC results are cached for each query/response pair to avoid redundant computation
|
|
575
|
+
|
|
535
576
|
### Tool Validation
|
|
536
577
|
|
|
537
578
|
When creating an agent, you can enable tool validation by setting `validate_tools=True`. This will check that any tools mentioned in your custom instructions actually exist in the agent's tool set:
|
|
@@ -745,7 +786,7 @@ agent = Agent(
|
|
|
745
786
|
```
|
|
746
787
|
|
|
747
788
|
The `AgentConfig` object may include the following items:
|
|
748
|
-
- `agent_type`: the agent type. Valid values are `REACT
|
|
789
|
+
- `agent_type`: the agent type. Valid values are `REACT` or `FUNCTION_CALLING` (default: `FUNCTION_CALLING`).
|
|
749
790
|
- `main_llm_provider` and `tool_llm_provider`: the LLM provider for main agent and for the tools. Valid values are `OPENAI`, `ANTHROPIC`, `TOGETHER`, `GROQ`, `COHERE`, `BEDROCK`, `GEMINI` (default: `OPENAI`).
|
|
750
791
|
|
|
751
792
|
> **Note:** Fireworks AI support has been removed. If you were using Fireworks, please migrate to one of the supported providers listed above.
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
- **Rapid Tool Creation:**
|
|
49
49
|
Build Vectara RAG tools or search tools with a single line of code.
|
|
50
50
|
- **Agent Flexibility:**
|
|
51
|
-
Supports multiple agent types including `ReAct
|
|
51
|
+
Supports multiple agent types including `ReAct` and `Function Calling`.
|
|
52
52
|
- **Pre-Built Domain Tools:**
|
|
53
53
|
Tools tailored for finance, legal, and other verticals.
|
|
54
54
|
- **Multi-LLM Integration:**
|
|
@@ -455,6 +455,49 @@ Built-in formatters include `format_as_table`, `format_as_json`, and `format_as_
|
|
|
455
455
|
|
|
456
456
|
The human-readable format, if available, is used when using Vectara Hallucination Correction.
|
|
457
457
|
|
|
458
|
+
## 🔍 Vectara Hallucination Correction (VHC)
|
|
459
|
+
|
|
460
|
+
`vectara-agentic` provides built-in support for Vectara Hallucination Correction (VHC), which analyzes agent responses and corrects any detected hallucinations based on the factual content retrieved by VHC-eligible tools.
|
|
461
|
+
|
|
462
|
+
### Computing VHC
|
|
463
|
+
|
|
464
|
+
After a chat interaction, you can compute VHC to analyze and correct the agent's response:
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
# Chat with the agent
|
|
468
|
+
response = agent.chat("What was Apple's revenue in 2022?")
|
|
469
|
+
print(response.response)
|
|
470
|
+
|
|
471
|
+
# Compute VHC analysis
|
|
472
|
+
vhc_result = agent.compute_vhc()
|
|
473
|
+
|
|
474
|
+
# Access corrected text and corrections
|
|
475
|
+
if vhc_result["corrected_text"]:
|
|
476
|
+
print("Original:", response.response)
|
|
477
|
+
print("Corrected:", vhc_result["corrected_text"])
|
|
478
|
+
print("Corrections:", vhc_result["corrections"])
|
|
479
|
+
else:
|
|
480
|
+
print("No corrections needed or VHC not available")
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Async VHC Computation
|
|
484
|
+
|
|
485
|
+
For async applications, use `acompute_vhc()`:
|
|
486
|
+
|
|
487
|
+
```python
|
|
488
|
+
# Async chat
|
|
489
|
+
response = await agent.achat("What was Apple's revenue in 2022?")
|
|
490
|
+
|
|
491
|
+
# Async VHC computation
|
|
492
|
+
vhc_result = await agent.acompute_vhc()
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### VHC Requirements
|
|
496
|
+
|
|
497
|
+
- VHC requires a valid `VECTARA_API_KEY` environment variable
|
|
498
|
+
- Only VHC-eligible tools (those marked with `vhc_eligible=True`) contribute to the analysis
|
|
499
|
+
- VHC results are cached for each query/response pair to avoid redundant computation
|
|
500
|
+
|
|
458
501
|
### Tool Validation
|
|
459
502
|
|
|
460
503
|
When creating an agent, you can enable tool validation by setting `validate_tools=True`. This will check that any tools mentioned in your custom instructions actually exist in the agent's tool set:
|
|
@@ -668,7 +711,7 @@ agent = Agent(
|
|
|
668
711
|
```
|
|
669
712
|
|
|
670
713
|
The `AgentConfig` object may include the following items:
|
|
671
|
-
- `agent_type`: the agent type. Valid values are `REACT
|
|
714
|
+
- `agent_type`: the agent type. Valid values are `REACT` or `FUNCTION_CALLING` (default: `FUNCTION_CALLING`).
|
|
672
715
|
- `main_llm_provider` and `tool_llm_provider`: the LLM provider for main agent and for the tools. Valid values are `OPENAI`, `ANTHROPIC`, `TOGETHER`, `GROQ`, `COHERE`, `BEDROCK`, `GEMINI` (default: `OPENAI`).
|
|
673
716
|
|
|
674
717
|
> **Note:** Fireworks AI support has been removed. If you were using Fireworks, please migrate to one of the supported providers listed above.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
llama-index==0.12.
|
|
2
|
-
llama-index-core==0.12.
|
|
1
|
+
llama-index==0.12.52
|
|
2
|
+
llama-index-core==0.12.52.post1
|
|
3
3
|
llama-index-workflow==1.0.1
|
|
4
4
|
llama-index-cli==0.4.4
|
|
5
5
|
llama-index-indices-managed-vectara==0.4.5
|
|
6
|
-
llama-index-agent-llm-compiler==0.3.2
|
|
7
|
-
llama-index-agent-lats==0.3.2
|
|
8
6
|
llama-index-agent-openai==0.4.12
|
|
9
7
|
llama-index-llms-openai==0.4.7
|
|
10
8
|
llama-index-llms-openai-like==0.4.0
|
|
@@ -35,7 +33,7 @@ openinference-instrumentation-llama-index==4.3.1
|
|
|
35
33
|
opentelemetry-proto>=1.31.0
|
|
36
34
|
arize-phoenix==10.9.1
|
|
37
35
|
arize-phoenix-otel==0.10.3
|
|
38
|
-
protobuf==5.29.
|
|
36
|
+
protobuf==5.29.5
|
|
39
37
|
tokenizers>=0.20
|
|
40
38
|
pydantic==2.11.5
|
|
41
39
|
pandas==2.2.3
|
|
@@ -19,6 +19,7 @@ from vectara_agentic.types import AgentType, ModelProvider
|
|
|
19
19
|
# Common Test Functions
|
|
20
20
|
# ========================================
|
|
21
21
|
|
|
22
|
+
|
|
22
23
|
def mult(x: float, y: float) -> float:
|
|
23
24
|
"""Multiply two numbers - common test function used across multiple test files."""
|
|
24
25
|
return x * y
|
|
@@ -37,7 +38,9 @@ def add(x: float, y: float) -> float:
|
|
|
37
38
|
STANDARD_TEST_TOPIC = "AI topic"
|
|
38
39
|
|
|
39
40
|
# Standard test instructions used across most tests
|
|
40
|
-
STANDARD_TEST_INSTRUCTIONS =
|
|
41
|
+
STANDARD_TEST_INSTRUCTIONS = (
|
|
42
|
+
"Always do as your father tells you, if your mother agrees!"
|
|
43
|
+
)
|
|
41
44
|
|
|
42
45
|
# Alternative instructions for specific tests
|
|
43
46
|
WORKFLOW_TEST_INSTRUCTIONS = "You are a helpful AI assistant."
|
|
@@ -139,6 +142,7 @@ private_llm_fc_config = AgentConfig(
|
|
|
139
142
|
# Error Detection and Testing Utilities
|
|
140
143
|
# ========================================
|
|
141
144
|
|
|
145
|
+
|
|
142
146
|
def is_rate_limited(response_text: str) -> bool:
|
|
143
147
|
"""
|
|
144
148
|
Check if a response indicates a rate limit error from any LLM provider.
|
|
@@ -7,17 +7,13 @@ import threading
|
|
|
7
7
|
from datetime import date
|
|
8
8
|
|
|
9
9
|
from vectara_agentic.agent import Agent, AgentType
|
|
10
|
-
from vectara_agentic.agent_core.
|
|
10
|
+
from vectara_agentic.agent_core.factory import format_prompt
|
|
11
11
|
from vectara_agentic.agent_config import AgentConfig
|
|
12
12
|
from vectara_agentic.types import ModelProvider, ObserverType
|
|
13
13
|
from vectara_agentic.tools import ToolsFactory
|
|
14
14
|
|
|
15
15
|
from vectara_agentic.agent_core.prompts import GENERAL_INSTRUCTIONS
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def mult(x: float, y: float) -> float:
|
|
19
|
-
"Multiply two numbers"
|
|
20
|
-
return x * y
|
|
16
|
+
from conftest import mult, STANDARD_TEST_TOPIC, STANDARD_TEST_INSTRUCTIONS
|
|
21
17
|
|
|
22
18
|
|
|
23
19
|
ARIZE_LOCK = threading.Lock()
|
|
@@ -38,12 +34,10 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
38
34
|
|
|
39
35
|
def test_agent_init(self):
|
|
40
36
|
tools = [ToolsFactory().create_tool(mult)]
|
|
41
|
-
|
|
42
|
-
custom_instructions = "Always do as your mother tells you!"
|
|
43
|
-
agent = Agent(tools, topic, custom_instructions)
|
|
37
|
+
agent = Agent(tools, STANDARD_TEST_TOPIC, STANDARD_TEST_INSTRUCTIONS)
|
|
44
38
|
self.assertEqual(agent.agent_type, AgentType.FUNCTION_CALLING)
|
|
45
|
-
self.assertEqual(agent._topic,
|
|
46
|
-
self.assertEqual(agent._custom_instructions,
|
|
39
|
+
self.assertEqual(agent._topic, STANDARD_TEST_TOPIC)
|
|
40
|
+
self.assertEqual(agent._custom_instructions, STANDARD_TEST_INSTRUCTIONS)
|
|
47
41
|
|
|
48
42
|
# To run this test, you must have appropriate API key in your environment
|
|
49
43
|
self.assertEqual(
|
|
@@ -56,8 +50,6 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
56
50
|
def test_agent_config(self):
|
|
57
51
|
with ARIZE_LOCK:
|
|
58
52
|
tools = [ToolsFactory().create_tool(mult)]
|
|
59
|
-
topic = "AI topic"
|
|
60
|
-
instructions = "Always do as your father tells you, if your mother agrees!"
|
|
61
53
|
config = AgentConfig(
|
|
62
54
|
agent_type=AgentType.REACT,
|
|
63
55
|
main_llm_provider=ModelProvider.ANTHROPIC,
|
|
@@ -69,12 +61,12 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
69
61
|
|
|
70
62
|
agent = Agent(
|
|
71
63
|
tools=tools,
|
|
72
|
-
topic=
|
|
73
|
-
custom_instructions=
|
|
64
|
+
topic=STANDARD_TEST_TOPIC,
|
|
65
|
+
custom_instructions=STANDARD_TEST_INSTRUCTIONS,
|
|
74
66
|
agent_config=config
|
|
75
67
|
)
|
|
76
|
-
self.assertEqual(agent._topic,
|
|
77
|
-
self.assertEqual(agent._custom_instructions,
|
|
68
|
+
self.assertEqual(agent._topic, STANDARD_TEST_TOPIC)
|
|
69
|
+
self.assertEqual(agent._custom_instructions, STANDARD_TEST_INSTRUCTIONS)
|
|
78
70
|
self.assertEqual(agent.agent_type, AgentType.REACT)
|
|
79
71
|
self.assertEqual(agent.agent_config.observer, ObserverType.ARIZE_PHOENIX)
|
|
80
72
|
self.assertEqual(agent.agent_config.main_llm_provider, ModelProvider.ANTHROPIC)
|
|
@@ -89,19 +81,20 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
89
81
|
)
|
|
90
82
|
|
|
91
83
|
def test_multiturn(self):
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
84
|
+
with ARIZE_LOCK:
|
|
85
|
+
tools = [ToolsFactory().create_tool(mult)]
|
|
86
|
+
topic = "AI topic"
|
|
87
|
+
instructions = "Always do as your father tells you, if your mother agrees!"
|
|
88
|
+
agent = Agent(
|
|
89
|
+
tools=tools,
|
|
90
|
+
topic=topic,
|
|
91
|
+
custom_instructions=instructions,
|
|
92
|
+
)
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
94
|
+
agent.chat("What is 5 times 10. Only give the answer, nothing else")
|
|
95
|
+
agent.chat("what is 3 times 7. Only give the answer, nothing else")
|
|
96
|
+
res = agent.chat("multiply the results of the last two questions. Output only the answer.")
|
|
97
|
+
self.assertEqual(res.response, "1050")
|
|
105
98
|
|
|
106
99
|
def test_from_corpus(self):
|
|
107
100
|
agent = Agent.from_corpus(
|
|
@@ -126,6 +119,10 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
126
119
|
chat_history=[("What is 5 times 10", "50"), ("What is 3 times 7", "21")]
|
|
127
120
|
)
|
|
128
121
|
|
|
122
|
+
data = agent.dumps()
|
|
123
|
+
clone = Agent.loads(data)
|
|
124
|
+
assert clone.memory.get() == agent.memory.get()
|
|
125
|
+
|
|
129
126
|
res = agent.chat("multiply the results of the last two questions. Output only the answer.")
|
|
130
127
|
self.assertEqual(res.response, "1050")
|
|
131
128
|
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Suppress external dependency warnings before any other imports
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
warnings.simplefilter("ignore", DeprecationWarning)
|
|
5
|
+
|
|
6
|
+
import unittest
|
|
7
|
+
import threading
|
|
8
|
+
|
|
9
|
+
from vectara_agentic.agent import Agent, AgentType
|
|
10
|
+
from vectara_agentic.agent_config import AgentConfig
|
|
11
|
+
from vectara_agentic.types import ModelProvider, AgentConfigType
|
|
12
|
+
from vectara_agentic.tools import ToolsFactory
|
|
13
|
+
|
|
14
|
+
from llama_index.core.llms import ChatMessage, MessageRole
|
|
15
|
+
from conftest import mult, add
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
ARIZE_LOCK = threading.Lock()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestAgentFallbackMemoryConsistency(unittest.TestCase):
|
|
22
|
+
"""Test memory consistency between main and fallback agents"""
|
|
23
|
+
|
|
24
|
+
def setUp(self):
|
|
25
|
+
"""Set up test fixtures"""
|
|
26
|
+
self.tools = [ToolsFactory().create_tool(mult), ToolsFactory().create_tool(add)]
|
|
27
|
+
self.topic = "Mathematics"
|
|
28
|
+
self.custom_instructions = "You are a helpful math assistant."
|
|
29
|
+
|
|
30
|
+
# Main agent config
|
|
31
|
+
self.main_config = AgentConfig(
|
|
32
|
+
agent_type=AgentType.FUNCTION_CALLING,
|
|
33
|
+
main_llm_provider=ModelProvider.ANTHROPIC,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Fallback agent config
|
|
37
|
+
self.fallback_config = AgentConfig(
|
|
38
|
+
agent_type=AgentType.REACT, main_llm_provider=ModelProvider.ANTHROPIC
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
self.session_id = "test-fallback-session-123"
|
|
42
|
+
|
|
43
|
+
def test_memory_consistency_on_agent_creation(self):
|
|
44
|
+
"""Test that main and fallback agents are created with the same memory content"""
|
|
45
|
+
agent = Agent(
|
|
46
|
+
tools=self.tools,
|
|
47
|
+
topic=self.topic,
|
|
48
|
+
custom_instructions=self.custom_instructions,
|
|
49
|
+
agent_config=self.main_config,
|
|
50
|
+
fallback_agent_config=self.fallback_config,
|
|
51
|
+
session_id=self.session_id,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Add some memory before creating the agents
|
|
55
|
+
test_messages = [
|
|
56
|
+
ChatMessage(role=MessageRole.USER, content="What is 2*3?"),
|
|
57
|
+
ChatMessage(role=MessageRole.ASSISTANT, content="2*3 = 6"),
|
|
58
|
+
]
|
|
59
|
+
agent.memory.put_messages(test_messages)
|
|
60
|
+
|
|
61
|
+
# Verify both agents have memory with the same content
|
|
62
|
+
# Memory is managed by the main Agent class, not individual agent instances
|
|
63
|
+
main_memory = agent.memory.get()
|
|
64
|
+
fallback_memory = agent.memory.get() # Both access the same memory
|
|
65
|
+
|
|
66
|
+
self.assertEqual(len(main_memory), 2)
|
|
67
|
+
self.assertEqual(len(fallback_memory), 2)
|
|
68
|
+
self.assertEqual(main_memory[0].content, "What is 2*3?")
|
|
69
|
+
self.assertEqual(fallback_memory[0].content, "What is 2*3?")
|
|
70
|
+
|
|
71
|
+
# Verify session_id consistency
|
|
72
|
+
# Memory is managed by the main Agent class
|
|
73
|
+
self.assertEqual(agent.memory.session_id, self.session_id)
|
|
74
|
+
|
|
75
|
+
def test_memory_sync_during_agent_switching(self):
|
|
76
|
+
"""Test that memory remains consistent when switching between main and fallback agents"""
|
|
77
|
+
agent = Agent(
|
|
78
|
+
tools=self.tools,
|
|
79
|
+
topic=self.topic,
|
|
80
|
+
custom_instructions=self.custom_instructions,
|
|
81
|
+
agent_config=self.main_config,
|
|
82
|
+
fallback_agent_config=self.fallback_config,
|
|
83
|
+
session_id=self.session_id,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Start with main agent
|
|
87
|
+
self.assertEqual(agent.agent_config_type, AgentConfigType.DEFAULT)
|
|
88
|
+
|
|
89
|
+
# Add initial memory
|
|
90
|
+
initial_messages = [
|
|
91
|
+
ChatMessage(role=MessageRole.USER, content="Initial question"),
|
|
92
|
+
ChatMessage(role=MessageRole.ASSISTANT, content="Initial response"),
|
|
93
|
+
]
|
|
94
|
+
agent.memory.put_messages(initial_messages)
|
|
95
|
+
|
|
96
|
+
# Access main agent to ensure it's loaded
|
|
97
|
+
main_memory_before = agent.memory.get() # Memory managed by main Agent class
|
|
98
|
+
self.assertEqual(len(main_memory_before), 2)
|
|
99
|
+
|
|
100
|
+
# Switch to fallback agent (this should clear the fallback agent instance)
|
|
101
|
+
agent._switch_agent_config()
|
|
102
|
+
self.assertEqual(agent.agent_config_type, AgentConfigType.FALLBACK)
|
|
103
|
+
|
|
104
|
+
# Access fallback agent (should be recreated with current memory)
|
|
105
|
+
fallback_memory = agent.memory.get() # Memory managed by main Agent class
|
|
106
|
+
|
|
107
|
+
# Verify fallback agent has the same memory content
|
|
108
|
+
self.assertEqual(len(fallback_memory), 2)
|
|
109
|
+
self.assertEqual(fallback_memory[0].content, "Initial question")
|
|
110
|
+
self.assertEqual(fallback_memory[1].content, "Initial response")
|
|
111
|
+
|
|
112
|
+
# Add more memory while using fallback agent
|
|
113
|
+
additional_messages = [
|
|
114
|
+
ChatMessage(role=MessageRole.USER, content="Fallback question"),
|
|
115
|
+
ChatMessage(role=MessageRole.ASSISTANT, content="Fallback response"),
|
|
116
|
+
]
|
|
117
|
+
agent.memory.put_messages(additional_messages)
|
|
118
|
+
|
|
119
|
+
# Switch back to main agent (this should clear the main agent instance)
|
|
120
|
+
agent._switch_agent_config()
|
|
121
|
+
self.assertEqual(agent.agent_config_type, AgentConfigType.DEFAULT)
|
|
122
|
+
|
|
123
|
+
# Verify recreated main agent now has all the memory including what was added during fallback
|
|
124
|
+
main_memory_after = agent.memory.get() # Memory managed by main Agent class
|
|
125
|
+
self.assertEqual(len(main_memory_after), 4)
|
|
126
|
+
self.assertEqual(main_memory_after[2].content, "Fallback question")
|
|
127
|
+
self.assertEqual(main_memory_after[3].content, "Fallback response")
|
|
128
|
+
|
|
129
|
+
def test_memory_sync_on_clear_memory(self):
|
|
130
|
+
"""Test that memory clearing resets agent instances for consistency"""
|
|
131
|
+
agent = Agent(
|
|
132
|
+
tools=self.tools,
|
|
133
|
+
topic=self.topic,
|
|
134
|
+
custom_instructions=self.custom_instructions,
|
|
135
|
+
agent_config=self.main_config,
|
|
136
|
+
fallback_agent_config=self.fallback_config,
|
|
137
|
+
session_id=self.session_id,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Add memory
|
|
141
|
+
test_messages = [
|
|
142
|
+
ChatMessage(role=MessageRole.USER, content="Test question"),
|
|
143
|
+
ChatMessage(role=MessageRole.ASSISTANT, content="Test response"),
|
|
144
|
+
]
|
|
145
|
+
agent.memory.put_messages(test_messages)
|
|
146
|
+
|
|
147
|
+
# Verify memory exists
|
|
148
|
+
# Memory is managed by the main Agent class
|
|
149
|
+
self.assertEqual(len(agent.memory.get()), 2)
|
|
150
|
+
self.assertEqual(len(agent.memory.get()), 2) # Both access same memory
|
|
151
|
+
|
|
152
|
+
# Clear memory (should reset agent instances)
|
|
153
|
+
agent.clear_memory()
|
|
154
|
+
|
|
155
|
+
# Verify core memory is cleared
|
|
156
|
+
self.assertEqual(len(agent.memory.get()), 0)
|
|
157
|
+
|
|
158
|
+
# Verify agent instances were reset (None)
|
|
159
|
+
self.assertIsNone(agent._agent)
|
|
160
|
+
self.assertIsNone(agent._fallback_agent)
|
|
161
|
+
|
|
162
|
+
# Verify new agents have cleared memory
|
|
163
|
+
# Memory is managed by the main Agent class
|
|
164
|
+
self.assertEqual(len(agent.memory.get()), 0)
|
|
165
|
+
self.assertEqual(len(agent.memory.get()), 0) # Both access same memory
|
|
166
|
+
|
|
167
|
+
def test_memory_consistency_after_serialization(self):
|
|
168
|
+
"""Test that memory consistency is maintained after serialization/deserialization"""
|
|
169
|
+
agent = Agent(
|
|
170
|
+
tools=self.tools,
|
|
171
|
+
topic=self.topic,
|
|
172
|
+
custom_instructions=self.custom_instructions,
|
|
173
|
+
agent_config=self.main_config,
|
|
174
|
+
fallback_agent_config=self.fallback_config,
|
|
175
|
+
session_id=self.session_id,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Add memory and load both agents
|
|
179
|
+
test_messages = [
|
|
180
|
+
ChatMessage(role=MessageRole.USER, content="Serialization test"),
|
|
181
|
+
ChatMessage(role=MessageRole.ASSISTANT, content="Serialization response"),
|
|
182
|
+
]
|
|
183
|
+
agent.memory.put_messages(test_messages)
|
|
184
|
+
|
|
185
|
+
# Access both agents
|
|
186
|
+
_ = agent.agent
|
|
187
|
+
_ = agent.fallback_agent
|
|
188
|
+
|
|
189
|
+
# Serialize and deserialize
|
|
190
|
+
serialized_data = agent.dumps()
|
|
191
|
+
restored_agent = Agent.loads(serialized_data)
|
|
192
|
+
|
|
193
|
+
# Verify memory is preserved and consistent
|
|
194
|
+
self.assertEqual(restored_agent.session_id, self.session_id)
|
|
195
|
+
self.assertEqual(len(restored_agent.memory.get()), 2)
|
|
196
|
+
|
|
197
|
+
# Verify memory consistency
|
|
198
|
+
# Individual agent instances don't have .memory attribute - memory is managed by main Agent class
|
|
199
|
+
# Both agent instances should use the same memory from the main Agent
|
|
200
|
+
|
|
201
|
+
main_memory = restored_agent.memory.get()
|
|
202
|
+
fallback_memory = restored_agent.memory.get() # Both access same memory
|
|
203
|
+
|
|
204
|
+
self.assertEqual(len(main_memory), 2)
|
|
205
|
+
self.assertEqual(len(fallback_memory), 2)
|
|
206
|
+
self.assertEqual(main_memory[0].content, "Serialization test")
|
|
207
|
+
self.assertEqual(fallback_memory[0].content, "Serialization test")
|
|
208
|
+
|
|
209
|
+
def test_session_id_consistency_across_agents(self):
|
|
210
|
+
"""Test that session_id is consistent between main and fallback agents"""
|
|
211
|
+
agent = Agent(
|
|
212
|
+
tools=self.tools,
|
|
213
|
+
topic=self.topic,
|
|
214
|
+
custom_instructions=self.custom_instructions,
|
|
215
|
+
agent_config=self.main_config,
|
|
216
|
+
fallback_agent_config=self.fallback_config,
|
|
217
|
+
session_id=self.session_id,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Verify main agent session_id consistency
|
|
221
|
+
self.assertEqual(agent.session_id, self.session_id)
|
|
222
|
+
self.assertEqual(agent.memory.session_id, self.session_id)
|
|
223
|
+
|
|
224
|
+
# Verify session_id consistency across all agents
|
|
225
|
+
# Memory is managed by the main Agent class
|
|
226
|
+
self.assertEqual(agent.memory.session_id, self.session_id)
|
|
227
|
+
self.assertEqual(
|
|
228
|
+
agent.memory.session_id, self.session_id
|
|
229
|
+
) # Both access same memory
|
|
230
|
+
|
|
231
|
+
def test_agent_recreation_on_switch(self):
|
|
232
|
+
"""Test that agents are properly recreated when switching configurations"""
|
|
233
|
+
agent = Agent(
|
|
234
|
+
tools=self.tools,
|
|
235
|
+
topic=self.topic,
|
|
236
|
+
custom_instructions=self.custom_instructions,
|
|
237
|
+
agent_config=self.main_config,
|
|
238
|
+
fallback_agent_config=self.fallback_config,
|
|
239
|
+
session_id=self.session_id,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Load main agent
|
|
243
|
+
original_main_agent = agent.agent
|
|
244
|
+
self.assertIsNotNone(original_main_agent)
|
|
245
|
+
|
|
246
|
+
# Load fallback agent
|
|
247
|
+
original_fallback_agent = agent.fallback_agent
|
|
248
|
+
self.assertIsNotNone(original_fallback_agent)
|
|
249
|
+
|
|
250
|
+
# Switch to fallback - should clear the fallback agent instance
|
|
251
|
+
agent._switch_agent_config()
|
|
252
|
+
self.assertEqual(agent.agent_config_type, AgentConfigType.FALLBACK)
|
|
253
|
+
self.assertIsNone(agent._fallback_agent) # Should be cleared
|
|
254
|
+
|
|
255
|
+
# Access fallback agent again - should be a new instance
|
|
256
|
+
new_fallback_agent = agent.fallback_agent
|
|
257
|
+
self.assertIsNot(new_fallback_agent, original_fallback_agent)
|
|
258
|
+
|
|
259
|
+
# Switch back to main - should clear the main agent instance
|
|
260
|
+
agent._switch_agent_config()
|
|
261
|
+
self.assertEqual(agent.agent_config_type, AgentConfigType.DEFAULT)
|
|
262
|
+
self.assertIsNone(agent._agent) # Should be cleared
|
|
263
|
+
|
|
264
|
+
# Access main agent again - should be a new instance
|
|
265
|
+
new_main_agent = agent.agent
|
|
266
|
+
self.assertIsNot(new_main_agent, original_main_agent)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == "__main__":
|
|
270
|
+
unittest.main()
|