vectara-agentic 0.1.24__py3-none-any.whl → 0.1.26__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.

@@ -7,3 +7,10 @@ from .tools import VectaraToolFactory, VectaraTool
7
7
 
8
8
  # Define the __all__ variable for wildcard imports
9
9
  __all__ = ['Agent', 'VectaraToolFactory', 'VectaraTool']
10
+
11
+ # Ensure package version is available
12
+ try:
13
+ import importlib.metadata
14
+ __version__ = importlib.metadata.version("vectara_agentic")
15
+ except Exception:
16
+ __version__ = "0.0.0" # fallback if not installed
@@ -5,6 +5,7 @@ This file contains the prompt templates for the different types of agents.
5
5
  # General (shared) instructions
6
6
  GENERAL_INSTRUCTIONS = """
7
7
  - Use tools as your main source of information, do not respond without using a tool. Do not respond based on pre-trained knowledge.
8
+ - Always call the 'get_current_date' tool to ensure you know the exact date when a user asks a question.
8
9
  - When using a tool with arguments, simplify the query as much as possible if you use the tool with arguments.
9
10
  For example, if the original query is "revenue for apple in 2021", you can use the tool with a query "revenue" with arguments year=2021 and company=apple.
10
11
  - If a tool responds with "I do not have enough information", try one of the following:
@@ -43,7 +44,7 @@ GENERAL_PROMPT_TEMPLATE = """
43
44
  You are a helpful chatbot in conversation with a user, with expertise in {chat_topic}.
44
45
 
45
46
  ## Date
46
- Today's date is {today}.
47
+ Your birth date is {today}.
47
48
 
48
49
  ## INSTRUCTIONS:
49
50
  IMPORTANT - FOLLOW THESE INSTRUCTIONS CAREFULLY:
@@ -63,7 +64,7 @@ You are designed to help with a variety of tasks, from answering questions to pr
63
64
  You have expertise in {chat_topic}.
64
65
 
65
66
  ## Date
66
- Today's date is {today}.
67
+ Your birth date is {today}.
67
68
 
68
69
  ## Tools
69
70
  You have access to a wide variety of tools.
@@ -1,4 +1,4 @@
1
1
  """
2
2
  Define the version of the package.
3
3
  """
4
- __version__ = "0.1.24"
4
+ __version__ = "0.1.26"
vectara_agentic/agent.py CHANGED
@@ -8,6 +8,7 @@ import time
8
8
  import json
9
9
  import logging
10
10
  import traceback
11
+ import asyncio
11
12
 
12
13
  import dill
13
14
  from dotenv import load_dotenv
@@ -25,12 +26,13 @@ from llama_index.core.callbacks.base_handler import BaseCallbackHandler
25
26
  from llama_index.agent.openai import OpenAIAgent
26
27
  from llama_index.core.memory import ChatMemoryBuffer
27
28
 
28
- from .types import AgentType, AgentStatusType, LLMRole, ToolType
29
+ from .types import AgentType, AgentStatusType, LLMRole, ToolType, AgentResponse, AgentStreamingResponse
29
30
  from .utils import get_llm, get_tokenizer_for_model
30
31
  from ._prompts import REACT_PROMPT_TEMPLATE, GENERAL_PROMPT_TEMPLATE, GENERAL_INSTRUCTIONS
31
32
  from ._callback import AgentCallbackHandler
32
33
  from ._observability import setup_observer, eval_fcs
33
- from .tools import VectaraToolFactory, VectaraTool
34
+ from .tools import VectaraToolFactory, VectaraTool, ToolsFactory
35
+ from .tools_catalog import get_current_date
34
36
  from .agent_config import AgentConfig
35
37
 
36
38
  logger = logging.getLogger("opentelemetry.exporter.otlp.proto.http.trace_exporter")
@@ -92,6 +94,7 @@ class Agent:
92
94
  verbose: bool = True,
93
95
  update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
94
96
  agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
97
+ query_logging_callback: Optional[Callable[[str, str], None]] = None,
95
98
  agent_config: Optional[AgentConfig] = None,
96
99
  ) -> None:
97
100
  """
@@ -105,16 +108,18 @@ class Agent:
105
108
  verbose (bool, optional): Whether the agent should print its steps. Defaults to True.
106
109
  agent_progress_callback (Callable): A callback function the code calls on any agent updates.
107
110
  update_func (Callable): old name for agent_progress_callback. Will be deprecated in future.
111
+ query_logging_callback (Callable): A callback function the code calls upon completion of a query
108
112
  agent_config (AgentConfig, optional): The configuration of the agent.
109
113
  Defaults to AgentConfig(), which reads from environment variables.
110
114
  """
111
115
  self.agent_config = agent_config or AgentConfig()
112
116
  self.agent_type = self.agent_config.agent_type
113
- self.tools = tools
117
+ self.tools = tools + [ToolsFactory().create_tool(get_current_date)]
114
118
  self.llm = get_llm(LLMRole.MAIN, config=self.agent_config)
115
119
  self._custom_instructions = custom_instructions
116
120
  self._topic = topic
117
121
  self.agent_progress_callback = agent_progress_callback if agent_progress_callback else update_func
122
+ self.query_logging_callback = query_logging_callback
118
123
 
119
124
  main_tok = get_tokenizer_for_model(role=LLMRole.MAIN)
120
125
  self.main_token_counter = TokenCountingHandler(tokenizer=main_tok) if main_tok else None
@@ -134,7 +139,7 @@ class Agent:
134
139
  if self.agent_type == AgentType.REACT:
135
140
  prompt = _get_prompt(REACT_PROMPT_TEMPLATE, topic, custom_instructions)
136
141
  self.agent = ReActAgent.from_tools(
137
- tools=tools,
142
+ tools=self.tools,
138
143
  llm=self.llm,
139
144
  memory=self.memory,
140
145
  verbose=verbose,
@@ -145,7 +150,7 @@ class Agent:
145
150
  elif self.agent_type == AgentType.OPENAI:
146
151
  prompt = _get_prompt(GENERAL_PROMPT_TEMPLATE, topic, custom_instructions)
147
152
  self.agent = OpenAIAgent.from_tools(
148
- tools=tools,
153
+ tools=self.tools,
149
154
  llm=self.llm,
150
155
  memory=self.memory,
151
156
  verbose=verbose,
@@ -154,23 +159,24 @@ class Agent:
154
159
  system_prompt=prompt,
155
160
  )
156
161
  elif self.agent_type == AgentType.LLMCOMPILER:
157
- self.agent = LLMCompilerAgentWorker.from_tools(
158
- tools=tools,
162
+ agent_worker = LLMCompilerAgentWorker.from_tools(
163
+ tools=self.tools,
159
164
  llm=self.llm,
160
165
  verbose=verbose,
161
166
  callable_manager=callback_manager,
162
- ).as_agent()
163
- self.agent.agent_worker.system_prompt = _get_prompt(
164
- _get_llm_compiler_prompt(self.agent.agent_worker.system_prompt, topic, custom_instructions),
167
+ )
168
+ agent_worker.system_prompt = _get_prompt(
169
+ _get_llm_compiler_prompt(agent_worker.system_prompt, topic, custom_instructions),
165
170
  topic, custom_instructions
166
171
  )
167
- self.agent.agent_worker.system_prompt_replan = _get_prompt(
168
- _get_llm_compiler_prompt(self.agent.agent_worker.system_prompt_replan, topic, custom_instructions),
172
+ agent_worker.system_prompt_replan = _get_prompt(
173
+ _get_llm_compiler_prompt(agent_worker.system_prompt_replan, topic, custom_instructions),
169
174
  topic, custom_instructions
170
175
  )
176
+ self.agent = agent_worker.as_agent()
171
177
  elif self.agent_type == AgentType.LATS:
172
178
  agent_worker = LATSAgentWorker.from_tools(
173
- tools=tools,
179
+ tools=self.tools,
174
180
  llm=self.llm,
175
181
  num_expansions=3,
176
182
  max_rollouts=-1,
@@ -255,6 +261,7 @@ class Agent:
255
261
  verbose: bool = True,
256
262
  update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
257
263
  agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
264
+ query_logging_callback: Optional[Callable[[str, str], None]] = None,
258
265
  agent_config: AgentConfig = AgentConfig(),
259
266
  ) -> "Agent":
260
267
  """
@@ -268,6 +275,7 @@ class Agent:
268
275
  verbose (bool, optional): Whether the agent should print its steps. Defaults to True.
269
276
  agent_progress_callback (Callable): A callback function the code calls on any agent updates.
270
277
  update_func (Callable): old name for agent_progress_callback. Will be deprecated in future.
278
+ query_logging_callback (Callable): A callback function the code calls upon completion of a query
271
279
  agent_config (AgentConfig, optional): The configuration of the agent.
272
280
 
273
281
  Returns:
@@ -276,6 +284,7 @@ class Agent:
276
284
  return cls(
277
285
  tools=tools, topic=topic, custom_instructions=custom_instructions,
278
286
  verbose=verbose, agent_progress_callback=agent_progress_callback,
287
+ query_logging_callback=query_logging_callback,
279
288
  update_func=update_func, agent_config=agent_config
280
289
  )
281
290
 
@@ -289,6 +298,7 @@ class Agent:
289
298
  vectara_corpus_id: str = str(os.environ.get("VECTARA_CORPUS_ID", "")),
290
299
  vectara_api_key: str = str(os.environ.get("VECTARA_API_KEY", "")),
291
300
  agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
301
+ query_logging_callback: Optional[Callable[[str, str], None]] = None,
292
302
  verbose: bool = False,
293
303
  vectara_filter_fields: list[dict] = [],
294
304
  vectara_lambda_val: float = 0.005,
@@ -308,6 +318,7 @@ class Agent:
308
318
  vectara_corpus_id (str): The Vectara corpus ID (or comma separated list of IDs).
309
319
  vectara_api_key (str): The Vectara API key.
310
320
  agent_progress_callback (Callable): A callback function the code calls on any agent updates.
321
+ query_logging_callback (Callable): A callback function the code calls upon completion of a query
311
322
  data_description (str): The description of the data.
312
323
  assistant_specialty (str): The specialty of the assistant.
313
324
  verbose (bool, optional): Whether to print verbose output.
@@ -367,6 +378,7 @@ class Agent:
367
378
  custom_instructions=assistant_instructions,
368
379
  verbose=verbose,
369
380
  agent_progress_callback=agent_progress_callback,
381
+ query_logging_callback=query_logging_callback,
370
382
  )
371
383
 
372
384
  def report(self) -> None:
@@ -385,8 +397,8 @@ class Agent:
385
397
  print(f"- {tool.metadata.name}")
386
398
  else:
387
399
  print("- tool without metadata")
388
- print(f"Agent LLM = {get_llm(LLMRole.MAIN).metadata.model_name}")
389
- print(f"Tool LLM = {get_llm(LLMRole.TOOL).metadata.model_name}")
400
+ print(f"Agent LLM = {get_llm(LLMRole.MAIN, config=self.agent_config).metadata.model_name}")
401
+ print(f"Tool LLM = {get_llm(LLMRole.TOOL, config=self.agent_config).metadata.model_name}")
390
402
 
391
403
  def token_counts(self) -> dict:
392
404
  """
@@ -400,12 +412,32 @@ class Agent:
400
412
  "tool token count": self.tool_token_counter.total_llm_token_count if self.tool_token_counter else -1,
401
413
  }
402
414
 
415
+ async def _aformat_for_lats(self, prompt, agent_response):
416
+ llm_prompt = f"""
417
+ Given the question '{prompt}', and agent response '{agent_response.response}',
418
+ Please provide a well formatted final response to the query.
419
+ final response:
420
+ """
421
+ agent_response.response = str(self.llm.acomplete(llm_prompt))
422
+
423
+ def chat(self, prompt: str) -> AgentResponse: # type: ignore
424
+ """
425
+ Interact with the agent using a chat prompt.
426
+
427
+ Args:
428
+ prompt (str): The chat prompt.
429
+
430
+ Returns:
431
+ AgentResponse: The response from the agent.
432
+ """
433
+ return asyncio.run(self.achat(prompt))
434
+
403
435
  @retry(
404
436
  retry_on_exception=_retry_if_exception,
405
437
  stop_max_attempt_number=3,
406
438
  wait_fixed=2000,
407
439
  )
408
- def chat(self, prompt: str) -> str:
440
+ async def achat(self, prompt: str) -> AgentResponse: # type: ignore
409
441
  """
410
442
  Interact with the agent using a chat prompt.
411
443
 
@@ -413,32 +445,79 @@ class Agent:
413
445
  prompt (str): The chat prompt.
414
446
 
415
447
  Returns:
416
- str: The response from the agent.
448
+ AgentResponse: The response from the agent.
417
449
  """
418
450
 
419
451
  try:
420
452
  st = time.time()
421
- agent_response = self.agent.chat(prompt)
453
+ agent_response = await self.agent.achat(prompt)
422
454
  if self.agent_type == AgentType.LATS:
423
- prompt = f"""
424
- Given the question '{prompt}', and agent response '{agent_response.response}',
425
- Please provide a well formatted final response to the query.
426
- final response:
427
- """
428
- final_response = str(self.llm.complete(prompt))
429
- else:
430
- final_response = agent_response.response
431
-
455
+ await self._aformat_for_lats(prompt, agent_response)
432
456
  if self.verbose:
433
457
  print(f"Time taken: {time.time() - st}")
434
458
  if self.observability_enabled:
435
459
  eval_fcs()
436
- return final_response
460
+ if self.query_logging_callback:
461
+ self.query_logging_callback(prompt, agent_response.response)
462
+ return agent_response
437
463
  except Exception as e:
438
- return f"Vectara Agentic: encountered an exception ({e}) at ({traceback.format_exc()}), and can't respond."
464
+ return AgentResponse(
465
+ response = (
466
+ f"Vectara Agentic: encountered an exception ({e}) at ({traceback.format_exc()})"
467
+ ", and can't respond."
468
+ )
469
+ )
439
470
 
440
- # Serialization methods
471
+ def stream_chat(self, prompt: str) -> AgentStreamingResponse: # type: ignore
472
+ """
473
+ Interact with the agent using a chat prompt with streaming.
474
+ Args:
475
+ prompt (str): The chat prompt.
476
+ Returns:
477
+ AgentStreamingResponse: The streaming response from the agent.
478
+ """
479
+ return asyncio.run(self.astream_chat(prompt))
480
+
481
+ @retry(
482
+ retry_on_exception=_retry_if_exception,
483
+ stop_max_attempt_number=3,
484
+ wait_fixed=2000,
485
+ )
486
+ async def astream_chat(self, prompt: str) -> AgentStreamingResponse: # type: ignore
487
+ """
488
+ Interact with the agent using a chat prompt asynchronously with streaming.
489
+ Args:
490
+ prompt (str): The chat prompt.
491
+ Returns:
492
+ AgentStreamingResponse: The streaming response from the agent.
493
+ """
494
+ try:
495
+ agent_response = await self.agent.astream_chat(prompt)
496
+ original_async_response_gen = agent_response.async_response_gen
497
+
498
+ # Wrap async_response_gen
499
+ async def _stream_response_wrapper():
500
+ async for token in original_async_response_gen():
501
+ yield token # Yield async token to keep streaming behavior
502
+
503
+ # After streaming completes, execute additional logic
504
+ if self.agent_type == AgentType.LATS:
505
+ await self._aformat_for_lats(prompt, agent_response)
506
+ if self.query_logging_callback:
507
+ self.query_logging_callback(prompt, agent_response.response)
508
+ if self.observability_enabled:
509
+ eval_fcs()
510
+
511
+ agent_response.async_response_gen = _stream_response_wrapper # Override method
512
+ return agent_response
513
+ except Exception as e:
514
+ raise ValueError(
515
+ f"Vectara Agentic: encountered an exception ({e}) at ({traceback.format_exc()}), and can't respond."
516
+ ) from e
441
517
 
518
+ #
519
+ # Serialization methods
520
+ #
442
521
  def dumps(self) -> str:
443
522
  """Serialize the Agent instance to a JSON string."""
444
523
  return json.dumps(self.to_dict())
@@ -31,7 +31,7 @@ class AgentConfig:
31
31
  )
32
32
 
33
33
  main_llm_model_name: str = field(
34
- default_factory=lambda: os.getenv("VECTARA_AGENTIC_MAIN_LLM_MODEL_NAME", "")
34
+ default_factory=lambda: os.getenv("VECTARA_AGENTIC_MAIN_MODEL_NAME", "")
35
35
  )
36
36
 
37
37
  # Tool LLM provider & model name
@@ -41,7 +41,7 @@ class AgentConfig:
41
41
  )
42
42
  )
43
43
  tool_llm_model_name: str = field(
44
- default_factory=lambda: os.getenv("VECTARA_AGENTIC_TOOL_LLM_MODEL_NAME", "")
44
+ default_factory=lambda: os.getenv("VECTARA_AGENTIC_TOOL_MODEL_NAME", "")
45
45
  )
46
46
 
47
47
  # Observer