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.

@@ -60,16 +60,24 @@ class SubQuestionQueryWorkflow(Workflow):
60
60
 
61
61
  if hasattr(ev, "agent"):
62
62
  await ctx.set("agent", ev.agent)
63
+ else:
64
+ raise ValueError("Agent not provided to workflow Start Event.")
63
65
  chat_history = [str(msg) for msg in ev.agent.memory.get()]
64
66
 
65
67
  if hasattr(ev, "llm"):
66
68
  await ctx.set("llm", ev.llm)
69
+ else:
70
+ raise ValueError("LLM not provided to workflow Start Event.")
67
71
 
68
72
  if hasattr(ev, "tools"):
69
73
  await ctx.set("tools", ev.tools)
74
+ else:
75
+ raise ValueError("Tools not provided to workflow Start Event.")
70
76
 
71
77
  if hasattr(ev, "verbose"):
72
78
  await ctx.set("verbose", ev.verbose)
79
+ else:
80
+ await ctx.set("verbose", False)
73
81
 
74
82
  llm = await ctx.get("llm")
75
83
  response = llm.complete(
@@ -77,6 +85,7 @@ class SubQuestionQueryWorkflow(Workflow):
77
85
  Given a user question, and a list of tools, output a list of
78
86
  relevant sub-questions, such that the answers to all the
79
87
  sub-questions put together will answer the question.
88
+ Order the sub-questions in the right order if there are dependencies.
80
89
  Make sure sub-questions do not result in duplicate tool calling.
81
90
  Respond in pure JSON without any markdown, like this:
82
91
  {{
@@ -106,11 +115,11 @@ class SubQuestionQueryWorkflow(Workflow):
106
115
  await ctx.set("sub_question_count", len(sub_questions))
107
116
 
108
117
  for question in sub_questions:
109
- self.send_event(self.QueryEvent(question=question))
118
+ ctx.send_event(self.QueryEvent(question=question))
110
119
 
111
120
  return None
112
121
 
113
- @step
122
+ @step(num_workers=3)
114
123
  async def sub_question(self, ctx: Context, ev: QueryEvent) -> AnswerEvent:
115
124
  """
116
125
  Given a sub-question, return the answer to the sub-question, using the agent.
@@ -151,7 +160,6 @@ class SubQuestionQueryWorkflow(Workflow):
151
160
  Sub-questions and answers:
152
161
  {answers}
153
162
  """
154
-
155
163
  if await ctx.get("verbose"):
156
164
  print(f"Final prompt is {prompt}")
157
165
 
@@ -163,3 +171,134 @@ class SubQuestionQueryWorkflow(Workflow):
163
171
 
164
172
  output = self.OutputsModel(response=str(response))
165
173
  return StopEvent(result=output)
174
+
175
+ class SequentialSubQuestionsWorkflow(Workflow):
176
+ """
177
+ Workflow for breaking a query into sequential sub-questions
178
+ """
179
+
180
+ # Workflow inputs/outputs
181
+ class InputsModel(BaseModel):
182
+ """
183
+ Inputs for the workflow.
184
+ """
185
+ query: str
186
+
187
+ class OutputsModel(BaseModel):
188
+ """
189
+ Outputs for the workflow.
190
+ """
191
+ response: str
192
+
193
+ # Workflow Event types
194
+ class QueryEvent(Event):
195
+ """Event for a query."""
196
+ question: str
197
+ prev_answer: str
198
+ num: int
199
+
200
+ @step
201
+ async def query(self, ctx: Context, ev: StartEvent) -> QueryEvent:
202
+ """
203
+ Given a user question, and a list of tools, output a list of relevant
204
+ sub-questions, such that each question depends on the response of the
205
+ previous question, to answer the original user question.
206
+ """
207
+ if not hasattr(ev, "inputs"):
208
+ raise ValueError("No inputs provided to workflow Start Event.")
209
+ if hasattr(ev, "inputs") and not isinstance(ev.inputs, self.InputsModel):
210
+ raise ValueError(f"Expected inputs to be of type {self.InputsModel}")
211
+ if hasattr(ev, "inputs"):
212
+ query = ev.inputs.query
213
+ await ctx.set("original_query", query)
214
+
215
+ if hasattr(ev, "agent"):
216
+ await ctx.set("agent", ev.agent)
217
+ else:
218
+ raise ValueError("Agent not provided to workflow Start Event.")
219
+ chat_history = [str(msg) for msg in ev.agent.memory.get()]
220
+
221
+ if hasattr(ev, "llm"):
222
+ await ctx.set("llm", ev.llm)
223
+ else:
224
+ raise ValueError("LLM not provided to workflow Start Event.")
225
+
226
+ if hasattr(ev, "tools"):
227
+ await ctx.set("tools", ev.tools)
228
+ else:
229
+ raise ValueError("Tools not provided to workflow Start Event.")
230
+
231
+ if hasattr(ev, "verbose"):
232
+ await ctx.set("verbose", ev.verbose)
233
+ else:
234
+ await ctx.set("verbose", False)
235
+ if ev.verbose:
236
+ print(f"Query is {await ctx.get('original_query')}")
237
+
238
+ llm = await ctx.get("llm")
239
+ response = llm.complete(
240
+ f"""
241
+ Given a user question, and a list of tools, output a list of
242
+ relevant sequential sub-questions, such that the answers to all the
243
+ sub-questions in sequence will answer the question, and the output
244
+ of each question can be used as input to the subsequent question.
245
+ Respond in pure JSON without any markdown, like this:
246
+ {{
247
+ "sub_questions": [
248
+ "What is the population of San Francisco?",
249
+ "Is that population larger than the population of San Jose?",
250
+ ]
251
+ }}
252
+ As an example, for the question
253
+ "what is the name of the mayor of the largest city within 50 miles of San Francisco?",
254
+ the sub-questions could be:
255
+ - What is the largest city within 50 miles of San Francisco?
256
+ - Who is the mayor of this city?
257
+ The answer to the first question is San Jose, which is given as context to the second question.
258
+ The answer to the second question is Matt Mahan.
259
+ Here is the user question: {await ctx.get('original_query')}.
260
+ Here are previous chat messages: {chat_history}.
261
+ And here is the list of tools: {await ctx.get('tools')}
262
+ """,
263
+ )
264
+
265
+ response_obj = json.loads(str(response))
266
+ sub_questions = response_obj["sub_questions"]
267
+
268
+ await ctx.set("sub_questions", sub_questions)
269
+ if await ctx.get("verbose"):
270
+ print(f"Sub-questions are {sub_questions}")
271
+
272
+ return self.QueryEvent(question=sub_questions[0], prev_answer="", num=0)
273
+
274
+ @step
275
+ async def sub_question(self, ctx: Context, ev: QueryEvent) -> StopEvent | QueryEvent:
276
+ """
277
+ Given a sub-question, return the answer to the sub-question, using the agent.
278
+ """
279
+ if await ctx.get("verbose"):
280
+ print(f"Sub-question is {ev.question}")
281
+ agent = await ctx.get("agent")
282
+ sub_questions = await ctx.get("sub_questions")
283
+ if ev.prev_answer:
284
+ prev_question = sub_questions[ev.num - 1]
285
+ prompt = f"""
286
+ The answer to the question '{prev_question}' is: '{ev.prev_answer}'
287
+ Now answer the following question: '{ev.question}'
288
+ """
289
+ response = await agent.achat(prompt)
290
+ else:
291
+ response = await agent.achat(ev.question)
292
+ if await ctx.get("verbose"):
293
+ print(f"Answer is {response}")
294
+
295
+ sub_questions = await ctx.get("sub_questions")
296
+ if ev.num + 1 < len(sub_questions):
297
+ return self.QueryEvent(
298
+ question=sub_questions[ev.num + 1],
299
+ prev_answer = response.response,
300
+ num=ev.num + 1
301
+ )
302
+
303
+ output = self.OutputsModel(response=response.response)
304
+ return StopEvent(result=output)
vectara_agentic/tools.py CHANGED
@@ -8,7 +8,7 @@ import importlib
8
8
  import os
9
9
 
10
10
  from typing import Callable, List, Dict, Any, Optional, Union, Type
11
- from pydantic import BaseModel, Field
11
+ from pydantic import BaseModel, Field, create_model
12
12
  from pydantic_core import PydanticUndefined
13
13
 
14
14
  from llama_index.core.tools import FunctionTool
@@ -21,7 +21,7 @@ from llama_index.core.workflow.context import Context
21
21
  from .types import ToolType
22
22
  from .tools_catalog import ToolsCatalog, get_bad_topics
23
23
  from .db_tools import DBLoadSampleData, DBLoadUniqueValues, DBLoadData
24
- from .utils import is_float
24
+ from .utils import is_float, summarize_vectara_document
25
25
  from .agent_config import AgentConfig
26
26
 
27
27
  LI_packages = {
@@ -74,6 +74,7 @@ class VectaraToolMetadata(ToolMetadata):
74
74
  base_repr = super().__repr__()
75
75
  return f"{base_repr}, tool_type={self.tool_type}"
76
76
 
77
+
77
78
  class VectaraTool(FunctionTool):
78
79
  """
79
80
  A subclass of FunctionTool adding the tool_type attribute.
@@ -161,7 +162,7 @@ class VectaraTool(FunctionTool):
161
162
  self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
162
163
  ) -> ToolOutput:
163
164
  try:
164
- return super().call(*args, ctx=ctx, **kwargs)
165
+ return await super().acall(*args, ctx=ctx, **kwargs)
165
166
  except Exception as e:
166
167
  err_output = ToolOutput(
167
168
  tool_name=self.metadata.name,
@@ -171,6 +172,65 @@ class VectaraTool(FunctionTool):
171
172
  )
172
173
  return err_output
173
174
 
175
+ def _create_tool_from_dynamic_function(
176
+ function: Callable[..., ToolOutput],
177
+ tool_name: str,
178
+ tool_description: str,
179
+ base_params: list[inspect.Parameter],
180
+ tool_args_schema: type[BaseModel],
181
+ ) -> VectaraTool:
182
+ """
183
+ Create a VectaraTool from a dynamic function, including
184
+ setting the function signature and creating the tool schema.
185
+ """
186
+ fields = {}
187
+ for param in base_params:
188
+ default_value = param.default if param.default != inspect.Parameter.empty else ...
189
+ fields[param.name] = (param.annotation, default_value)
190
+ for field_name, field_info in tool_args_schema.model_fields.items():
191
+ if field_name not in fields:
192
+ default_value = field_info.default if field_info.default is not PydanticUndefined else ...
193
+ fields[field_name] = (field_info.annotation, default_value)
194
+ fn_schema = create_model(f"{tool_name}", **fields)
195
+
196
+ schema_params = [
197
+ inspect.Parameter(
198
+ name=field_name,
199
+ kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
200
+ default=field_info.default if field_info.default is not PydanticUndefined else inspect.Parameter.empty,
201
+ annotation=field_info.annotation if hasattr(field_info, 'annotation') else field_info,
202
+ )
203
+ for field_name, field_info in tool_args_schema.model_fields.items()
204
+ if field_name not in [p.name for p in base_params]
205
+ ]
206
+ all_params = base_params + schema_params
207
+
208
+ required_params = [p for p in all_params if p.default is inspect.Parameter.empty]
209
+ optional_params = [p for p in all_params if p.default is not inspect.Parameter.empty]
210
+ sig = inspect.Signature(required_params + optional_params)
211
+ function.__signature__ = sig
212
+ function.__annotations__["return"] = dict[str, Any]
213
+ function.__name__ = "_" + re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
214
+
215
+ # Create the tool function signature string
216
+ param_strs = []
217
+ for param in all_params:
218
+ annotation = param.annotation
219
+ type_name = annotation.__name__ if hasattr(annotation, '__name__') else str(annotation)
220
+ param_strs.append(f"{param.name}: {type_name}")
221
+ args_str = ", ".join(param_strs)
222
+ function_str = f"{tool_name}({args_str}) -> str"
223
+
224
+ # Create the tool
225
+ tool = VectaraTool.from_defaults(
226
+ fn=function,
227
+ name=tool_name,
228
+ description=function_str + "\n" + tool_description,
229
+ fn_schema=fn_schema,
230
+ tool_type=ToolType.QUERY,
231
+ )
232
+ return tool
233
+
174
234
  def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict], fixed_filter: str) -> str:
175
235
  """
176
236
  Build filter string for Vectara from kwargs
@@ -196,7 +256,7 @@ def _build_filter_string(kwargs: Dict[str, Any], tool_args_type: Dict[str, dict]
196
256
 
197
257
  if value is PydanticUndefined:
198
258
  raise ValueError(
199
- f"Value of argument {key} is undefined, and this is invalid. "
259
+ f"Value of argument {key} is undefined, and this is invalid."
200
260
  "Please form proper arguments and try again."
201
261
  )
202
262
 
@@ -320,6 +380,8 @@ class VectaraToolFactory:
320
380
  self.vectara_corpus_key = vectara_corpus_key
321
381
  self.vectara_api_key = vectara_api_key
322
382
  self.num_corpora = len(vectara_corpus_key.split(","))
383
+ self.cache_expiry = 60 * 60 # 1 hour
384
+ self.max_cache_size = 128
323
385
 
324
386
  def create_search_tool(
325
387
  self,
@@ -392,7 +454,7 @@ class VectaraToolFactory:
392
454
  )
393
455
 
394
456
  # Dynamically generate the search function
395
- def search_function(*args, **kwargs) -> ToolOutput:
457
+ def search_function(*args: Any, **kwargs: Any) -> ToolOutput:
396
458
  """
397
459
  Dynamically generated function for semantic search Vectara.
398
460
  """
@@ -404,6 +466,7 @@ class VectaraToolFactory:
404
466
 
405
467
  query = kwargs.pop("query")
406
468
  top_k = kwargs.pop("top_k", 10)
469
+ summarize = kwargs.pop("summarize", True)
407
470
  try:
408
471
  filter_string = _build_filter_string(kwargs, tool_args_type, fixed_filter)
409
472
  except ValueError as e:
@@ -451,7 +514,11 @@ class VectaraToolFactory:
451
514
  if doc.id_ in unique_ids:
452
515
  continue
453
516
  unique_ids.add(doc.id_)
454
- tool_output += f"document_id: '{doc.id_}'\nmetadata: '{doc.metadata}'\n"
517
+ if summarize:
518
+ summary = summarize_vectara_document(self.vectara_corpus_key, self.vectara_api_key, doc.id_)
519
+ tool_output += f"document_id: '{doc.id_}'\nmetadata: '{doc.metadata}'\nsummary: '{summary}'\n\n"
520
+ else:
521
+ tool_output += f"document_id: '{doc.id_}'\nmetadata: '{doc.metadata}'\n\n"
455
522
  out = ToolOutput(
456
523
  tool_name=search_function.__name__,
457
524
  content=tool_output,
@@ -460,42 +527,22 @@ class VectaraToolFactory:
460
527
  )
461
528
  return out
462
529
 
463
- fields = tool_args_schema.model_fields
464
- params = [
465
- inspect.Parameter(
466
- name=field_name,
467
- kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
468
- default=field_info.default,
469
- annotation=field_info,
470
- )
471
- for field_name, field_info in fields.items()
530
+ base_params = [
531
+ inspect.Parameter("query", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
532
+ inspect.Parameter("top_k", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=10, annotation=int),
533
+ inspect.Parameter("summarize", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=True, annotation=bool),
472
534
  ]
473
-
474
- # Create a new signature using the extracted parameters
475
- sig = inspect.Signature(params)
476
- search_function.__signature__ = sig
477
- search_function.__annotations__["return"] = dict[str, Any]
478
- search_function.__name__ = "_" + re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
479
-
480
- # Create the tool function signature string
481
- fields = []
482
- for name, field in tool_args_schema.model_fields.items():
483
- annotation = field.annotation
484
- type_name = annotation.__name__ if hasattr(annotation, '__name__') else str(annotation)
485
- fields.append(f"{name}: {type_name}")
486
- args_str = ", ".join(fields)
487
- function_str = f"{tool_name}({args_str}) -> str"
488
-
489
- # Create the tool
490
- search_tool_extra_desc = """
491
- The response includes metadata about each relevant document, but NOT the text itself.
535
+ search_tool_extra_desc = tool_description + "\n" + """
536
+ The response includes metadata about each relevant document.
537
+ If summarize=True, it also includes a summary of each document.
492
538
  """
493
- tool = VectaraTool.from_defaults(
494
- fn=search_function,
495
- name=tool_name,
496
- description=function_str + "\n" + tool_description + '\n' + search_tool_extra_desc,
497
- fn_schema=tool_args_schema,
498
- tool_type=ToolType.QUERY,
539
+
540
+ tool = _create_tool_from_dynamic_function(
541
+ search_function,
542
+ tool_name,
543
+ search_tool_extra_desc,
544
+ base_params,
545
+ tool_args_schema,
499
546
  )
500
547
  return tool
501
548
 
@@ -595,11 +642,11 @@ class VectaraToolFactory:
595
642
  vectara_corpus_key=self.vectara_corpus_key,
596
643
  x_source_str="vectara-agentic",
597
644
  vectara_base_url=vectara_base_url,
598
- vetara_verify_ssl=vectara_verify_ssl,
645
+ vectara_verify_ssl=vectara_verify_ssl,
599
646
  )
600
647
 
601
648
  # Dynamically generate the RAG function
602
- def rag_function(*args, **kwargs) -> ToolOutput:
649
+ def rag_function(*args: Any, **kwargs: Any) -> ToolOutput:
603
650
  """
604
651
  Dynamically generated function for RAG query with Vectara.
605
652
  """
@@ -719,39 +766,15 @@ class VectaraToolFactory:
719
766
  )
720
767
  return out
721
768
 
722
- fields = tool_args_schema.model_fields
723
- params = [
724
- inspect.Parameter(
725
- name=field_name,
726
- kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
727
- default=field_info.default,
728
- annotation=field_info,
729
- )
730
- for field_name, field_info in fields.items()
769
+ base_params = [
770
+ inspect.Parameter("query", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
731
771
  ]
732
-
733
- # Create a new signature using the extracted parameters
734
- sig = inspect.Signature(params)
735
- rag_function.__signature__ = sig
736
- rag_function.__annotations__["return"] = dict[str, Any]
737
- rag_function.__name__ = "_" + re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
738
-
739
- # Create the tool function signature string
740
- fields = []
741
- for name, field in tool_args_schema.model_fields.items():
742
- annotation = field.annotation
743
- type_name = annotation.__name__ if hasattr(annotation, '__name__') else str(annotation)
744
- fields.append(f"{name}: {type_name}")
745
- args_str = ", ".join(fields)
746
- function_str = f"{tool_name}({args_str}) -> str"
747
-
748
- # Create the tool
749
- tool = VectaraTool.from_defaults(
750
- fn=rag_function,
751
- name=tool_name,
752
- description=function_str + ". " + tool_description,
753
- fn_schema=tool_args_schema,
754
- tool_type=ToolType.QUERY,
772
+ tool = _create_tool_from_dynamic_function(
773
+ rag_function,
774
+ tool_name,
775
+ tool_description,
776
+ base_params,
777
+ tool_args_schema,
755
778
  )
756
779
  return tool
757
780
 
vectara_agentic/types.py CHANGED
@@ -12,6 +12,7 @@ class AgentType(Enum):
12
12
 
13
13
  REACT = "REACT"
14
14
  OPENAI = "OPENAI"
15
+ FUNCTION_CALLING = "FUNCTION_CALLING"
15
16
  LLMCOMPILER = "LLMCOMPILER"
16
17
  LATS = "LATS"
17
18
 
@@ -57,6 +58,11 @@ class ToolType(Enum):
57
58
  QUERY = "query"
58
59
  ACTION = "action"
59
60
 
61
+ class AgentConfigType(Enum):
62
+ """Enumeration for different types of agent configurations."""
63
+ DEFAULT = "default"
64
+ FALLBACK = "fallback"
65
+
60
66
 
61
67
  # classes for Agent responses
62
68
  ToolOutput = LI_ToolOutput
vectara_agentic/utils.py CHANGED
@@ -5,6 +5,8 @@ Utilities for the Vectara agentic.
5
5
  from typing import Tuple, Callable, Optional
6
6
  from functools import lru_cache
7
7
  from inspect import signature
8
+ import json
9
+ import requests
8
10
 
9
11
  import tiktoken
10
12
 
@@ -17,13 +19,13 @@ from .agent_config import AgentConfig
17
19
 
18
20
  provider_to_default_model_name = {
19
21
  ModelProvider.OPENAI: "gpt-4o",
20
- ModelProvider.ANTHROPIC: "claude-3-5-sonnet-20241022",
22
+ ModelProvider.ANTHROPIC: "claude-3-7-sonnet-20250219",
21
23
  ModelProvider.TOGETHER: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
22
24
  ModelProvider.GROQ: "llama-3.3-70b-versatile",
23
25
  ModelProvider.FIREWORKS: "accounts/fireworks/models/firefunction-v2",
24
26
  ModelProvider.BEDROCK: "anthropic.claude-3-5-sonnet-20241022-v2:0",
25
27
  ModelProvider.COHERE: "command-r-plus",
26
- ModelProvider.GEMINI: "models/gemini-1.5-flash",
28
+ ModelProvider.GEMINI: "models/gemini-2.0-flash",
27
29
  }
28
30
 
29
31
  DEFAULT_MODEL_PROVIDER = ModelProvider.OPENAI
@@ -90,35 +92,50 @@ def get_llm(
90
92
  Get the LLM for the specified role, using the provided config
91
93
  or a default if none is provided.
92
94
  """
95
+ max_tokens = 8192
93
96
  model_provider, model_name = _get_llm_params_for_role(role, config)
94
97
  if model_provider == ModelProvider.OPENAI:
95
98
  llm = OpenAI(model=model_name, temperature=0,
96
99
  is_function_calling_model=True,
97
- strict=True)
100
+ strict=True,
101
+ max_tokens=max_tokens
102
+ )
98
103
  elif model_provider == ModelProvider.ANTHROPIC:
99
- llm = Anthropic(model=model_name, temperature=0)
104
+ llm = Anthropic(model=model_name, temperature=0, max_tokens=max_tokens)
100
105
  elif model_provider == ModelProvider.GEMINI:
101
106
  from llama_index.llms.gemini import Gemini
102
- llm = Gemini(model=model_name, temperature=0, is_function_calling_model=True)
107
+ llm = Gemini(
108
+ model=model_name, temperature=0,
109
+ is_function_calling_model=True,
110
+ max_tokens=max_tokens
111
+ )
103
112
  elif model_provider == ModelProvider.TOGETHER:
104
113
  from llama_index.llms.together import TogetherLLM
105
- llm = TogetherLLM(model=model_name, temperature=0, is_function_calling_model=True)
114
+ llm = TogetherLLM(
115
+ model=model_name, temperature=0,
116
+ is_function_calling_model=True,
117
+ max_tokens=max_tokens
118
+ )
106
119
  elif model_provider == ModelProvider.GROQ:
107
120
  from llama_index.llms.groq import Groq
108
- llm = Groq(model=model_name, temperature=0, is_function_calling_model=True)
121
+ llm = Groq(
122
+ model=model_name, temperature=0,
123
+ is_function_calling_model=True, max_tokens=max_tokens
124
+ )
109
125
  elif model_provider == ModelProvider.FIREWORKS:
110
126
  from llama_index.llms.fireworks import Fireworks
111
- llm = Fireworks(model=model_name, temperature=0)
127
+ llm = Fireworks(model=model_name, temperature=0, max_tokens=max_tokens)
112
128
  elif model_provider == ModelProvider.BEDROCK:
113
129
  from llama_index.llms.bedrock import Bedrock
114
- llm = Bedrock(model=model_name, temperature=0)
130
+ llm = Bedrock(model=model_name, temperature=0, max_tokens=max_tokens)
115
131
  elif model_provider == ModelProvider.COHERE:
116
132
  from llama_index.llms.cohere import Cohere
117
- llm = Cohere(model=model_name, temperature=0)
133
+ llm = Cohere(model=model_name, temperature=0, max_tokens=max_tokens)
118
134
  elif model_provider == ModelProvider.PRIVATE:
119
135
  from llama_index.llms.openai_like import OpenAILike
120
136
  llm = OpenAILike(model=model_name, temperature=0, is_function_calling_model=True,is_chat_model=True,
121
- api_base=config.private_llm_api_base, api_key=config.private_llm_api_key)
137
+ api_base=config.private_llm_api_base, api_key=config.private_llm_api_key,
138
+ max_tokens=max_tokens)
122
139
  else:
123
140
  raise ValueError(f"Unknown LLM provider: {model_provider}")
124
141
  return llm
@@ -141,3 +158,25 @@ def remove_self_from_signature(func):
141
158
  new_sig = sig.replace(parameters=params)
142
159
  func.__signature__ = new_sig
143
160
  return func
161
+
162
+ def summarize_vectara_document(corpus_key: str, vectara_api_key, doc_id: str) -> str:
163
+ """
164
+ Summarize a document in a Vectara corpus using the Vectara API.
165
+ """
166
+ url = f"https://api.vectara.io/v2/corpora/{corpus_key}/documents/{doc_id}/summarize"
167
+
168
+ payload = json.dumps({
169
+ "llm_name": "gpt-4o",
170
+ "model_parameters": {},
171
+ "stream_response": False
172
+ })
173
+ headers = {
174
+ 'Content-Type': 'application/json',
175
+ 'Accept': 'application/json',
176
+ 'x-api-key': vectara_api_key
177
+ }
178
+
179
+ response = requests.request("POST", url, headers=headers, data=payload, timeout=60)
180
+ if response.status_code != 200:
181
+ return f"Vectara Summarization failed with error code {response.status_code}, error={response.text}"
182
+ return json.loads(response.text)["summary"]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: vectara_agentic
3
- Version: 0.2.5
3
+ Version: 0.2.7
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
@@ -41,18 +41,18 @@ Requires-Dist: llama-index-tools-exa==0.3.0
41
41
  Requires-Dist: tavily-python==0.5.1
42
42
  Requires-Dist: exa-py==1.8.9
43
43
  Requires-Dist: yahoo-finance==1.4.0
44
- Requires-Dist: openinference-instrumentation-llama-index==3.1.4
45
- Requires-Dist: opentelemetry-proto==1.26.0
46
- Requires-Dist: arize-phoenix==7.11.0
47
- Requires-Dist: arize-phoenix-otel==0.6.1
48
- Requires-Dist: protobuf==4.25.5
44
+ Requires-Dist: openinference-instrumentation-llama-index==3.3.3
45
+ Requires-Dist: opentelemetry-proto==1.31.0
46
+ Requires-Dist: arize-phoenix==8.14.1
47
+ Requires-Dist: arize-phoenix-otel==0.8.0
48
+ Requires-Dist: protobuf==5.29.3
49
49
  Requires-Dist: tokenizers>=0.20
50
- Requires-Dist: pydantic==2.10.3
50
+ Requires-Dist: pydantic==2.10.6
51
51
  Requires-Dist: retrying==1.3.4
52
52
  Requires-Dist: python-dotenv==1.0.1
53
53
  Requires-Dist: tiktoken==0.9.0
54
54
  Requires-Dist: cloudpickle>=3.1.1
55
- Requires-Dist: httpx==0.27.2
55
+ Requires-Dist: httpx==0.28.1
56
56
  Dynamic: author
57
57
  Dynamic: author-email
58
58
  Dynamic: classifier
@@ -60,6 +60,7 @@ Dynamic: description
60
60
  Dynamic: description-content-type
61
61
  Dynamic: home-page
62
62
  Dynamic: keywords
63
+ Dynamic: license-file
63
64
  Dynamic: project-url
64
65
  Dynamic: requires-dist
65
66
  Dynamic: requires-python
@@ -0,0 +1,28 @@
1
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ tests/endpoint.py,sha256=frnpdZQpnuQNNKNYgAn2rFTarNG8MCJaNA77Bw_W22A,1420
3
+ tests/test_agent.py,sha256=CU7Zdb1J5kFjrkkIeDr70W1wsikYuOvoYKGYpg4EPxM,6678
4
+ tests/test_agent_planning.py,sha256=_mj73TNP9yUjkUJ-X31r-cQYreJ4qatXOtMrRvVpF4Y,2411
5
+ tests/test_agent_type.py,sha256=JM0Q2GBGHSADoBacz_DW551zWSfbpf7qa8xXqtyWsc4,5671
6
+ tests/test_fallback.py,sha256=M5YD7NHZ0joVU1frYIr9_OiRAIje5mrXrYVcekzlyGs,2829
7
+ tests/test_private_llm.py,sha256=CY-_rCpxGUuxnZ3ypkodw5Jj-sJCNdh6rLbCvULwuJI,2247
8
+ tests/test_tools.py,sha256=IVKn0HoS2erTCr1mOEGzTkktiY0PCfKNvqnD_pizjOg,3977
9
+ tests/test_workflow.py,sha256=lVyrVHdRO5leYNbYtHTmKqMX0c8_xehCpUA7cXQKVsc,2175
10
+ vectara_agentic/__init__.py,sha256=2GLDS3U6KckK-dBRl9v_x1kSV507gEhjOfuMmmu0Qxg,850
11
+ vectara_agentic/_callback.py,sha256=5PfqjLmuaZIR6dnqmhniTD_zwCgfi7kOu-nexb6Kss4,9688
12
+ vectara_agentic/_observability.py,sha256=fTL3KW0jQU-_JSpFgjO6-XzgDut_oiq9kt4QR-FkSqU,3804
13
+ vectara_agentic/_prompts.py,sha256=LYyiOAiC8imz3U7MSJiuCYAP39afsp7ycXY7-9biyJI,9314
14
+ vectara_agentic/_version.py,sha256=FGUM5lA5uZpmWWB52dt2AMCqWcU0M9b-2BB-raX-EN4,65
15
+ vectara_agentic/agent.py,sha256=nbBl66n56kjEZX4Zconb9IZjESzpjBZIEQdL4uLfurI,43333
16
+ vectara_agentic/agent_config.py,sha256=y1hSvU5ns0cE2R7BqF65LFstixF1ytJcoVgicGXo7w0,3691
17
+ vectara_agentic/agent_endpoint.py,sha256=QIMejCLlpW2qzXxeDAxv3anF46XMDdVMdKGWhJh3azY,1996
18
+ vectara_agentic/db_tools.py,sha256=VUdcjDFPwauFd2A92mXNYZnCjeMiTzcTka7S5At_3oQ,3595
19
+ vectara_agentic/sub_query_workflow.py,sha256=eS1S7l5PdyLPLZqxUJSR0oM2kvHb4raPGHk8t8td9sc,10939
20
+ vectara_agentic/tools.py,sha256=RpPGWiPHe-9ZiOxNz389W-gNWxegg7m4RlEx_pH9_W0,42881
21
+ vectara_agentic/tools_catalog.py,sha256=oiw3wAfbpFhh0_6rMvZsyPqWV6QIzHqhZCNzqRxuyV8,4818
22
+ vectara_agentic/types.py,sha256=HcS7vR8P2v2xQTlOc6ZFV2vvlr3OpzSNWhtcLMxqUZc,1792
23
+ vectara_agentic/utils.py,sha256=U4VWCyrvpXfPb9SJpd4Xj7rJCN-cZCNReNm9_uQjnlk,6759
24
+ vectara_agentic-0.2.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
25
+ vectara_agentic-0.2.7.dist-info/METADATA,sha256=z-IFDKlGmNh9QSIUV4xOOCYKF-PrTUnDukp8M5BNMe4,25046
26
+ vectara_agentic-0.2.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
27
+ vectara_agentic-0.2.7.dist-info/top_level.txt,sha256=Y7TQTFdOYGYodQRltUGRieZKIYuzeZj2kHqAUpfCUfg,22
28
+ vectara_agentic-0.2.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.1.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5