vectara-agentic 0.4.2__py3-none-any.whl → 0.4.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vectara-agentic might be problematic. Click here for more details.

Files changed (43) hide show
  1. tests/__init__.py +1 -0
  2. tests/benchmark_models.py +547 -372
  3. tests/conftest.py +14 -12
  4. tests/endpoint.py +9 -5
  5. tests/run_tests.py +1 -0
  6. tests/test_agent.py +22 -9
  7. tests/test_agent_fallback_memory.py +4 -4
  8. tests/test_agent_memory_consistency.py +4 -4
  9. tests/test_agent_type.py +2 -0
  10. tests/test_api_endpoint.py +13 -13
  11. tests/test_bedrock.py +9 -1
  12. tests/test_fallback.py +18 -7
  13. tests/test_gemini.py +14 -40
  14. tests/test_groq.py +43 -1
  15. tests/test_openai.py +160 -0
  16. tests/test_private_llm.py +19 -6
  17. tests/test_react_error_handling.py +293 -0
  18. tests/test_react_memory.py +257 -0
  19. tests/test_react_streaming.py +135 -0
  20. tests/test_react_workflow_events.py +395 -0
  21. tests/test_return_direct.py +1 -0
  22. tests/test_serialization.py +58 -20
  23. tests/test_session_memory.py +11 -11
  24. tests/test_streaming.py +0 -44
  25. tests/test_together.py +75 -1
  26. tests/test_tools.py +3 -1
  27. tests/test_vectara_llms.py +2 -2
  28. tests/test_vhc.py +7 -2
  29. tests/test_workflow.py +17 -11
  30. vectara_agentic/_callback.py +79 -21
  31. vectara_agentic/_version.py +1 -1
  32. vectara_agentic/agent.py +65 -27
  33. vectara_agentic/agent_core/serialization.py +5 -9
  34. vectara_agentic/agent_core/streaming.py +245 -64
  35. vectara_agentic/agent_core/utils/schemas.py +2 -2
  36. vectara_agentic/llm_utils.py +64 -15
  37. vectara_agentic/tools.py +88 -31
  38. {vectara_agentic-0.4.2.dist-info → vectara_agentic-0.4.4.dist-info}/METADATA +133 -36
  39. vectara_agentic-0.4.4.dist-info/RECORD +59 -0
  40. vectara_agentic-0.4.2.dist-info/RECORD +0 -54
  41. {vectara_agentic-0.4.2.dist-info → vectara_agentic-0.4.4.dist-info}/WHEEL +0 -0
  42. {vectara_agentic-0.4.2.dist-info → vectara_agentic-0.4.4.dist-info}/licenses/LICENSE +0 -0
  43. {vectara_agentic-0.4.2.dist-info → vectara_agentic-0.4.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,257 @@
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
10
+ from vectara_agentic.tools import ToolsFactory
11
+ from llama_index.core.llms import MessageRole
12
+
13
+ import nest_asyncio
14
+
15
+ nest_asyncio.apply()
16
+
17
+ from conftest import (
18
+ AgentTestMixin,
19
+ react_config_anthropic,
20
+ react_config_gemini,
21
+ mult,
22
+ add,
23
+ STANDARD_TEST_TOPIC,
24
+ STANDARD_TEST_INSTRUCTIONS,
25
+ )
26
+
27
+ ARIZE_LOCK = threading.Lock()
28
+
29
+
30
+ class TestReActMemory(unittest.TestCase, AgentTestMixin):
31
+ """Test memory persistence and conversation history for ReAct agents."""
32
+
33
+ def setUp(self):
34
+ self.tools = [ToolsFactory().create_tool(mult), ToolsFactory().create_tool(add)]
35
+ self.topic = STANDARD_TEST_TOPIC
36
+ self.instructions = STANDARD_TEST_INSTRUCTIONS
37
+ self.session_id = "test-react-memory-123"
38
+
39
+ def test_react_memory_persistence_across_chats(self):
40
+ """Test that ReAct agents maintain conversation context across multiple chat calls."""
41
+ agent = Agent(
42
+ agent_config=react_config_anthropic,
43
+ tools=self.tools,
44
+ topic=self.topic,
45
+ custom_instructions=self.instructions,
46
+ session_id=self.session_id,
47
+ )
48
+
49
+ with self.with_provider_fallback("Anthropic"):
50
+ # First interaction - establish context
51
+ response1 = agent.chat("Calculate 5 times 10 and remember this result.")
52
+ self.check_response_and_skip(response1, "Anthropic")
53
+ self.assertIn("50", response1.response)
54
+
55
+ # Second interaction - reference previous result
56
+ response2 = agent.chat(
57
+ "What was the result I asked you to calculate and remember in the previous message?"
58
+ )
59
+ self.check_response_and_skip(response2, "Anthropic")
60
+ self.assertIn("50", response2.response)
61
+
62
+ # Third interaction - use previous result in new calculation
63
+ response3 = agent.chat("Add 25 to the number you calculated earlier.")
64
+ self.check_response_and_skip(response3, "Anthropic")
65
+ # Should be 50 + 25 = 75
66
+ self.assertIn("75", response3.response)
67
+
68
+ def test_react_memory_with_tool_history(self):
69
+ """Test that ReAct agents remember tool usage history across conversations."""
70
+ agent = Agent(
71
+ agent_config=react_config_anthropic,
72
+ tools=self.tools,
73
+ topic=self.topic,
74
+ custom_instructions=self.instructions,
75
+ session_id=self.session_id + "_tools",
76
+ )
77
+
78
+ with self.with_provider_fallback("Anthropic"):
79
+ # Use multiplication tool
80
+ response1 = agent.chat("Multiply 7 by 8.")
81
+ self.check_response_and_skip(response1, "Anthropic")
82
+ self.assertIn("56", response1.response)
83
+
84
+ # Use addition tool
85
+ response2 = agent.chat("Add 20 to 30.")
86
+ self.check_response_and_skip(response2, "Anthropic")
87
+ self.assertIn("50", response2.response)
88
+
89
+ # Reference both previous tool uses
90
+ response3 = agent.chat(
91
+ "What were the two calculations I asked you to perform? "
92
+ "Add those two results together."
93
+ )
94
+ self.check_response_and_skip(response3, "Anthropic")
95
+ # Should remember 7*8=56 and 20+30=50, then 56+50=106
96
+ self.assertIn("106", response3.response)
97
+
98
+ def test_react_memory_state_consistency(self):
99
+ """Test that ReAct agent memory state remains consistent during workflow execution."""
100
+ agent = Agent(
101
+ agent_config=react_config_anthropic,
102
+ tools=self.tools,
103
+ topic=self.topic,
104
+ custom_instructions=self.instructions,
105
+ session_id=self.session_id + "_consistency",
106
+ )
107
+
108
+ with self.with_provider_fallback("Anthropic"):
109
+ # Check initial memory state
110
+ initial_memory_size = len(agent.memory.get_all())
111
+
112
+ # Perform a conversation with tool use
113
+ response1 = agent.chat("Calculate 6 times 9 and tell me the result.")
114
+ self.check_response_and_skip(response1, "Anthropic")
115
+
116
+ # Memory should now contain user message, tool calls, and assistant response
117
+ after_first_memory = agent.memory.get_all()
118
+ self.assertGreater(
119
+ len(after_first_memory),
120
+ initial_memory_size,
121
+ "Memory should contain new messages after interaction",
122
+ )
123
+
124
+ # Continue conversation
125
+ response2 = agent.chat("Double that result.")
126
+ self.check_response_and_skip(response2, "Anthropic")
127
+
128
+ # Memory should contain all previous messages plus new ones
129
+ after_second_memory = agent.memory.get_all()
130
+ self.assertGreater(
131
+ len(after_second_memory),
132
+ len(after_first_memory),
133
+ "Memory should accumulate messages across interactions",
134
+ )
135
+
136
+ # Final result should be (6*9)*2 = 54*2 = 108
137
+ self.assertIn("108", response2.response)
138
+
139
+ def test_react_memory_across_different_providers(self):
140
+ """Test memory consistency when using different ReAct providers."""
141
+ # Test with Anthropic
142
+ agent_anthropic = Agent(
143
+ agent_config=react_config_anthropic,
144
+ tools=self.tools,
145
+ topic=self.topic,
146
+ custom_instructions=self.instructions,
147
+ session_id=self.session_id + "_anthropic_provider",
148
+ )
149
+
150
+ with self.with_provider_fallback("Anthropic"):
151
+ response1 = agent_anthropic.chat("Multiply 4 by 12.")
152
+ self.check_response_and_skip(response1, "Anthropic")
153
+ self.assertIn("48", response1.response)
154
+
155
+ # Verify memory structure is consistent
156
+ anthropic_memory = agent_anthropic.memory.get_all()
157
+ self.assertGreater(len(anthropic_memory), 0)
158
+
159
+ # Test with Gemini (if available)
160
+ agent_gemini = Agent(
161
+ agent_config=react_config_gemini,
162
+ tools=self.tools,
163
+ topic=self.topic,
164
+ custom_instructions=self.instructions,
165
+ session_id=self.session_id + "_gemini_provider",
166
+ )
167
+
168
+ with self.with_provider_fallback("Gemini"):
169
+ response2 = agent_gemini.chat("Multiply 4 by 12.")
170
+ self.check_response_and_skip(response2, "Gemini")
171
+ self.assertIn("48", response2.response)
172
+
173
+ # Verify memory structure is consistent across providers
174
+ gemini_memory = agent_gemini.memory.get_all()
175
+ self.assertGreater(len(gemini_memory), 0)
176
+
177
+ def test_react_memory_serialization_compatibility(self):
178
+ """Test that ReAct agent memory can be properly serialized and deserialized."""
179
+ agent = Agent(
180
+ agent_config=react_config_anthropic,
181
+ tools=self.tools,
182
+ topic=self.topic,
183
+ custom_instructions=self.instructions,
184
+ session_id=self.session_id + "_serialization",
185
+ )
186
+
187
+ with self.with_provider_fallback("Anthropic"):
188
+ # Perform some interactions to populate memory
189
+ response1 = agent.chat("Calculate 15 times 3.")
190
+ self.check_response_and_skip(response1, "Anthropic")
191
+
192
+ response2 = agent.chat("Add 10 to the previous result.")
193
+ self.check_response_and_skip(response2, "Anthropic")
194
+
195
+ # Get memory state before serialization
196
+ original_memory = agent.memory.get_all()
197
+ original_memory_size = len(original_memory)
198
+
199
+ # Test that memory state can be accessed and contains expected content
200
+ self.assertGreater(original_memory_size, 0)
201
+
202
+ # Verify memory contains both user and assistant messages
203
+ user_messages = [
204
+ msg for msg in original_memory if msg.role == MessageRole.USER
205
+ ]
206
+ assistant_messages = [
207
+ msg for msg in original_memory if msg.role == MessageRole.ASSISTANT
208
+ ]
209
+
210
+ self.assertGreater(
211
+ len(user_messages), 0, "Should have user messages in memory"
212
+ )
213
+ self.assertGreater(
214
+ len(assistant_messages), 0, "Should have assistant messages in memory"
215
+ )
216
+
217
+ async def test_react_memory_async_streaming_consistency(self):
218
+ """Test memory consistency during async streaming operations with ReAct agents."""
219
+ agent = Agent(
220
+ agent_config=react_config_anthropic,
221
+ tools=self.tools,
222
+ topic=self.topic,
223
+ custom_instructions=self.instructions,
224
+ session_id=self.session_id + "_async_streaming",
225
+ )
226
+
227
+ with self.with_provider_fallback("Anthropic"):
228
+ # First streaming interaction
229
+ stream1 = await agent.astream_chat("Calculate 8 times 7.")
230
+ async for chunk in stream1.async_response_gen():
231
+ pass
232
+ response1 = await stream1.aget_response()
233
+ self.check_response_and_skip(response1, "Anthropic")
234
+
235
+ # Check memory after first streaming interaction
236
+ memory_after_first = agent.memory.get_all()
237
+ self.assertGreater(len(memory_after_first), 0)
238
+
239
+ # Second streaming interaction that references the first
240
+ stream2 = await agent.astream_chat(
241
+ "Subtract 6 from the result you just calculated."
242
+ )
243
+ async for chunk in stream2.async_response_gen():
244
+ pass
245
+ response2 = await stream2.aget_response()
246
+ self.check_response_and_skip(response2, "Anthropic")
247
+
248
+ # Memory should contain both interactions
249
+ memory_after_second = agent.memory.get_all()
250
+ self.assertGreater(len(memory_after_second), len(memory_after_first))
251
+
252
+ # Final result should be (8*7)-6 = 56-6 = 50
253
+ self.assertIn("50", response2.response)
254
+
255
+
256
+ if __name__ == "__main__":
257
+ unittest.main()
@@ -0,0 +1,135 @@
1
+ # Suppress external dependency warnings before any other imports
2
+ import warnings
3
+
4
+ warnings.simplefilter("ignore", DeprecationWarning)
5
+
6
+ import unittest
7
+
8
+ from vectara_agentic.agent import Agent
9
+ from vectara_agentic.tools import ToolsFactory
10
+
11
+ import nest_asyncio
12
+
13
+ nest_asyncio.apply()
14
+
15
+ from conftest import (
16
+ AgentTestMixin,
17
+ react_config_openai,
18
+ react_config_anthropic,
19
+ react_config_gemini,
20
+ react_config_together,
21
+ mult,
22
+ STANDARD_TEST_TOPIC,
23
+ STANDARD_TEST_INSTRUCTIONS,
24
+ )
25
+
26
+
27
+ class TestReActStreaming(unittest.IsolatedAsyncioTestCase, AgentTestMixin):
28
+ """Test streaming functionality for ReAct agents across all providers."""
29
+
30
+ def setUp(self):
31
+ self.tools = [ToolsFactory().create_tool(mult)]
32
+ self.topic = STANDARD_TEST_TOPIC
33
+ self.instructions = STANDARD_TEST_INSTRUCTIONS
34
+
35
+ async def _test_react_streaming_workflow(self, config, provider_name):
36
+ """Common workflow for testing ReAct streaming with any provider."""
37
+ agent = Agent(
38
+ agent_config=config,
39
+ tools=self.tools,
40
+ topic=self.topic,
41
+ custom_instructions=self.instructions,
42
+ )
43
+
44
+ with self.with_provider_fallback(provider_name):
45
+ # First calculation: 5 * 10 = 50
46
+ stream1 = await agent.astream_chat(
47
+ "What is 5 times 10. Only give the answer, nothing else"
48
+ )
49
+ # Consume the stream
50
+ async for chunk in stream1.async_response_gen():
51
+ pass
52
+ response1 = await stream1.aget_response()
53
+ self.check_response_and_skip(response1, provider_name)
54
+
55
+ # Second calculation: 3 * 7 = 21
56
+ stream2 = await agent.astream_chat(
57
+ "what is 3 times 7. Only give the answer, nothing else"
58
+ )
59
+ # Consume the stream
60
+ async for chunk in stream2.async_response_gen():
61
+ pass
62
+ response2 = await stream2.aget_response()
63
+ self.check_response_and_skip(response2, provider_name)
64
+
65
+ # Final calculation: 50 * 21 = 1050
66
+ stream3 = await agent.astream_chat(
67
+ "multiply the results of the last two multiplications. Only give the answer, nothing else."
68
+ )
69
+ # Consume the stream and collect chunks for verification
70
+ chunks = []
71
+ async for chunk in stream3.async_response_gen():
72
+ chunks.append(chunk)
73
+
74
+ response3 = await stream3.aget_response()
75
+ self.check_response_and_skip(response3, provider_name)
76
+
77
+ # Verify the final result
78
+ self.assertIn("1050", response3.response)
79
+
80
+ # Verify we actually got streaming chunks
81
+ self.assertGreater(
82
+ len(chunks), 0, f"{provider_name} should produce streaming chunks"
83
+ )
84
+
85
+ async def test_anthropic_react_streaming(self):
86
+ """Test ReAct agent streaming with Anthropic."""
87
+ await self._test_react_streaming_workflow(react_config_anthropic, "Anthropic")
88
+
89
+ async def test_openai_react_streaming(self):
90
+ """Test ReAct agent streaming with OpenAI."""
91
+ await self._test_react_streaming_workflow(react_config_openai, "OpenAI")
92
+
93
+ async def test_gemini_react_streaming(self):
94
+ """Test ReAct agent streaming with Gemini."""
95
+ await self._test_react_streaming_workflow(react_config_gemini, "Gemini")
96
+
97
+ async def test_together_react_streaming(self):
98
+ """Test ReAct agent streaming with Together.AI."""
99
+ await self._test_react_streaming_workflow(react_config_together, "Together AI")
100
+
101
+ async def test_react_streaming_reasoning_pattern(self):
102
+ """Test that ReAct agents demonstrate reasoning patterns in streaming responses."""
103
+ agent = Agent(
104
+ agent_config=react_config_anthropic,
105
+ tools=self.tools,
106
+ topic=self.topic,
107
+ custom_instructions="Think step by step and show your reasoning before using tools.",
108
+ )
109
+
110
+ with self.with_provider_fallback("Anthropic"):
111
+ # Ask a question that requires multi-step reasoning
112
+ stream = await agent.astream_chat(
113
+ "I need to calculate 7 times 8, then add 12 to that result, then multiply by 2. "
114
+ "Show me your reasoning process."
115
+ )
116
+
117
+ chunks = []
118
+ async for chunk in stream.async_response_gen():
119
+ chunks.append(str(chunk))
120
+
121
+ response = await stream.aget_response()
122
+ self.check_response_and_skip(response, "Anthropic")
123
+
124
+ # Verify we got streaming content
125
+ self.assertGreater(len(chunks), 0)
126
+
127
+ # For ReAct agents, we should see reasoning patterns in the response
128
+ full_content = "".join(chunks).lower()
129
+
130
+ # The final answer should be correct: (7*8 + 12) * 2 = (56 + 12) * 2 = 68 * 2 = 136
131
+ self.assertTrue("136" in response.response or "136" in full_content)
132
+
133
+
134
+ if __name__ == "__main__":
135
+ unittest.main()