vectara-agentic 0.2.5__py3-none-any.whl → 0.2.7__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.
- tests/test_agent.py +73 -51
- tests/test_agent_planning.py +47 -20
- tests/test_agent_type.py +104 -10
- tests/test_fallback.py +83 -0
- tests/test_private_llm.py +11 -10
- tests/test_tools.py +1 -1
- tests/test_workflow.py +31 -6
- vectara_agentic/_observability.py +1 -1
- vectara_agentic/_prompts.py +5 -5
- vectara_agentic/_version.py +1 -1
- vectara_agentic/agent.py +226 -111
- vectara_agentic/sub_query_workflow.py +142 -3
- vectara_agentic/tools.py +97 -74
- vectara_agentic/types.py +6 -0
- vectara_agentic/utils.py +50 -11
- {vectara_agentic-0.2.5.dist-info → vectara_agentic-0.2.7.dist-info}/METADATA +10 -9
- vectara_agentic-0.2.7.dist-info/RECORD +28 -0
- {vectara_agentic-0.2.5.dist-info → vectara_agentic-0.2.7.dist-info}/WHEEL +1 -1
- vectara_agentic-0.2.5.dist-info/RECORD +0 -27
- {vectara_agentic-0.2.5.dist-info → vectara_agentic-0.2.7.dist-info/licenses}/LICENSE +0 -0
- {vectara_agentic-0.2.5.dist-info → vectara_agentic-0.2.7.dist-info}/top_level.txt +0 -0
vectara_agentic/agent.py
CHANGED
|
@@ -8,7 +8,6 @@ from datetime import date
|
|
|
8
8
|
import time
|
|
9
9
|
import json
|
|
10
10
|
import logging
|
|
11
|
-
import traceback
|
|
12
11
|
import asyncio
|
|
13
12
|
import importlib
|
|
14
13
|
from collections import Counter
|
|
@@ -17,24 +16,25 @@ import cloudpickle as pickle
|
|
|
17
16
|
|
|
18
17
|
from dotenv import load_dotenv
|
|
19
18
|
|
|
20
|
-
from retrying import retry
|
|
21
19
|
from pydantic import Field, create_model, ValidationError
|
|
22
20
|
|
|
23
21
|
from llama_index.core.memory import ChatMemoryBuffer
|
|
24
22
|
from llama_index.core.llms import ChatMessage, MessageRole
|
|
25
23
|
from llama_index.core.tools import FunctionTool
|
|
26
|
-
from llama_index.core.agent import ReActAgent, StructuredPlannerAgent
|
|
24
|
+
from llama_index.core.agent import ReActAgent, StructuredPlannerAgent, FunctionCallingAgent
|
|
27
25
|
from llama_index.core.agent.react.formatter import ReActChatFormatter
|
|
28
26
|
from llama_index.agent.llm_compiler import LLMCompilerAgentWorker
|
|
29
27
|
from llama_index.agent.lats import LATSAgentWorker
|
|
30
28
|
from llama_index.core.callbacks import CallbackManager, TokenCountingHandler
|
|
31
29
|
from llama_index.core.callbacks.base_handler import BaseCallbackHandler
|
|
32
30
|
from llama_index.agent.openai import OpenAIAgent
|
|
31
|
+
from llama_index.core.agent.runner.base import AgentRunner
|
|
32
|
+
from llama_index.core.agent.types import BaseAgent
|
|
33
33
|
from llama_index.core.workflow import Workflow
|
|
34
34
|
|
|
35
35
|
from .types import (
|
|
36
36
|
AgentType, AgentStatusType, LLMRole, ToolType,
|
|
37
|
-
AgentResponse, AgentStreamingResponse,
|
|
37
|
+
AgentResponse, AgentStreamingResponse, AgentConfigType
|
|
38
38
|
)
|
|
39
39
|
from .utils import get_llm, get_tokenizer_for_model
|
|
40
40
|
from ._prompts import (
|
|
@@ -103,9 +103,6 @@ def _get_llm_compiler_prompt(prompt: str, topic: str, custom_instructions: str)
|
|
|
103
103
|
prompt += f"Today is {date.today().strftime('%A, %B %d, %Y')}"
|
|
104
104
|
return prompt
|
|
105
105
|
|
|
106
|
-
def _retry_if_exception(exception):
|
|
107
|
-
# Define the condition to retry on certain exceptions
|
|
108
|
-
return isinstance(exception, (TimeoutError))
|
|
109
106
|
|
|
110
107
|
def get_field_type(field_schema: dict) -> Any:
|
|
111
108
|
"""
|
|
@@ -151,6 +148,7 @@ class Agent:
|
|
|
151
148
|
agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
152
149
|
query_logging_callback: Optional[Callable[[str, str], None]] = None,
|
|
153
150
|
agent_config: Optional[AgentConfig] = None,
|
|
151
|
+
fallback_agent_config: Optional[AgentConfig] = None,
|
|
154
152
|
chat_history: Optional[list[Tuple[str, str]]] = None,
|
|
155
153
|
validate_tools: bool = False,
|
|
156
154
|
workflow_cls: Workflow = None,
|
|
@@ -172,6 +170,8 @@ class Agent:
|
|
|
172
170
|
query_logging_callback (Callable): A callback function the code calls upon completion of a query
|
|
173
171
|
agent_config (AgentConfig, optional): The configuration of the agent.
|
|
174
172
|
Defaults to AgentConfig(), which reads from environment variables.
|
|
173
|
+
fallback_agent_config (AgentConfig, optional): The fallback configuration of the agent.
|
|
174
|
+
This config is used when the main agent config fails multiple times.
|
|
175
175
|
chat_history (Tuple[str, str], optional): A list of user/agent chat pairs to initialize the agent memory.
|
|
176
176
|
validate_tools (bool, optional): Whether to validate tool inconsistency with instructions.
|
|
177
177
|
Defaults to False.
|
|
@@ -179,12 +179,12 @@ class Agent:
|
|
|
179
179
|
workflow_timeout (int, optional): The timeout for the workflow in seconds. Defaults to 120.
|
|
180
180
|
"""
|
|
181
181
|
self.agent_config = agent_config or AgentConfig()
|
|
182
|
-
self.
|
|
183
|
-
self.use_structured_planning = use_structured_planning
|
|
182
|
+
self.agent_config_type = AgentConfigType.DEFAULT
|
|
184
183
|
self.tools = tools
|
|
185
184
|
if not any(tool.metadata.name == 'get_current_date' for tool in self.tools):
|
|
186
185
|
self.tools += [ToolsFactory().create_tool(get_current_date)]
|
|
187
|
-
|
|
186
|
+
self.agent_type = self.agent_config.agent_type
|
|
187
|
+
self.use_structured_planning = use_structured_planning
|
|
188
188
|
self.llm = get_llm(LLMRole.MAIN, config=self.agent_config)
|
|
189
189
|
self._custom_instructions = custom_instructions
|
|
190
190
|
self._topic = topic
|
|
@@ -231,7 +231,6 @@ class Agent:
|
|
|
231
231
|
if self.tool_token_counter:
|
|
232
232
|
callbacks.append(self.tool_token_counter)
|
|
233
233
|
callback_manager = CallbackManager(callbacks) # type: ignore
|
|
234
|
-
self.llm.callback_manager = callback_manager
|
|
235
234
|
self.verbose = verbose
|
|
236
235
|
|
|
237
236
|
if chat_history:
|
|
@@ -243,83 +242,130 @@ class Agent:
|
|
|
243
242
|
else:
|
|
244
243
|
self.memory = ChatMemoryBuffer.from_defaults(token_limit=128000)
|
|
245
244
|
|
|
246
|
-
#
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
# Set up main agent and fallback agent
|
|
246
|
+
self.agent = self._create_agent(self.agent_config, callback_manager)
|
|
247
|
+
self.fallback_agent_config = fallback_agent_config
|
|
248
|
+
if self.fallback_agent_config:
|
|
249
|
+
self.fallback_agent = self._create_agent(self.fallback_agent_config, callback_manager)
|
|
250
|
+
else:
|
|
251
|
+
self.fallback_agent_config = None
|
|
252
|
+
|
|
253
|
+
# Setup observability
|
|
254
|
+
try:
|
|
255
|
+
self.observability_enabled = setup_observer(self.agent_config)
|
|
256
|
+
except Exception as e:
|
|
257
|
+
print(f"Failed to set up observer ({e}), ignoring")
|
|
258
|
+
self.observability_enabled = False
|
|
259
|
+
|
|
260
|
+
def _create_agent(
|
|
261
|
+
self,
|
|
262
|
+
config: AgentConfig,
|
|
263
|
+
llm_callback_manager: CallbackManager
|
|
264
|
+
) -> Union[BaseAgent, AgentRunner]:
|
|
265
|
+
"""
|
|
266
|
+
Creates the agent based on the configuration object.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
|
|
270
|
+
config: The configuration of the agent.
|
|
271
|
+
llm_callback_manager: The callback manager for the agent's llm.
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Union[BaseAgent, AgentRunner]: The configured agent object.
|
|
275
|
+
"""
|
|
276
|
+
agent_type = config.agent_type
|
|
277
|
+
llm = get_llm(LLMRole.MAIN, config=config)
|
|
278
|
+
llm.callback_manager = llm_callback_manager
|
|
279
|
+
|
|
280
|
+
if agent_type == AgentType.FUNCTION_CALLING:
|
|
281
|
+
prompt = _get_prompt(GENERAL_PROMPT_TEMPLATE, self._topic, self._custom_instructions)
|
|
282
|
+
agent = FunctionCallingAgent.from_tools(
|
|
283
|
+
tools=self.tools,
|
|
284
|
+
llm=llm,
|
|
285
|
+
memory=self.memory,
|
|
286
|
+
verbose=self.verbose,
|
|
287
|
+
max_function_calls=config.max_reasoning_steps,
|
|
288
|
+
callback_manager=llm_callback_manager,
|
|
289
|
+
system_prompt = prompt,
|
|
290
|
+
allow_parallel_tool_calls=True,
|
|
291
|
+
)
|
|
292
|
+
elif agent_type == AgentType.REACT:
|
|
293
|
+
prompt = _get_prompt(REACT_PROMPT_TEMPLATE, self._topic, self._custom_instructions)
|
|
294
|
+
agent = ReActAgent.from_tools(
|
|
250
295
|
tools=self.tools,
|
|
251
|
-
llm=
|
|
296
|
+
llm=llm,
|
|
252
297
|
memory=self.memory,
|
|
253
|
-
verbose=verbose,
|
|
298
|
+
verbose=self.verbose,
|
|
254
299
|
react_chat_formatter=ReActChatFormatter(system_header=prompt),
|
|
255
|
-
max_iterations=
|
|
256
|
-
callable_manager=
|
|
300
|
+
max_iterations=config.max_reasoning_steps,
|
|
301
|
+
callable_manager=llm_callback_manager,
|
|
257
302
|
)
|
|
258
|
-
elif
|
|
259
|
-
prompt = _get_prompt(GENERAL_PROMPT_TEMPLATE,
|
|
260
|
-
|
|
303
|
+
elif agent_type == AgentType.OPENAI:
|
|
304
|
+
prompt = _get_prompt(GENERAL_PROMPT_TEMPLATE, self._topic, self._custom_instructions)
|
|
305
|
+
agent = OpenAIAgent.from_tools(
|
|
261
306
|
tools=self.tools,
|
|
262
|
-
llm=
|
|
307
|
+
llm=llm,
|
|
263
308
|
memory=self.memory,
|
|
264
|
-
verbose=verbose,
|
|
265
|
-
|
|
266
|
-
max_function_calls=
|
|
309
|
+
verbose=self.verbose,
|
|
310
|
+
callback_manager=llm_callback_manager,
|
|
311
|
+
max_function_calls=config.max_reasoning_steps,
|
|
267
312
|
system_prompt=prompt,
|
|
268
313
|
)
|
|
269
|
-
elif
|
|
314
|
+
elif agent_type == AgentType.LLMCOMPILER:
|
|
270
315
|
agent_worker = LLMCompilerAgentWorker.from_tools(
|
|
271
316
|
tools=self.tools,
|
|
272
|
-
llm=
|
|
273
|
-
verbose=verbose,
|
|
274
|
-
|
|
317
|
+
llm=llm,
|
|
318
|
+
verbose=self.verbose,
|
|
319
|
+
callback_manager=llm_callback_manager,
|
|
275
320
|
)
|
|
276
321
|
agent_worker.system_prompt = _get_prompt(
|
|
277
|
-
_get_llm_compiler_prompt(agent_worker.system_prompt,
|
|
278
|
-
|
|
322
|
+
_get_llm_compiler_prompt(agent_worker.system_prompt, self._topic, self._custom_instructions),
|
|
323
|
+
self._topic, self._custom_instructions
|
|
279
324
|
)
|
|
280
325
|
agent_worker.system_prompt_replan = _get_prompt(
|
|
281
|
-
_get_llm_compiler_prompt(agent_worker.system_prompt_replan,
|
|
282
|
-
|
|
326
|
+
_get_llm_compiler_prompt(agent_worker.system_prompt_replan, self._topic, self._custom_instructions),
|
|
327
|
+
self._topic, self._custom_instructions
|
|
283
328
|
)
|
|
284
|
-
|
|
285
|
-
elif
|
|
329
|
+
agent = agent_worker.as_agent()
|
|
330
|
+
elif agent_type == AgentType.LATS:
|
|
286
331
|
agent_worker = LATSAgentWorker.from_tools(
|
|
287
332
|
tools=self.tools,
|
|
288
|
-
llm=
|
|
333
|
+
llm=llm,
|
|
289
334
|
num_expansions=3,
|
|
290
335
|
max_rollouts=-1,
|
|
291
|
-
verbose=verbose,
|
|
292
|
-
|
|
336
|
+
verbose=self.verbose,
|
|
337
|
+
callback_manager=llm_callback_manager,
|
|
293
338
|
)
|
|
294
|
-
prompt = _get_prompt(REACT_PROMPT_TEMPLATE,
|
|
339
|
+
prompt = _get_prompt(REACT_PROMPT_TEMPLATE, self._topic, self._custom_instructions)
|
|
295
340
|
agent_worker.chat_formatter = ReActChatFormatter(system_header=prompt)
|
|
296
|
-
|
|
341
|
+
agent = agent_worker.as_agent()
|
|
297
342
|
else:
|
|
298
|
-
raise ValueError(f"Unknown agent type: {
|
|
299
|
-
|
|
300
|
-
try:
|
|
301
|
-
self.observability_enabled = setup_observer(self.agent_config)
|
|
302
|
-
except Exception as e:
|
|
303
|
-
print(f"Failed to set up observer ({e}), ignoring")
|
|
304
|
-
self.observability_enabled = False
|
|
343
|
+
raise ValueError(f"Unknown agent type: {agent_type}")
|
|
305
344
|
|
|
306
345
|
# Set up structured planner if needed
|
|
307
346
|
if (self.use_structured_planning
|
|
308
347
|
or self.agent_type in [AgentType.LLMCOMPILER, AgentType.LATS]):
|
|
309
|
-
|
|
310
|
-
agent_worker=
|
|
348
|
+
agent = StructuredPlannerAgent(
|
|
349
|
+
agent_worker=agent.agent_worker,
|
|
311
350
|
tools=self.tools,
|
|
312
351
|
memory=self.memory,
|
|
313
|
-
verbose=verbose,
|
|
352
|
+
verbose=self.verbose,
|
|
314
353
|
initial_plan_prompt=STRUCTURED_PLANNER_INITIAL_PLAN_PROMPT,
|
|
315
354
|
plan_refine_prompt=STRUCTURED_PLANNER_PLAN_REFINE_PROMPT,
|
|
316
355
|
)
|
|
317
356
|
|
|
357
|
+
return agent
|
|
358
|
+
|
|
318
359
|
def clear_memory(self) -> None:
|
|
319
360
|
"""
|
|
320
361
|
Clear the agent's memory.
|
|
321
362
|
"""
|
|
322
|
-
self.
|
|
363
|
+
if self.agent_config_type == AgentConfigType.DEFAULT:
|
|
364
|
+
self.agent.memory.reset()
|
|
365
|
+
elif self.agent_config_type == AgentConfigType.FALLBACK and self.fallback_agent_config:
|
|
366
|
+
self.fallback_agent.memory.reset()
|
|
367
|
+
else:
|
|
368
|
+
raise ValueError(f"Invalid agent config type {self.agent_config_type}")
|
|
323
369
|
|
|
324
370
|
def __eq__(self, other):
|
|
325
371
|
if not isinstance(other, Agent):
|
|
@@ -327,10 +373,10 @@ class Agent:
|
|
|
327
373
|
return False
|
|
328
374
|
|
|
329
375
|
# Compare agent_type
|
|
330
|
-
if self.agent_type != other.agent_type:
|
|
376
|
+
if self.agent_config.agent_type != other.agent_config.agent_type:
|
|
331
377
|
print(
|
|
332
|
-
f"Comparison failed: agent_type differs. (self.agent_type: {self.agent_type},
|
|
333
|
-
f"other.agent_type: {other.agent_type})"
|
|
378
|
+
f"Comparison failed: agent_type differs. (self.agent_config.agent_type: {self.agent_config.agent_type},"
|
|
379
|
+
f" other.agent_config.agent_type: {other.agent_config.agent_type})"
|
|
334
380
|
)
|
|
335
381
|
return False
|
|
336
382
|
|
|
@@ -360,7 +406,7 @@ class Agent:
|
|
|
360
406
|
print(f"Comparison failed: verbose differs. (self.verbose: {self.verbose}, other.verbose: {other.verbose})")
|
|
361
407
|
return False
|
|
362
408
|
|
|
363
|
-
# Compare agent
|
|
409
|
+
# Compare agent memory
|
|
364
410
|
if self.agent.memory.chat_store != other.agent.memory.chat_store:
|
|
365
411
|
print(
|
|
366
412
|
f"Comparison failed: agent memory differs. (self.agent: {repr(self.agent.memory.chat_store)}, "
|
|
@@ -383,7 +429,11 @@ class Agent:
|
|
|
383
429
|
agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
384
430
|
query_logging_callback: Optional[Callable[[str, str], None]] = None,
|
|
385
431
|
agent_config: AgentConfig = AgentConfig(),
|
|
432
|
+
validate_tools: bool = False,
|
|
433
|
+
fallback_agent_config: Optional[AgentConfig] = None,
|
|
386
434
|
chat_history: Optional[list[Tuple[str, str]]] = None,
|
|
435
|
+
workflow_cls: Workflow = None,
|
|
436
|
+
workflow_timeout: int = 120,
|
|
387
437
|
) -> "Agent":
|
|
388
438
|
"""
|
|
389
439
|
Create an agent from tools, agent type, and language model.
|
|
@@ -398,7 +448,12 @@ class Agent:
|
|
|
398
448
|
update_func (Callable): old name for agent_progress_callback. Will be deprecated in future.
|
|
399
449
|
query_logging_callback (Callable): A callback function the code calls upon completion of a query
|
|
400
450
|
agent_config (AgentConfig, optional): The configuration of the agent.
|
|
451
|
+
fallback_agent_config (AgentConfig, optional): The fallback configuration of the agent.
|
|
401
452
|
chat_history (Tuple[str, str], optional): A list of user/agent chat pairs to initialize the agent memory.
|
|
453
|
+
validate_tools (bool, optional): Whether to validate tool inconsistency with instructions.
|
|
454
|
+
Defaults to False.
|
|
455
|
+
workflow_cls (Workflow, optional): The workflow class to be used with run(). Defaults to None.
|
|
456
|
+
workflow_timeout (int, optional): The timeout for the workflow in seconds. Defaults to 120.
|
|
402
457
|
|
|
403
458
|
Returns:
|
|
404
459
|
Agent: An instance of the Agent class.
|
|
@@ -409,6 +464,9 @@ class Agent:
|
|
|
409
464
|
query_logging_callback=query_logging_callback,
|
|
410
465
|
update_func=update_func, agent_config=agent_config,
|
|
411
466
|
chat_history=chat_history,
|
|
467
|
+
validate_tools=validate_tools,
|
|
468
|
+
fallback_agent_config=fallback_agent_config,
|
|
469
|
+
workflow_cls = workflow_cls, workflow_timeout = workflow_timeout,
|
|
412
470
|
)
|
|
413
471
|
|
|
414
472
|
@classmethod
|
|
@@ -421,6 +479,9 @@ class Agent:
|
|
|
421
479
|
vectara_api_key: str = str(os.environ.get("VECTARA_API_KEY", "")),
|
|
422
480
|
agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
423
481
|
query_logging_callback: Optional[Callable[[str, str], None]] = None,
|
|
482
|
+
agent_config: AgentConfig = AgentConfig(),
|
|
483
|
+
fallback_agent_config: Optional[AgentConfig] = None,
|
|
484
|
+
chat_history: Optional[list[Tuple[str, str]]] = None,
|
|
424
485
|
verbose: bool = False,
|
|
425
486
|
vectara_filter_fields: list[dict] = [],
|
|
426
487
|
vectara_offset: int = 0,
|
|
@@ -456,6 +517,9 @@ class Agent:
|
|
|
456
517
|
vectara_api_key (str): The Vectara API key.
|
|
457
518
|
agent_progress_callback (Callable): A callback function the code calls on any agent updates.
|
|
458
519
|
query_logging_callback (Callable): A callback function the code calls upon completion of a query
|
|
520
|
+
agent_config (AgentConfig, optional): The configuration of the agent.
|
|
521
|
+
fallback_agent_config (AgentConfig, optional): The fallback configuration of the agent.
|
|
522
|
+
chat_history (Tuple[str, str], optional): A list of user/agent chat pairs to initialize the agent memory.
|
|
459
523
|
data_description (str): The description of the data.
|
|
460
524
|
assistant_specialty (str): The specialty of the assistant.
|
|
461
525
|
verbose (bool, optional): Whether to print verbose output.
|
|
@@ -557,22 +621,41 @@ class Agent:
|
|
|
557
621
|
verbose=verbose,
|
|
558
622
|
agent_progress_callback=agent_progress_callback,
|
|
559
623
|
query_logging_callback=query_logging_callback,
|
|
624
|
+
agent_config=agent_config,
|
|
625
|
+
fallback_agent_config=fallback_agent_config,
|
|
626
|
+
chat_history=chat_history,
|
|
560
627
|
)
|
|
561
628
|
|
|
562
|
-
def
|
|
629
|
+
def _switch_agent_config(self) -> None:
|
|
630
|
+
""""
|
|
631
|
+
Switch the configuration type of the agent.
|
|
632
|
+
This function is called automatically to switch the agent configuration if the current configuration fails.
|
|
633
|
+
"""
|
|
634
|
+
if self.agent_config_type == AgentConfigType.DEFAULT:
|
|
635
|
+
self.agent_config_type = AgentConfigType.FALLBACK
|
|
636
|
+
else:
|
|
637
|
+
self.agent_config_type = AgentConfigType.DEFAULT
|
|
638
|
+
|
|
639
|
+
def report(self, detailed: bool = False) -> None:
|
|
563
640
|
"""
|
|
564
641
|
Get a report from the agent.
|
|
565
642
|
|
|
643
|
+
Args:
|
|
644
|
+
detailed (bool, optional): Whether to include detailed information. Defaults to False.
|
|
645
|
+
|
|
566
646
|
Returns:
|
|
567
647
|
str: The report from the agent.
|
|
568
648
|
"""
|
|
569
649
|
print("Vectara agentic Report:")
|
|
570
|
-
print(f"Agent Type = {self.agent_type}")
|
|
650
|
+
print(f"Agent Type = {self.agent_config.agent_type}")
|
|
571
651
|
print(f"Topic = {self._topic}")
|
|
572
652
|
print("Tools:")
|
|
573
653
|
for tool in self.tools:
|
|
574
654
|
if hasattr(tool, 'metadata'):
|
|
575
|
-
|
|
655
|
+
if detailed:
|
|
656
|
+
print(f"- {tool.metadata.name} - {tool.metadata.description}")
|
|
657
|
+
else:
|
|
658
|
+
print(f"- {tool.metadata.name}")
|
|
576
659
|
else:
|
|
577
660
|
print("- tool without metadata")
|
|
578
661
|
print(f"Agent LLM = {get_llm(LLMRole.MAIN, config=self.agent_config).metadata.model_name}")
|
|
@@ -590,13 +673,27 @@ class Agent:
|
|
|
590
673
|
"tool token count": self.tool_token_counter.total_llm_token_count if self.tool_token_counter else -1,
|
|
591
674
|
}
|
|
592
675
|
|
|
676
|
+
def _get_current_agent(self):
|
|
677
|
+
return self.agent if self.agent_config_type == AgentConfigType.DEFAULT else self.fallback_agent
|
|
678
|
+
|
|
679
|
+
def _get_current_agent_type(self):
|
|
680
|
+
return (
|
|
681
|
+
self.agent_config.agent_type if self.agent_config_type == AgentConfigType.DEFAULT
|
|
682
|
+
else self.fallback_agent_config.agent_type
|
|
683
|
+
)
|
|
684
|
+
|
|
593
685
|
async def _aformat_for_lats(self, prompt, agent_response):
|
|
594
686
|
llm_prompt = f"""
|
|
595
687
|
Given the question '{prompt}', and agent response '{agent_response.response}',
|
|
596
688
|
Please provide a well formatted final response to the query.
|
|
597
689
|
final response:
|
|
598
690
|
"""
|
|
599
|
-
|
|
691
|
+
agent_type = self._get_current_agent_type()
|
|
692
|
+
if agent_type != AgentType.LATS:
|
|
693
|
+
return
|
|
694
|
+
|
|
695
|
+
agent = self._get_current_agent()
|
|
696
|
+
agent_response.response = str(agent.llm.acomplete(llm_prompt))
|
|
600
697
|
|
|
601
698
|
def chat(self, prompt: str) -> AgentResponse: # type: ignore
|
|
602
699
|
"""
|
|
@@ -610,12 +707,7 @@ class Agent:
|
|
|
610
707
|
"""
|
|
611
708
|
return asyncio.run(self.achat(prompt))
|
|
612
709
|
|
|
613
|
-
|
|
614
|
-
retry_on_exception=_retry_if_exception,
|
|
615
|
-
stop_max_attempt_number=3,
|
|
616
|
-
wait_fixed=2000,
|
|
617
|
-
)
|
|
618
|
-
async def achat(self, prompt: str) -> AgentResponse: # type: ignore
|
|
710
|
+
async def achat(self, prompt: str) -> AgentResponse: # type: ignore
|
|
619
711
|
"""
|
|
620
712
|
Interact with the agent using a chat prompt.
|
|
621
713
|
|
|
@@ -625,25 +717,36 @@ class Agent:
|
|
|
625
717
|
Returns:
|
|
626
718
|
AgentResponse: The response from the agent.
|
|
627
719
|
"""
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
720
|
+
max_attempts = 4 if self.fallback_agent_config else 2
|
|
721
|
+
attempt = 0
|
|
722
|
+
orig_llm = self.llm.metadata.model_name
|
|
723
|
+
last_error = None
|
|
724
|
+
while attempt < max_attempts:
|
|
725
|
+
try:
|
|
726
|
+
current_agent = self._get_current_agent()
|
|
727
|
+
agent_response = await current_agent.achat(prompt)
|
|
632
728
|
await self._aformat_for_lats(prompt, agent_response)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
)
|
|
729
|
+
if self.observability_enabled:
|
|
730
|
+
eval_fcs()
|
|
731
|
+
if self.query_logging_callback:
|
|
732
|
+
self.query_logging_callback(prompt, agent_response.response)
|
|
733
|
+
return agent_response
|
|
734
|
+
|
|
735
|
+
except Exception as e:
|
|
736
|
+
last_error = e
|
|
737
|
+
if attempt >= 2:
|
|
738
|
+
if self.verbose:
|
|
739
|
+
print(f"LLM call failed on attempt {attempt}. Switching agent configuration.")
|
|
740
|
+
self._switch_agent_config()
|
|
741
|
+
time.sleep(1)
|
|
742
|
+
attempt += 1
|
|
743
|
+
|
|
744
|
+
return AgentResponse(
|
|
745
|
+
response=(
|
|
746
|
+
f"For {orig_llm} LLM - failure can't be resolved after "
|
|
747
|
+
f"{max_attempts} attempts ({last_error}."
|
|
646
748
|
)
|
|
749
|
+
)
|
|
647
750
|
|
|
648
751
|
def stream_chat(self, prompt: str) -> AgentStreamingResponse: # type: ignore
|
|
649
752
|
"""
|
|
@@ -655,11 +758,6 @@ class Agent:
|
|
|
655
758
|
"""
|
|
656
759
|
return asyncio.run(self.astream_chat(prompt))
|
|
657
760
|
|
|
658
|
-
@retry(
|
|
659
|
-
retry_on_exception=_retry_if_exception,
|
|
660
|
-
stop_max_attempt_number=3,
|
|
661
|
-
wait_fixed=2000,
|
|
662
|
-
)
|
|
663
761
|
async def astream_chat(self, prompt: str) -> AgentStreamingResponse: # type: ignore
|
|
664
762
|
"""
|
|
665
763
|
Interact with the agent using a chat prompt asynchronously with streaming.
|
|
@@ -668,29 +766,39 @@ class Agent:
|
|
|
668
766
|
Returns:
|
|
669
767
|
AgentStreamingResponse: The streaming response from the agent.
|
|
670
768
|
"""
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
769
|
+
max_attempts = 4 if self.fallback_agent_config else 2
|
|
770
|
+
attempt = 0
|
|
771
|
+
while attempt < max_attempts:
|
|
772
|
+
try:
|
|
773
|
+
current_agent = self._get_current_agent()
|
|
774
|
+
agent_response = await current_agent.astream_chat(prompt)
|
|
775
|
+
original_async_response_gen = agent_response.async_response_gen
|
|
776
|
+
|
|
777
|
+
# Define a wrapper to preserve streaming behavior while executing post-stream logic.
|
|
778
|
+
async def _stream_response_wrapper():
|
|
779
|
+
async for token in original_async_response_gen():
|
|
780
|
+
yield token # Yield tokens as they are generated
|
|
781
|
+
# Post-streaming additional logic:
|
|
682
782
|
await self._aformat_for_lats(prompt, agent_response)
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
783
|
+
if self.query_logging_callback:
|
|
784
|
+
self.query_logging_callback(prompt, agent_response.response)
|
|
785
|
+
if self.observability_enabled:
|
|
786
|
+
eval_fcs()
|
|
787
|
+
|
|
788
|
+
agent_response.async_response_gen = _stream_response_wrapper # Override the generator
|
|
789
|
+
return agent_response
|
|
790
|
+
|
|
791
|
+
except Exception:
|
|
792
|
+
if attempt >= 2:
|
|
793
|
+
if self.verbose:
|
|
794
|
+
print("LLM call failed. Switching agent configuration.")
|
|
795
|
+
self._switch_agent_config()
|
|
796
|
+
time.sleep(1)
|
|
797
|
+
attempt += 1
|
|
798
|
+
|
|
799
|
+
return AgentResponse(
|
|
800
|
+
response=f"LLM failure can't be resolved after {max_attempts} attempts."
|
|
801
|
+
)
|
|
694
802
|
|
|
695
803
|
#
|
|
696
804
|
# run() method for running a workflow
|
|
@@ -783,13 +891,14 @@ class Agent:
|
|
|
783
891
|
tool_info.append(tool_dict)
|
|
784
892
|
|
|
785
893
|
return {
|
|
786
|
-
"agent_type": self.agent_type.value,
|
|
894
|
+
"agent_type": self.agent_config.agent_type.value,
|
|
787
895
|
"memory": pickle.dumps(self.agent.memory).decode("latin-1"),
|
|
788
896
|
"tools": tool_info,
|
|
789
897
|
"topic": self._topic,
|
|
790
898
|
"custom_instructions": self._custom_instructions,
|
|
791
899
|
"verbose": self.verbose,
|
|
792
900
|
"agent_config": self.agent_config.to_dict(),
|
|
901
|
+
"fallback_agent": self.fallback_agent_config.to_dict() if self.fallback_agent_config else None,
|
|
793
902
|
"workflow_cls": self.workflow_cls if self.workflow_cls else None,
|
|
794
903
|
}
|
|
795
904
|
|
|
@@ -797,6 +906,11 @@ class Agent:
|
|
|
797
906
|
def from_dict(cls, data: Dict[str, Any]) -> "Agent":
|
|
798
907
|
"""Create an Agent instance from a dictionary."""
|
|
799
908
|
agent_config = AgentConfig.from_dict(data["agent_config"])
|
|
909
|
+
fallback_agent_config = (
|
|
910
|
+
AgentConfig.from_dict(data["fallback_agent_config"])
|
|
911
|
+
if data.get("fallback_agent_config")
|
|
912
|
+
else None
|
|
913
|
+
)
|
|
800
914
|
tools = []
|
|
801
915
|
|
|
802
916
|
for tool_data in data["tools"]:
|
|
@@ -850,6 +964,7 @@ class Agent:
|
|
|
850
964
|
topic=data["topic"],
|
|
851
965
|
custom_instructions=data["custom_instructions"],
|
|
852
966
|
verbose=data["verbose"],
|
|
967
|
+
fallback_agent_config=fallback_agent_config,
|
|
853
968
|
workflow_cls=data["workflow_cls"],
|
|
854
969
|
)
|
|
855
970
|
memory = pickle.loads(data["memory"].encode("latin-1")) if data.get("memory") else None
|