vectara-agentic 0.2.21__py3-none-any.whl → 0.2.23__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_type.py +5 -2
- tests/test_groq.py +13 -86
- tests/test_workflow.py +8 -35
- vectara_agentic/_prompts.py +1 -0
- vectara_agentic/_version.py +1 -1
- vectara_agentic/agent.py +33 -10
- vectara_agentic/llm_utils.py +52 -16
- vectara_agentic/sub_query_workflow.py +31 -9
- vectara_agentic/tools.py +2 -0
- {vectara_agentic-0.2.21.dist-info → vectara_agentic-0.2.23.dist-info}/METADATA +9 -1
- {vectara_agentic-0.2.21.dist-info → vectara_agentic-0.2.23.dist-info}/RECORD +14 -14
- {vectara_agentic-0.2.21.dist-info → vectara_agentic-0.2.23.dist-info}/WHEEL +0 -0
- {vectara_agentic-0.2.21.dist-info → vectara_agentic-0.2.23.dist-info}/licenses/LICENSE +0 -0
- {vectara_agentic-0.2.21.dist-info → vectara_agentic-0.2.23.dist-info}/top_level.txt +0 -0
tests/test_agent_type.py
CHANGED
|
@@ -19,10 +19,13 @@ react_config_anthropic = AgentConfig(
|
|
|
19
19
|
tool_llm_provider=ModelProvider.ANTHROPIC,
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
+
# React with Google does not work with Gemini 2.5-flash
|
|
22
23
|
react_config_gemini = AgentConfig(
|
|
23
24
|
agent_type=AgentType.REACT,
|
|
24
25
|
main_llm_provider=ModelProvider.GEMINI,
|
|
26
|
+
main_llm_model_name="models/gemini-2.0-flash",
|
|
25
27
|
tool_llm_provider=ModelProvider.GEMINI,
|
|
28
|
+
tool_llm_model_name="models/gemini-2.0-flash",
|
|
26
29
|
)
|
|
27
30
|
|
|
28
31
|
react_config_together = AgentConfig(
|
|
@@ -97,7 +100,7 @@ class TestAgentType(unittest.TestCase):
|
|
|
97
100
|
)
|
|
98
101
|
agent.chat("What is 5 times 10. Only give the answer, nothing else")
|
|
99
102
|
agent.chat("what is 3 times 7. Only give the answer, nothing else")
|
|
100
|
-
res = agent.chat("
|
|
103
|
+
res = agent.chat("what is the result of multiplying the results of the last two multiplications. Only give the answer, nothing else.")
|
|
101
104
|
self.assertIn("1050", res.response)
|
|
102
105
|
|
|
103
106
|
agent = Agent(
|
|
@@ -108,7 +111,7 @@ class TestAgentType(unittest.TestCase):
|
|
|
108
111
|
)
|
|
109
112
|
agent.chat("What is 5 times 10. Only give the answer, nothing else")
|
|
110
113
|
agent.chat("what is 3 times 7. Only give the answer, nothing else")
|
|
111
|
-
res = agent.chat("
|
|
114
|
+
res = agent.chat("what is the result of multiplying the results of the last two multiplications. Only give the answer, nothing else.")
|
|
112
115
|
self.assertIn("1050", res.response)
|
|
113
116
|
|
|
114
117
|
def test_together(self):
|
tests/test_groq.py
CHANGED
|
@@ -1,59 +1,18 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
|
|
3
|
-
from pydantic import Field, BaseModel
|
|
4
|
-
|
|
5
3
|
from vectara_agentic.agent import Agent, AgentType
|
|
6
4
|
from vectara_agentic.agent_config import AgentConfig
|
|
7
|
-
from vectara_agentic.tools import
|
|
5
|
+
from vectara_agentic.tools import ToolsFactory
|
|
8
6
|
from vectara_agentic.types import ModelProvider
|
|
9
7
|
|
|
10
|
-
|
|
11
8
|
import nest_asyncio
|
|
12
9
|
nest_asyncio.apply()
|
|
13
10
|
|
|
14
|
-
tickers = {
|
|
15
|
-
"C": "Citigroup",
|
|
16
|
-
"COF": "Capital One",
|
|
17
|
-
"JPM": "JPMorgan Chase",
|
|
18
|
-
"AAPL": "Apple Computer",
|
|
19
|
-
"GOOG": "Google",
|
|
20
|
-
"AMZN": "Amazon",
|
|
21
|
-
"SNOW": "Snowflake",
|
|
22
|
-
"TEAM": "Atlassian",
|
|
23
|
-
"TSLA": "Tesla",
|
|
24
|
-
"NVDA": "Nvidia",
|
|
25
|
-
"MSFT": "Microsoft",
|
|
26
|
-
"AMD": "Advanced Micro Devices",
|
|
27
|
-
"INTC": "Intel",
|
|
28
|
-
"NFLX": "Netflix",
|
|
29
|
-
"STT": "State Street",
|
|
30
|
-
"BK": "Bank of New York Mellon",
|
|
31
|
-
}
|
|
32
|
-
years = list(range(2015, 2025))
|
|
33
|
-
|
|
34
|
-
|
|
35
11
|
def mult(x: float, y: float) -> float:
|
|
36
12
|
"Multiply two numbers"
|
|
37
13
|
return x * y
|
|
38
14
|
|
|
39
15
|
|
|
40
|
-
def get_company_info() -> list[str]:
|
|
41
|
-
"""
|
|
42
|
-
Returns a dictionary of companies you can query about. Always check this before using any other tool.
|
|
43
|
-
The output is a dictionary of valid ticker symbols mapped to company names.
|
|
44
|
-
You can use this to identify the companies you can query about, and their ticker information.
|
|
45
|
-
"""
|
|
46
|
-
return tickers
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def get_valid_years() -> list[str]:
|
|
50
|
-
"""
|
|
51
|
-
Returns a list of the years for which financial reports are available.
|
|
52
|
-
Always check this before using any other tool.
|
|
53
|
-
"""
|
|
54
|
-
return years
|
|
55
|
-
|
|
56
|
-
|
|
57
16
|
fc_config_groq = AgentConfig(
|
|
58
17
|
agent_type=AgentType.FUNCTION_CALLING,
|
|
59
18
|
main_llm_provider=ModelProvider.GROQ,
|
|
@@ -63,53 +22,21 @@ fc_config_groq = AgentConfig(
|
|
|
63
22
|
|
|
64
23
|
class TestGROQ(unittest.TestCase):
|
|
65
24
|
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
vec_factory = VectaraToolFactory(vectara_corpus_key, vectara_api_key)
|
|
71
|
-
|
|
72
|
-
class QueryToolArgs(BaseModel):
|
|
73
|
-
arg1: str = Field(description="the first argument", examples=["val1"])
|
|
74
|
-
arg2: str = Field(description="the second argument", examples=["val2"])
|
|
75
|
-
arg3: str = Field(description="the third argument", examples=["val3"])
|
|
76
|
-
arg4: str = Field(description="the fourth argument", examples=["val4"])
|
|
77
|
-
arg5: str = Field(description="the fifth argument", examples=["val5"])
|
|
78
|
-
arg6: str = Field(description="the sixth argument", examples=["val6"])
|
|
79
|
-
arg7: str = Field(description="the seventh argument", examples=["val7"])
|
|
80
|
-
arg8: str = Field(description="the eighth argument", examples=["val8"])
|
|
81
|
-
arg9: str = Field(description="the ninth argument", examples=["val9"])
|
|
82
|
-
arg10: str = Field(description="the tenth argument", examples=["val10"])
|
|
83
|
-
arg11: str = Field(description="the eleventh argument", examples=["val11"])
|
|
84
|
-
arg12: str = Field(description="the twelfth argument", examples=["val12"])
|
|
85
|
-
arg13: str = Field(
|
|
86
|
-
description="the thirteenth argument", examples=["val13"]
|
|
87
|
-
)
|
|
88
|
-
arg14: str = Field(
|
|
89
|
-
description="the fourteenth argument", examples=["val14"]
|
|
90
|
-
)
|
|
91
|
-
arg15: str = Field(description="the fifteenth argument", examples=["val15"])
|
|
92
|
-
|
|
93
|
-
query_tool_1 = vec_factory.create_rag_tool(
|
|
94
|
-
tool_name="rag_tool",
|
|
95
|
-
tool_description="""
|
|
96
|
-
A dummy tool that takes 15 arguments and returns a response (str) to the user query based on the data in this corpus.
|
|
97
|
-
We are using this tool to test the tool factory works and does not crash with OpenAI.
|
|
98
|
-
""",
|
|
99
|
-
tool_args_schema=QueryToolArgs,
|
|
100
|
-
)
|
|
101
|
-
|
|
25
|
+
def test_multiturn(self):
|
|
26
|
+
tools = [ToolsFactory().create_tool(mult)]
|
|
27
|
+
topic = "AI topic"
|
|
28
|
+
instructions = "Always do as your father tells you, if your mother agrees!"
|
|
102
29
|
agent = Agent(
|
|
103
|
-
tools=
|
|
104
|
-
topic=
|
|
105
|
-
custom_instructions=
|
|
106
|
-
agent_config=fc_config_groq,
|
|
107
|
-
)
|
|
108
|
-
res = agent.chat("What is the stock price?")
|
|
109
|
-
self.assertTrue(
|
|
110
|
-
any(sub in str(res) for sub in ["I don't know", "I do not have", "please specify which company"])
|
|
30
|
+
tools=tools,
|
|
31
|
+
topic=topic,
|
|
32
|
+
custom_instructions=instructions,
|
|
111
33
|
)
|
|
112
34
|
|
|
35
|
+
agent.chat("What is 5 times 10. Only give the answer, nothing else")
|
|
36
|
+
agent.chat("what is 3 times 7. Only give the answer, nothing else")
|
|
37
|
+
res = agent.chat("multiply the results of the last two questions. Output only the answer.")
|
|
38
|
+
self.assertEqual(res.response, "1050")
|
|
39
|
+
|
|
113
40
|
|
|
114
41
|
if __name__ == "__main__":
|
|
115
42
|
unittest.main()
|
tests/test_workflow.py
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from llama_index.core.workflow import WorkflowTimeoutError
|
|
6
|
-
|
|
7
3
|
from vectara_agentic.agent import Agent
|
|
8
4
|
from vectara_agentic.agent_config import AgentConfig
|
|
9
5
|
from vectara_agentic.tools import ToolsFactory
|
|
@@ -68,7 +64,7 @@ class TestWorkflowPackage(unittest.IsolatedAsyncioTestCase):
|
|
|
68
64
|
|
|
69
65
|
class TestWorkflowFailure(unittest.IsolatedAsyncioTestCase):
|
|
70
66
|
|
|
71
|
-
async def
|
|
67
|
+
async def test_workflow_failure_sub_question(self):
|
|
72
68
|
tools = [ToolsFactory().create_tool(mult)] + [ToolsFactory().create_tool(add)]
|
|
73
69
|
topic = "AI topic"
|
|
74
70
|
instructions = "You are a helpful AI assistant."
|
|
@@ -84,50 +80,27 @@ class TestWorkflowFailure(unittest.IsolatedAsyncioTestCase):
|
|
|
84
80
|
inputs = SubQuestionQueryWorkflow.InputsModel(
|
|
85
81
|
query="Compute 5 times 3, then add 7 to the result."
|
|
86
82
|
)
|
|
83
|
+
res = await agent.run(inputs=inputs)
|
|
84
|
+
self.assertIsInstance(res, SubQuestionQueryWorkflow.OutputModelOnFail)
|
|
87
85
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
try:
|
|
91
|
-
res = await agent.run(inputs=inputs)
|
|
92
|
-
except Exception as e:
|
|
93
|
-
self.assertIsInstance(e, WorkflowTimeoutError)
|
|
94
|
-
|
|
95
|
-
self.assertIsNone(res)
|
|
96
|
-
|
|
97
|
-
async def test_workflow_with_fail_class(self):
|
|
86
|
+
async def test_workflow_failure_seq_sub_question(self):
|
|
98
87
|
tools = [ToolsFactory().create_tool(mult)] + [ToolsFactory().create_tool(add)]
|
|
99
88
|
topic = "AI topic"
|
|
100
89
|
instructions = "You are a helpful AI assistant."
|
|
101
|
-
|
|
102
|
-
class SubQuestionQueryWorkflowWithFailClass(SubQuestionQueryWorkflow):
|
|
103
|
-
class OutputModelOnFail(BaseModel):
|
|
104
|
-
"""
|
|
105
|
-
In case of failure, returns the user's original query
|
|
106
|
-
"""
|
|
107
|
-
original_query: str
|
|
108
|
-
|
|
109
90
|
agent = Agent(
|
|
110
91
|
tools=tools,
|
|
111
92
|
topic=topic,
|
|
112
93
|
custom_instructions=instructions,
|
|
113
94
|
agent_config = AgentConfig(),
|
|
114
|
-
workflow_cls =
|
|
95
|
+
workflow_cls = SequentialSubQuestionsWorkflow,
|
|
115
96
|
workflow_timeout = 1
|
|
116
97
|
)
|
|
117
98
|
|
|
118
|
-
inputs =
|
|
99
|
+
inputs = SequentialSubQuestionsWorkflow.InputsModel(
|
|
119
100
|
query="Compute 5 times 3, then add 7 to the result."
|
|
120
101
|
)
|
|
121
|
-
|
|
122
|
-
res
|
|
123
|
-
|
|
124
|
-
try:
|
|
125
|
-
res = await agent.run(inputs=inputs)
|
|
126
|
-
except Exception as e:
|
|
127
|
-
assert isinstance(e, WorkflowTimeoutError)
|
|
128
|
-
|
|
129
|
-
self.assertIsInstance(res, SubQuestionQueryWorkflowWithFailClass.OutputModelOnFail)
|
|
130
|
-
self.assertEqual(res.original_query, "Compute 5 times 3, then add 7 to the result.")
|
|
102
|
+
res = await agent.run(inputs=inputs)
|
|
103
|
+
self.assertIsInstance(res, SequentialSubQuestionsWorkflow.OutputModelOnFail)
|
|
131
104
|
|
|
132
105
|
|
|
133
106
|
if __name__ == "__main__":
|
vectara_agentic/_prompts.py
CHANGED
|
@@ -44,6 +44,7 @@ GENERAL_INSTRUCTIONS = """
|
|
|
44
44
|
- If you are provided with database tools use them for analytical queries (such as counting, calculating max, min, average, sum, or other statistics).
|
|
45
45
|
For each database, the database tools include: x_list_tables, x_load_data, x_describe_tables, x_load_unique_values, and x_load_sample_data, where 'x' in the database name.
|
|
46
46
|
for example, if the database name is "ev", the tools are: ev_list_tables, ev_load_data, ev_describe_tables, ev_load_unique_values, and ev_load_sample_data.
|
|
47
|
+
Use ANSI SQL-92 syntax for the SQL queries, and do not use any other SQL dialect.
|
|
47
48
|
Before using the x_load_data with a SQL query, always follow these discovery steps:
|
|
48
49
|
- call the x_list_tables tool to list of available tables in the x database.
|
|
49
50
|
- Call the x_describe_tables tool to understand the schema of each table you want to query data from.
|
vectara_agentic/_version.py
CHANGED
vectara_agentic/agent.py
CHANGED
|
@@ -15,6 +15,8 @@ from collections import Counter
|
|
|
15
15
|
import inspect
|
|
16
16
|
from inspect import Signature, Parameter, ismethod
|
|
17
17
|
from pydantic import Field, create_model, ValidationError, BaseModel
|
|
18
|
+
from pydantic_core import PydanticUndefined
|
|
19
|
+
|
|
18
20
|
import cloudpickle as pickle
|
|
19
21
|
|
|
20
22
|
from dotenv import load_dotenv
|
|
@@ -1083,6 +1085,15 @@ class Agent:
|
|
|
1083
1085
|
if not isinstance(inputs, self.workflow_cls.InputsModel):
|
|
1084
1086
|
raise ValueError(f"Inputs must be an instance of {workflow.InputsModel}.")
|
|
1085
1087
|
|
|
1088
|
+
outputs_model_on_fail_cls = getattr(workflow.__class__, "OutputModelOnFail", None)
|
|
1089
|
+
if outputs_model_on_fail_cls:
|
|
1090
|
+
fields_without_default = []
|
|
1091
|
+
for name, field_info in outputs_model_on_fail_cls.model_fields.items():
|
|
1092
|
+
if field_info.default_factory is PydanticUndefined:
|
|
1093
|
+
fields_without_default.append(name)
|
|
1094
|
+
if fields_without_default:
|
|
1095
|
+
raise ValueError(f"Fields without default values: {fields_without_default}")
|
|
1096
|
+
|
|
1086
1097
|
workflow_context = Context(workflow=workflow)
|
|
1087
1098
|
try:
|
|
1088
1099
|
# run workflow
|
|
@@ -1102,15 +1113,14 @@ class Agent:
|
|
|
1102
1113
|
raise ValueError(f"Failed to map workflow output to model: {e}") from e
|
|
1103
1114
|
|
|
1104
1115
|
except Exception as e:
|
|
1105
|
-
|
|
1116
|
+
_missing = object()
|
|
1106
1117
|
if outputs_model_on_fail_cls:
|
|
1107
1118
|
model_fields = outputs_model_on_fail_cls.model_fields
|
|
1108
|
-
input_dict = {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
# return output in the form of workflow.OutputModelOnFail(BaseModel)
|
|
1119
|
+
input_dict = {}
|
|
1120
|
+
for key in model_fields:
|
|
1121
|
+
value = await workflow_context.get(key, default=_missing)
|
|
1122
|
+
if value is not _missing:
|
|
1123
|
+
input_dict[key] = value
|
|
1114
1124
|
output = outputs_model_on_fail_cls.model_validate(input_dict)
|
|
1115
1125
|
else:
|
|
1116
1126
|
print(f"Vectara Agentic: Workflow failed with unexpected error: {e}")
|
|
@@ -1126,9 +1136,14 @@ class Agent:
|
|
|
1126
1136
|
return json.dumps(self.to_dict())
|
|
1127
1137
|
|
|
1128
1138
|
@classmethod
|
|
1129
|
-
def loads(
|
|
1139
|
+
def loads(
|
|
1140
|
+
cls,
|
|
1141
|
+
data: str,
|
|
1142
|
+
agent_progress_callback: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
1143
|
+
query_logging_callback: Optional[Callable[[str, str], None]] = None
|
|
1144
|
+
) -> "Agent":
|
|
1130
1145
|
"""Create an Agent instance from a JSON string."""
|
|
1131
|
-
return cls.from_dict(json.loads(data))
|
|
1146
|
+
return cls.from_dict(json.loads(data), agent_progress_callback, query_logging_callback)
|
|
1132
1147
|
|
|
1133
1148
|
def to_dict(self) -> Dict[str, Any]:
|
|
1134
1149
|
"""Serialize the Agent instance to a dictionary."""
|
|
@@ -1185,7 +1200,12 @@ class Agent:
|
|
|
1185
1200
|
}
|
|
1186
1201
|
|
|
1187
1202
|
@classmethod
|
|
1188
|
-
def from_dict(
|
|
1203
|
+
def from_dict(
|
|
1204
|
+
cls,
|
|
1205
|
+
data: Dict[str, Any],
|
|
1206
|
+
agent_progress_callback: Optional[Callable] = None,
|
|
1207
|
+
query_logging_callback: Optional[Callable] = None
|
|
1208
|
+
) -> "Agent":
|
|
1189
1209
|
"""Create an Agent instance from a dictionary."""
|
|
1190
1210
|
agent_config = AgentConfig.from_dict(data["agent_config"])
|
|
1191
1211
|
fallback_agent_config = (
|
|
@@ -1286,6 +1306,8 @@ class Agent:
|
|
|
1286
1306
|
verbose=data["verbose"],
|
|
1287
1307
|
fallback_agent_config=fallback_agent_config,
|
|
1288
1308
|
workflow_cls=data["workflow_cls"],
|
|
1309
|
+
agent_progress_callback=agent_progress_callback,
|
|
1310
|
+
query_logging_callback=query_logging_callback,
|
|
1289
1311
|
)
|
|
1290
1312
|
memory = (
|
|
1291
1313
|
pickle.loads(data["memory"].encode("latin-1"))
|
|
@@ -1294,4 +1316,5 @@ class Agent:
|
|
|
1294
1316
|
)
|
|
1295
1317
|
if memory:
|
|
1296
1318
|
agent.agent.memory = memory
|
|
1319
|
+
agent.memory = memory
|
|
1297
1320
|
return agent
|
vectara_agentic/llm_utils.py
CHANGED
|
@@ -11,18 +11,54 @@ from llama_index.core.llms import LLM
|
|
|
11
11
|
from llama_index.llms.openai import OpenAI
|
|
12
12
|
from llama_index.llms.anthropic import Anthropic
|
|
13
13
|
|
|
14
|
+
# Optional provider imports with graceful fallback
|
|
15
|
+
try:
|
|
16
|
+
from llama_index.llms.google_genai import GoogleGenAI
|
|
17
|
+
except ImportError:
|
|
18
|
+
GoogleGenAI = None
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from llama_index.llms.together import TogetherLLM
|
|
22
|
+
except ImportError:
|
|
23
|
+
TogetherLLM = None
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from llama_index.llms.groq import Groq
|
|
27
|
+
except ImportError:
|
|
28
|
+
Groq = None
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
from llama_index.llms.fireworks import Fireworks
|
|
32
|
+
except ImportError:
|
|
33
|
+
Fireworks = None
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
from llama_index.llms.bedrock_converse import BedrockConverse
|
|
37
|
+
except ImportError:
|
|
38
|
+
BedrockConverse = None
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
from llama_index.llms.cohere import Cohere
|
|
42
|
+
except ImportError:
|
|
43
|
+
Cohere = None
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
from llama_index.llms.openai_like import OpenAILike
|
|
47
|
+
except ImportError:
|
|
48
|
+
OpenAILike = None
|
|
49
|
+
|
|
14
50
|
from .types import LLMRole, AgentType, ModelProvider
|
|
15
51
|
from .agent_config import AgentConfig
|
|
16
52
|
|
|
17
53
|
provider_to_default_model_name = {
|
|
18
54
|
ModelProvider.OPENAI: "gpt-4.1",
|
|
19
55
|
ModelProvider.ANTHROPIC: "claude-sonnet-4-20250514",
|
|
20
|
-
ModelProvider.TOGETHER: "
|
|
56
|
+
ModelProvider.TOGETHER: "meta-llama/Llama-4-Scout-17B-16E-Instruct",
|
|
21
57
|
ModelProvider.GROQ: "deepseek-r1-distill-llama-70b",
|
|
22
58
|
ModelProvider.FIREWORKS: "accounts/fireworks/models/firefunction-v2",
|
|
23
59
|
ModelProvider.BEDROCK: "us.anthropic.claude-sonnet-4-20250514-v1:0",
|
|
24
60
|
ModelProvider.COHERE: "command-a-03-2025",
|
|
25
|
-
ModelProvider.GEMINI: "models/gemini-2.
|
|
61
|
+
ModelProvider.GEMINI: "models/gemini-2.5-flash",
|
|
26
62
|
}
|
|
27
63
|
|
|
28
64
|
DEFAULT_MODEL_PROVIDER = ModelProvider.OPENAI
|
|
@@ -106,8 +142,8 @@ def get_llm(role: LLMRole, config: Optional[AgentConfig] = None) -> LLM:
|
|
|
106
142
|
max_tokens=max_tokens,
|
|
107
143
|
)
|
|
108
144
|
elif model_provider == ModelProvider.GEMINI:
|
|
109
|
-
|
|
110
|
-
|
|
145
|
+
if GoogleGenAI is None:
|
|
146
|
+
raise ImportError("google_genai not available. Install with: pip install llama-index-llms-google-genai")
|
|
111
147
|
llm = GoogleGenAI(
|
|
112
148
|
model=model_name,
|
|
113
149
|
temperature=0,
|
|
@@ -116,8 +152,8 @@ def get_llm(role: LLMRole, config: Optional[AgentConfig] = None) -> LLM:
|
|
|
116
152
|
max_tokens=max_tokens,
|
|
117
153
|
)
|
|
118
154
|
elif model_provider == ModelProvider.TOGETHER:
|
|
119
|
-
|
|
120
|
-
|
|
155
|
+
if TogetherLLM is None:
|
|
156
|
+
raise ImportError("together not available. Install with: pip install llama-index-llms-together")
|
|
121
157
|
llm = TogetherLLM(
|
|
122
158
|
model=model_name,
|
|
123
159
|
temperature=0,
|
|
@@ -125,8 +161,8 @@ def get_llm(role: LLMRole, config: Optional[AgentConfig] = None) -> LLM:
|
|
|
125
161
|
max_tokens=max_tokens,
|
|
126
162
|
)
|
|
127
163
|
elif model_provider == ModelProvider.GROQ:
|
|
128
|
-
|
|
129
|
-
|
|
164
|
+
if Groq is None:
|
|
165
|
+
raise ImportError("groq not available. Install with: pip install llama-index-llms-groq")
|
|
130
166
|
llm = Groq(
|
|
131
167
|
model=model_name,
|
|
132
168
|
temperature=0,
|
|
@@ -134,12 +170,12 @@ def get_llm(role: LLMRole, config: Optional[AgentConfig] = None) -> LLM:
|
|
|
134
170
|
max_tokens=max_tokens,
|
|
135
171
|
)
|
|
136
172
|
elif model_provider == ModelProvider.FIREWORKS:
|
|
137
|
-
|
|
138
|
-
|
|
173
|
+
if Fireworks is None:
|
|
174
|
+
raise ImportError("fireworks not available. Install with: pip install llama-index-llms-fireworks")
|
|
139
175
|
llm = Fireworks(model=model_name, temperature=0, max_tokens=max_tokens)
|
|
140
176
|
elif model_provider == ModelProvider.BEDROCK:
|
|
141
|
-
|
|
142
|
-
|
|
177
|
+
if BedrockConverse is None:
|
|
178
|
+
raise ImportError("bedrock_converse not available. Install with: pip install llama-index-llms-bedrock")
|
|
143
179
|
aws_profile_name = os.getenv("AWS_PROFILE", None)
|
|
144
180
|
aws_region = os.getenv("AWS_REGION", "us-east-2")
|
|
145
181
|
|
|
@@ -151,12 +187,12 @@ def get_llm(role: LLMRole, config: Optional[AgentConfig] = None) -> LLM:
|
|
|
151
187
|
region_name=aws_region,
|
|
152
188
|
)
|
|
153
189
|
elif model_provider == ModelProvider.COHERE:
|
|
154
|
-
|
|
155
|
-
|
|
190
|
+
if Cohere is None:
|
|
191
|
+
raise ImportError("cohere not available. Install with: pip install llama-index-llms-cohere")
|
|
156
192
|
llm = Cohere(model=model_name, temperature=0, max_tokens=max_tokens)
|
|
157
193
|
elif model_provider == ModelProvider.PRIVATE:
|
|
158
|
-
|
|
159
|
-
|
|
194
|
+
if OpenAILike is None:
|
|
195
|
+
raise ImportError("openai_like not available. Install with: pip install llama-index-llms-openai-like")
|
|
160
196
|
llm = OpenAILike(
|
|
161
197
|
model=model_name,
|
|
162
198
|
temperature=0,
|
|
@@ -5,7 +5,7 @@ that takes a user question and a list of tools, and outputs a list of sub-questi
|
|
|
5
5
|
|
|
6
6
|
import re
|
|
7
7
|
import json
|
|
8
|
-
from pydantic import BaseModel
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
9
|
|
|
10
10
|
from llama_index.core.workflow import (
|
|
11
11
|
step,
|
|
@@ -37,6 +37,13 @@ class SubQuestionQueryWorkflow(Workflow):
|
|
|
37
37
|
|
|
38
38
|
response: str
|
|
39
39
|
|
|
40
|
+
class OutputModelOnFail(BaseModel):
|
|
41
|
+
"""
|
|
42
|
+
Outputs for the workflow when it fails.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
qna: list[tuple[str,str]] = Field(default_factory=list, description="List of question-answer pairs")
|
|
46
|
+
|
|
40
47
|
# Workflow Event types
|
|
41
48
|
class QueryEvent(Event):
|
|
42
49
|
"""Event for a query."""
|
|
@@ -141,7 +148,7 @@ class SubQuestionQueryWorkflow(Workflow):
|
|
|
141
148
|
|
|
142
149
|
return None
|
|
143
150
|
|
|
144
|
-
@step(num_workers=
|
|
151
|
+
@step(num_workers=8)
|
|
145
152
|
async def sub_question(self, ctx: Context, ev: QueryEvent) -> AnswerEvent:
|
|
146
153
|
"""
|
|
147
154
|
Given a sub-question, return the answer to the sub-question, using the agent.
|
|
@@ -149,8 +156,11 @@ class SubQuestionQueryWorkflow(Workflow):
|
|
|
149
156
|
if await ctx.get("verbose"):
|
|
150
157
|
print(f"Sub-question is {ev.question}")
|
|
151
158
|
agent = await ctx.get("agent")
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
question = ev.question
|
|
160
|
+
response = await agent.achat(question)
|
|
161
|
+
answer = str(response)
|
|
162
|
+
await ctx.set("qna", await ctx.get("qna", []) + [(question, answer)])
|
|
163
|
+
return self.AnswerEvent(question=question, answer=answer)
|
|
154
164
|
|
|
155
165
|
@step
|
|
156
166
|
async def combine_answers(self, ctx: Context, ev: AnswerEvent) -> StopEvent | None:
|
|
@@ -209,6 +219,15 @@ class SequentialSubQuestionsWorkflow(Workflow):
|
|
|
209
219
|
|
|
210
220
|
response: str
|
|
211
221
|
|
|
222
|
+
class OutputModelOnFail(BaseModel):
|
|
223
|
+
"""
|
|
224
|
+
Outputs for the workflow when it fails.
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
qna: list[tuple[str,str]] = Field(
|
|
228
|
+
default_factory=list, description="List of question-answer pairs"
|
|
229
|
+
)
|
|
230
|
+
|
|
212
231
|
# Workflow Event types
|
|
213
232
|
class QueryEvent(Event):
|
|
214
233
|
"""Event for a query."""
|
|
@@ -322,24 +341,27 @@ class SequentialSubQuestionsWorkflow(Workflow):
|
|
|
322
341
|
print(f"Sub-question is {ev.question}")
|
|
323
342
|
agent = await ctx.get("agent")
|
|
324
343
|
sub_questions = await ctx.get("sub_questions")
|
|
344
|
+
question = ev.question
|
|
325
345
|
if ev.prev_answer:
|
|
326
346
|
prev_question = sub_questions[ev.num - 1]
|
|
327
347
|
prompt = f"""
|
|
328
348
|
The answer to the question '{prev_question}' is: '{ev.prev_answer}'
|
|
329
|
-
Now answer the following question: '{
|
|
349
|
+
Now answer the following question: '{question}'
|
|
330
350
|
"""
|
|
331
351
|
response = await agent.achat(prompt)
|
|
332
352
|
else:
|
|
333
|
-
response = await agent.achat(
|
|
353
|
+
response = await agent.achat(question)
|
|
354
|
+
answer = response.response
|
|
334
355
|
if await ctx.get("verbose"):
|
|
335
|
-
print(f"Answer is {
|
|
356
|
+
print(f"Answer is {answer}")
|
|
336
357
|
|
|
337
358
|
if ev.num + 1 < len(sub_questions):
|
|
359
|
+
await ctx.set("qna", await ctx.get("qna", []) + [(question, answer)])
|
|
338
360
|
return self.QueryEvent(
|
|
339
361
|
question=sub_questions[ev.num + 1],
|
|
340
|
-
prev_answer=
|
|
362
|
+
prev_answer=answer,
|
|
341
363
|
num=ev.num + 1,
|
|
342
364
|
)
|
|
343
365
|
|
|
344
|
-
output = self.OutputsModel(response=
|
|
366
|
+
output = self.OutputsModel(response=answer)
|
|
345
367
|
return StopEvent(result=output)
|
vectara_agentic/tools.py
CHANGED
|
@@ -129,6 +129,8 @@ class VectaraToolFactory:
|
|
|
129
129
|
- 'type': the type of each filter attribute in Vectara (doc or part).
|
|
130
130
|
- 'is_list': whether the filterable attribute is a list.
|
|
131
131
|
- 'filter_name': the name of the filterable attribute in Vectara.
|
|
132
|
+
summarize_docs (bool, optional): Whether to summarize the retrieved documents.
|
|
133
|
+
summarize_llm_name (str, optional): The name of the LLM to use for summarization.
|
|
132
134
|
fixed_filter (str, optional): A fixed Vectara filter condition to apply to all queries.
|
|
133
135
|
lambda_val (Union[List[float] | float], optional): Lambda value (or list of values for each corpora)
|
|
134
136
|
for the Vectara query, when using hybrid search.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vectara_agentic
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.23
|
|
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
|
|
@@ -530,6 +530,9 @@ class MyWorkflow(Workflow):
|
|
|
530
530
|
class OutputsModel(BaseModel):
|
|
531
531
|
answer: str
|
|
532
532
|
|
|
533
|
+
class OutputModelOnFail(BaseModel):
|
|
534
|
+
partial_response: str = ""
|
|
535
|
+
|
|
533
536
|
@step
|
|
534
537
|
async def my_step(self, ev: StartEvent) -> StopEvent:
|
|
535
538
|
# do something here
|
|
@@ -587,6 +590,11 @@ workflow_result = asyncio.run(agent.run(inputs))
|
|
|
587
590
|
print(workflow_result.answer)
|
|
588
591
|
```
|
|
589
592
|
|
|
593
|
+
When a workflow reaches its timeout, the timeout handler builds and returns an `OutputModelOnFail`
|
|
594
|
+
by reading each field named in that model from the workflow’s Context; for any field that isn’t set in the context,
|
|
595
|
+
it uses the default value you’ve defined on `OutputModelOnFail`. In other words, every property in `OutputModelOnFail`
|
|
596
|
+
must declare a default so that even if the corresponding context variable is missing, the model can be fully populated and returned without errors.
|
|
597
|
+
|
|
590
598
|
### Built-in Workflows
|
|
591
599
|
|
|
592
600
|
`vectara-agentic` includes two workflow implementations that you can use right away:
|
|
@@ -2,36 +2,36 @@ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
2
2
|
tests/endpoint.py,sha256=frnpdZQpnuQNNKNYgAn2rFTarNG8MCJaNA77Bw_W22A,1420
|
|
3
3
|
tests/test_agent.py,sha256=BmpJrYN-BLwYasgPhY5Dji-kIpc723e2F6I-nj4EQgc,5510
|
|
4
4
|
tests/test_agent_planning.py,sha256=JwEebGooROAvsQ9JZoaH6KEcrSyv1F0lL4TD4FjP8a8,2213
|
|
5
|
-
tests/test_agent_type.py,sha256=
|
|
5
|
+
tests/test_agent_type.py,sha256=9ZImIDw7Qz5EV2tX8bDD0tT1IFYghS3-SShpAezHO7s,7381
|
|
6
6
|
tests/test_api_endpoint.py,sha256=M9YGFCy_Jphzq9JznP4ftHqxZ_yu6dgWdX1jRvdsORA,5002
|
|
7
7
|
tests/test_bedrock.py,sha256=23A5_2FRaEl47PzgfUPDL6dgFDPJ9iktz-A-B1UwIhg,1224
|
|
8
8
|
tests/test_fallback.py,sha256=M5YD7NHZ0joVU1frYIr9_OiRAIje5mrXrYVcekzlyGs,2829
|
|
9
9
|
tests/test_gemini.py,sha256=QUBYWhZkX9AjnhPn5qa7sREf6YHZWeJEmYzKwVC23Io,4081
|
|
10
|
-
tests/test_groq.py,sha256=
|
|
10
|
+
tests/test_groq.py,sha256=5yTlOLwpzGRmiBPExAuulK6SEO9O13cMJWVSSHX9CsE,1212
|
|
11
11
|
tests/test_private_llm.py,sha256=-bQBI69Z-SwhhQJGzyC9GGM4kz5c6T5kAbXLbqn_G7E,2248
|
|
12
12
|
tests/test_return_direct.py,sha256=Y_K_v88eS_kJfxE6A0Yghma0nUT8u6COitj0SNnZGNs,1523
|
|
13
13
|
tests/test_serialization.py,sha256=Ed23GN2zhSJNdPFrVK4aqLkOhJKviczR_o0t-r9TuRI,4762
|
|
14
14
|
tests/test_tools.py,sha256=j6wY-jqeerE4Q7lxzuxbftRyzPLHE1scWKNFLgX7wSk,17138
|
|
15
15
|
tests/test_vectara_llms.py,sha256=gw5KQ4XT3L-_A6yj2jKqj-QomCjOb9VESKBtBH2Xb8s,2362
|
|
16
|
-
tests/test_workflow.py,sha256=
|
|
16
|
+
tests/test_workflow.py,sha256=TmNBxBqSW5owk_Nz9LLtHvqryVNsFPkf-M1G_uFSsAM,3739
|
|
17
17
|
vectara_agentic/__init__.py,sha256=2GLDS3U6KckK-dBRl9v_x1kSV507gEhjOfuMmmu0Qxg,850
|
|
18
18
|
vectara_agentic/_callback.py,sha256=DMExGJPiZPowB0gL7Re_3406BHg75go1cgzetfGb-KQ,13074
|
|
19
19
|
vectara_agentic/_observability.py,sha256=iZlByeQTyx6g3Y8aBYcdGcxdRkoYrfxHdcrTEKO26UE,4485
|
|
20
|
-
vectara_agentic/_prompts.py,sha256=
|
|
21
|
-
vectara_agentic/_version.py,sha256=
|
|
22
|
-
vectara_agentic/agent.py,sha256=
|
|
20
|
+
vectara_agentic/_prompts.py,sha256=NbKloHQYc25IvtpxmPdRKHXIM-p-lAK-jyk41iafL60,10050
|
|
21
|
+
vectara_agentic/_version.py,sha256=_HryRNoBbJs5TpiuE6yWSRf90S1J6zt4RlW3hL6aslM,66
|
|
22
|
+
vectara_agentic/agent.py,sha256=M4hiHfrVBYIdknI5JMHezabF1QcM1jfHSCx2VXoVTQ4,55912
|
|
23
23
|
vectara_agentic/agent_config.py,sha256=E-rtYMcpoGxnEAyy8231bizo2n0uGQ2qWxuSgTEfwdQ,4327
|
|
24
24
|
vectara_agentic/agent_endpoint.py,sha256=PzIN7HhEHv8Mq_Zo5cZ2xYrgdv2AN6kx6dc_2AJq28I,7497
|
|
25
25
|
vectara_agentic/db_tools.py,sha256=Kfz6n-rSj5TQEbAiJnWGmqWtcwB0A5GpxD7d1UwGzlc,11194
|
|
26
|
-
vectara_agentic/llm_utils.py,sha256=
|
|
27
|
-
vectara_agentic/sub_query_workflow.py,sha256=
|
|
26
|
+
vectara_agentic/llm_utils.py,sha256=oYm2S_xBCacN6GmFr_ASMIKEtRy2z2EQ_qDBfgSpiWE,7247
|
|
27
|
+
vectara_agentic/sub_query_workflow.py,sha256=JYwN0wK4QzHjTaFDsSCAQvMx9GD4g6CnqxZCnzi6xb4,13086
|
|
28
28
|
vectara_agentic/tool_utils.py,sha256=FkwKY2IsMHXIb-uD-wef8vVB_eZKkReeb74CcXGo1cQ,19219
|
|
29
|
-
vectara_agentic/tools.py,sha256=
|
|
29
|
+
vectara_agentic/tools.py,sha256=JIHPk08obKtQ4s6bhVYyyi82U7X5WaxEOxju6L_eej8,33519
|
|
30
30
|
vectara_agentic/tools_catalog.py,sha256=cAN_kDOWZUoW4GNFwY5GdS6ImMUQNnF2sggx9OGK9Cg,4906
|
|
31
31
|
vectara_agentic/types.py,sha256=HcS7vR8P2v2xQTlOc6ZFV2vvlr3OpzSNWhtcLMxqUZc,1792
|
|
32
32
|
vectara_agentic/utils.py,sha256=R9HitEG5K3Q_p2M_teosT181OUxkhs1-hnj98qDYGbE,2545
|
|
33
|
-
vectara_agentic-0.2.
|
|
34
|
-
vectara_agentic-0.2.
|
|
35
|
-
vectara_agentic-0.2.
|
|
36
|
-
vectara_agentic-0.2.
|
|
37
|
-
vectara_agentic-0.2.
|
|
33
|
+
vectara_agentic-0.2.23.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
34
|
+
vectara_agentic-0.2.23.dist-info/METADATA,sha256=Hv56Z2BC5nxAT1YrMvr4iXQMUquXg8JYCsEQOXyHrzU,31127
|
|
35
|
+
vectara_agentic-0.2.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
vectara_agentic-0.2.23.dist-info/top_level.txt,sha256=Y7TQTFdOYGYodQRltUGRieZKIYuzeZj2kHqAUpfCUfg,22
|
|
37
|
+
vectara_agentic-0.2.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|