soprano-sdk 0.1.93__py3-none-any.whl → 0.1.95__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.
- soprano_sdk/__init__.py +10 -0
- soprano_sdk/agents/__init__.py +30 -0
- soprano_sdk/agents/adaptor.py +91 -0
- soprano_sdk/agents/factory.py +228 -0
- soprano_sdk/agents/structured_output.py +97 -0
- soprano_sdk/core/__init__.py +0 -0
- soprano_sdk/core/constants.py +59 -0
- soprano_sdk/core/engine.py +225 -0
- soprano_sdk/core/rollback_strategies.py +259 -0
- soprano_sdk/core/state.py +71 -0
- soprano_sdk/engine.py +381 -0
- soprano_sdk/nodes/__init__.py +0 -0
- soprano_sdk/nodes/base.py +57 -0
- soprano_sdk/nodes/call_function.py +108 -0
- soprano_sdk/nodes/collect_input.py +526 -0
- soprano_sdk/nodes/factory.py +46 -0
- soprano_sdk/routing/__init__.py +0 -0
- soprano_sdk/routing/router.py +97 -0
- soprano_sdk/tools.py +219 -0
- soprano_sdk/utils/__init__.py +0 -0
- soprano_sdk/utils/data.py +1 -0
- soprano_sdk/utils/function.py +35 -0
- soprano_sdk/utils/logger.py +6 -0
- soprano_sdk/utils/template.py +27 -0
- soprano_sdk/utils/tool.py +60 -0
- soprano_sdk/utils/tracing.py +71 -0
- soprano_sdk/validation/__init__.py +13 -0
- soprano_sdk/validation/schema.py +302 -0
- soprano_sdk/validation/validator.py +173 -0
- {soprano_sdk-0.1.93.dist-info → soprano_sdk-0.1.95.dist-info}/METADATA +1 -1
- soprano_sdk-0.1.95.dist-info/RECORD +33 -0
- soprano_sdk-0.1.93.dist-info/RECORD +0 -4
- {soprano_sdk-0.1.93.dist-info → soprano_sdk-0.1.95.dist-info}/WHEEL +0 -0
- {soprano_sdk-0.1.93.dist-info → soprano_sdk-0.1.95.dist-info}/licenses/LICENSE +0 -0
soprano_sdk/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Agent module for managing different agent frameworks."""
|
|
2
|
+
|
|
3
|
+
from .factory import (
|
|
4
|
+
AgentAdapter,
|
|
5
|
+
AgentCreator,
|
|
6
|
+
AgentFactory,
|
|
7
|
+
LangGraphAgentAdapter,
|
|
8
|
+
LangGraphAgentCreator,
|
|
9
|
+
CrewAIAgentAdapter,
|
|
10
|
+
CrewAIAgentCreator,
|
|
11
|
+
AgnoAgentAdapter,
|
|
12
|
+
AgnoAgentCreator,
|
|
13
|
+
PydanticAIAgentAdapter,
|
|
14
|
+
PydanticAIAgentCreator,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"AgentAdapter",
|
|
19
|
+
"AgentCreator",
|
|
20
|
+
"AgentFactory",
|
|
21
|
+
"LangGraphAgentAdapter",
|
|
22
|
+
"LangGraphAgentCreator",
|
|
23
|
+
"CrewAIAgentAdapter",
|
|
24
|
+
"CrewAIAgentCreator",
|
|
25
|
+
"AgnoAgentAdapter",
|
|
26
|
+
"AgnoAgentCreator",
|
|
27
|
+
"PydanticAIAgentAdapter",
|
|
28
|
+
"PydanticAIAgentCreator",
|
|
29
|
+
]
|
|
30
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Any, Dict, List
|
|
4
|
+
from langgraph.graph.state import CompiledStateGraph
|
|
5
|
+
from agno.agent import Agent as AgnoAgent
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
from pydantic_ai.agent import Agent as PydanticAIAgent
|
|
8
|
+
from crewai.agent import Agent as CrewAIAgent
|
|
9
|
+
from ..utils.logger import logger
|
|
10
|
+
|
|
11
|
+
class AgentAdapter(ABC):
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def invoke(self, messages: List[Dict[str, str]]) -> Dict[str, Any]:
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LangGraphAgentAdapter(AgentAdapter):
|
|
19
|
+
|
|
20
|
+
def __init__(self, agent: CompiledStateGraph):
|
|
21
|
+
self.agent = agent
|
|
22
|
+
|
|
23
|
+
def invoke(self, messages: List[Dict[str, str]]) -> Dict[str, Any]:
|
|
24
|
+
logger.info("Invoking LangGraph agent with messages")
|
|
25
|
+
response = self.agent.invoke({"messages": messages})
|
|
26
|
+
|
|
27
|
+
if structured_response := response.get('structured_response'):
|
|
28
|
+
return structured_response.model_dump()
|
|
29
|
+
|
|
30
|
+
if not response or "messages" not in response:
|
|
31
|
+
raise ValueError("Agent response missing 'messages'")
|
|
32
|
+
|
|
33
|
+
response_messages = response.get("messages")
|
|
34
|
+
if not response_messages:
|
|
35
|
+
raise ValueError("Agent response 'messages' list is empty")
|
|
36
|
+
|
|
37
|
+
return response_messages[-1].content
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class CrewAIAgentAdapter(AgentAdapter):
|
|
41
|
+
|
|
42
|
+
def __init__(self, agent: CrewAIAgent, output_schema: BaseModel):
|
|
43
|
+
self.agent = agent
|
|
44
|
+
self.output_schema=output_schema
|
|
45
|
+
|
|
46
|
+
def invoke(self, messages: List[Dict[str, str]]) -> Any:
|
|
47
|
+
try:
|
|
48
|
+
logger.info("Invoking LangGraph agent with messages")
|
|
49
|
+
result = self.agent.kickoff(messages, response_format=self.output_schema)
|
|
50
|
+
|
|
51
|
+
if structured_response := getattr(result, 'pydantic', None) :
|
|
52
|
+
return structured_response.model_dump()
|
|
53
|
+
|
|
54
|
+
if agent_response := getattr(result, 'raw', None) :
|
|
55
|
+
return agent_response
|
|
56
|
+
|
|
57
|
+
return str(result)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
raise RuntimeError(f"CrewAI agent invocation failed: {e}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class AgnoAgentAdapter(AgentAdapter):
|
|
63
|
+
|
|
64
|
+
def __init__(self, agent: AgnoAgent):
|
|
65
|
+
self.agent = agent
|
|
66
|
+
|
|
67
|
+
def invoke(self, messages: List[Dict[str, str]]) -> Dict[str, Any]:
|
|
68
|
+
try:
|
|
69
|
+
logger.info("Invoking LangGraph agent with messages")
|
|
70
|
+
response = self.agent.run(messages)
|
|
71
|
+
agent_response = response.content if hasattr(response, 'content') else str(response)
|
|
72
|
+
|
|
73
|
+
return agent_response
|
|
74
|
+
except Exception as e:
|
|
75
|
+
raise RuntimeError(f"Agno agent invocation failed: {e}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class PydanticAIAgentAdapter(AgentAdapter):
|
|
79
|
+
|
|
80
|
+
def __init__(self, agent: PydanticAIAgent):
|
|
81
|
+
self.agent = agent
|
|
82
|
+
|
|
83
|
+
def invoke(self, messages: List[Dict[str, str]]) -> Dict[str, Any]:
|
|
84
|
+
try:
|
|
85
|
+
logger.info("Invoking LangGraph agent with messages")
|
|
86
|
+
result = self.agent.run_sync(messages)
|
|
87
|
+
agent_response = result.output if hasattr(result, 'output') else str(result)
|
|
88
|
+
|
|
89
|
+
return agent_response
|
|
90
|
+
except Exception as e:
|
|
91
|
+
raise RuntimeError(f"Pydantic-AI agent invocation failed: {e}")
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, List, Literal, Tuple, Callable
|
|
3
|
+
|
|
4
|
+
from agno.models.openai import OpenAIChat
|
|
5
|
+
from crewai import LLM
|
|
6
|
+
from langchain_openai import ChatOpenAI
|
|
7
|
+
from pydantic import SecretStr, BaseModel
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from .adaptor import (
|
|
11
|
+
AgentAdapter,
|
|
12
|
+
LangGraphAgentAdapter,
|
|
13
|
+
CrewAIAgentAdapter,
|
|
14
|
+
AgnoAgentAdapter,
|
|
15
|
+
PydanticAIAgentAdapter
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_model(config: Dict[str, Any], framework: Literal['langgraph', 'crewai', 'agno', 'pydantic-ai'] = "langgraph", output_schema: Optional[BaseModel] = None, tools: Optional[List] = None):
|
|
20
|
+
errors = []
|
|
21
|
+
|
|
22
|
+
model_name: str = config.get("model_name", "")
|
|
23
|
+
if not model_name:
|
|
24
|
+
errors.append("Model name is required in model_config")
|
|
25
|
+
|
|
26
|
+
base_url = config.get("base_url")
|
|
27
|
+
if not base_url:
|
|
28
|
+
errors.append("Base url for model is required in model_config")
|
|
29
|
+
|
|
30
|
+
api_key = config.get("api_key", "")
|
|
31
|
+
if not api_key:
|
|
32
|
+
if auth_callback := config.get("auth_callback"):
|
|
33
|
+
api_key = auth_callback()
|
|
34
|
+
if not api_key:
|
|
35
|
+
errors.append("API key/Auth callback for model is required in model_config")
|
|
36
|
+
|
|
37
|
+
if errors:
|
|
38
|
+
raise ValueError("; ".join(errors))
|
|
39
|
+
|
|
40
|
+
if framework == "agno" :
|
|
41
|
+
return OpenAIChat(
|
|
42
|
+
id=model_name,
|
|
43
|
+
api_key=api_key,
|
|
44
|
+
base_url=base_url
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if framework == "crewai" :
|
|
48
|
+
return LLM(
|
|
49
|
+
api_key=api_key,
|
|
50
|
+
model=f"openai/{model_name}",
|
|
51
|
+
base_url=base_url,
|
|
52
|
+
temperature=0.1,
|
|
53
|
+
top_p=0.7
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
llm = ChatOpenAI(
|
|
57
|
+
model=model_name,
|
|
58
|
+
api_key=SecretStr(api_key),
|
|
59
|
+
base_url=base_url,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if output_schema:
|
|
63
|
+
return llm.with_structured_output(output_schema)
|
|
64
|
+
|
|
65
|
+
if tools:
|
|
66
|
+
llm = llm.bind_tools(tools)
|
|
67
|
+
|
|
68
|
+
return llm
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AgentCreator(ABC):
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def create_agent(
|
|
74
|
+
self,
|
|
75
|
+
name: str,
|
|
76
|
+
model_config: Dict[str, Any],
|
|
77
|
+
tools: List[Any],
|
|
78
|
+
system_prompt: str,
|
|
79
|
+
structured_output_model: Any = None
|
|
80
|
+
) -> AgentAdapter:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class LangGraphAgentCreator(AgentCreator):
|
|
85
|
+
def create_agent(
|
|
86
|
+
self,
|
|
87
|
+
name: str,
|
|
88
|
+
model_config: Dict[str, Any],
|
|
89
|
+
tools: List[Any],
|
|
90
|
+
system_prompt: str,
|
|
91
|
+
structured_output_model: Any = None,
|
|
92
|
+
) -> LangGraphAgentAdapter:
|
|
93
|
+
from langchain.agents import create_agent
|
|
94
|
+
from langchain.tools import tool
|
|
95
|
+
from langchain.agents.structured_output import ProviderStrategy
|
|
96
|
+
|
|
97
|
+
tools = [tool(tool_name, description=description)(tool_callable) for tool_name, description, tool_callable in tools]
|
|
98
|
+
|
|
99
|
+
output_parser = None
|
|
100
|
+
if structured_output_model:
|
|
101
|
+
output_parser = ProviderStrategy(structured_output_model)
|
|
102
|
+
|
|
103
|
+
agent = create_agent(
|
|
104
|
+
name=name,
|
|
105
|
+
model=get_model(model_config, 'langgraph', tools=tools),
|
|
106
|
+
tools=tools,
|
|
107
|
+
system_prompt=system_prompt,
|
|
108
|
+
response_format=output_parser
|
|
109
|
+
)
|
|
110
|
+
return LangGraphAgentAdapter(agent)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class CrewAIAgentCreator(AgentCreator):
|
|
114
|
+
def create_agent(
|
|
115
|
+
self,
|
|
116
|
+
name: str,
|
|
117
|
+
model_config: Dict[str, Any],
|
|
118
|
+
tools: List[Any],
|
|
119
|
+
system_prompt: str,
|
|
120
|
+
structured_output_model: Any = None
|
|
121
|
+
) -> CrewAIAgentAdapter:
|
|
122
|
+
from crewai.agent import Agent
|
|
123
|
+
from crewai.tools import tool
|
|
124
|
+
|
|
125
|
+
def create_crewai_tool(tool_name: str, description: str, tool_callable: Callable) -> Any:
|
|
126
|
+
tool_callable.__doc__ = description
|
|
127
|
+
return tool(tool_name)(tool_callable)
|
|
128
|
+
|
|
129
|
+
tools = [create_crewai_tool(tn, desc, tc) for tn, desc, tc in tools]
|
|
130
|
+
|
|
131
|
+
agent = Agent(
|
|
132
|
+
role=name,
|
|
133
|
+
backstory=system_prompt,
|
|
134
|
+
goal="Collect the required data from user messages using the available tools.",
|
|
135
|
+
tools=tools,
|
|
136
|
+
llm=get_model(model_config, 'crewai'),
|
|
137
|
+
max_retry_limit=2
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
return CrewAIAgentAdapter(agent, output_schema=structured_output_model)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class AgnoAgentCreator(AgentCreator):
|
|
144
|
+
def create_agent(
|
|
145
|
+
self,
|
|
146
|
+
name: str,
|
|
147
|
+
model_config: Dict[str, Any],
|
|
148
|
+
tools: List[Any],
|
|
149
|
+
system_prompt: str,
|
|
150
|
+
structured_output_model: Any = None
|
|
151
|
+
) -> AgnoAgentAdapter:
|
|
152
|
+
from agno.agent import Agent
|
|
153
|
+
from agno.tools import tool
|
|
154
|
+
|
|
155
|
+
tools = [tool(name=tool_name, description=description)(tool_callable) for tool_name, description, tool_callable in tools]
|
|
156
|
+
|
|
157
|
+
agent = Agent(
|
|
158
|
+
name=name,
|
|
159
|
+
model=get_model(model_config, 'agno'),
|
|
160
|
+
tools=tools,
|
|
161
|
+
instructions=[system_prompt]
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return AgnoAgentAdapter(agent)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class PydanticAIAgentCreator(AgentCreator):
|
|
168
|
+
def create_agent(
|
|
169
|
+
self,
|
|
170
|
+
name: str,
|
|
171
|
+
model_config: Dict[str, Any],
|
|
172
|
+
tools: List[Tuple[str, str, Callable]],
|
|
173
|
+
system_prompt: str,
|
|
174
|
+
structured_output_model: Any = None
|
|
175
|
+
) -> PydanticAIAgentAdapter:
|
|
176
|
+
from pydantic_ai import Agent
|
|
177
|
+
|
|
178
|
+
agent = Agent(
|
|
179
|
+
model=get_model(model_config, 'pydantic-ai'),
|
|
180
|
+
system_prompt=system_prompt,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
for tool_name, description, tool_callable in tools:
|
|
184
|
+
agent.tool(name=tool_name, description=description)(tool_callable)
|
|
185
|
+
|
|
186
|
+
return PydanticAIAgentAdapter(agent)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class AgentFactory:
|
|
190
|
+
_CREATORS = {
|
|
191
|
+
"langgraph": LangGraphAgentCreator,
|
|
192
|
+
"crewai": CrewAIAgentCreator,
|
|
193
|
+
"agno": AgnoAgentCreator,
|
|
194
|
+
"pydantic-ai": PydanticAIAgentCreator,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def get_creator(cls, framework: str) -> AgentCreator:
|
|
199
|
+
framework_lower = framework.lower()
|
|
200
|
+
|
|
201
|
+
if framework_lower not in cls._CREATORS:
|
|
202
|
+
supported = ", ".join(cls._CREATORS.keys())
|
|
203
|
+
raise ValueError(
|
|
204
|
+
f"Unsupported agent framework: '{framework}'. "
|
|
205
|
+
f"Supported frameworks: {supported}"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
creator_class = cls._CREATORS[framework_lower]
|
|
209
|
+
return creator_class()
|
|
210
|
+
|
|
211
|
+
@classmethod
|
|
212
|
+
def create_agent(
|
|
213
|
+
cls,
|
|
214
|
+
framework: str,
|
|
215
|
+
name: str,
|
|
216
|
+
model_config: Dict[str, Any],
|
|
217
|
+
tools: List[Any],
|
|
218
|
+
system_prompt: str,
|
|
219
|
+
structured_output_model: Any
|
|
220
|
+
) -> Any:
|
|
221
|
+
creator = cls.get_creator(framework)
|
|
222
|
+
return creator.create_agent(
|
|
223
|
+
name=name,
|
|
224
|
+
model_config=model_config,
|
|
225
|
+
tools=tools,
|
|
226
|
+
system_prompt=system_prompt,
|
|
227
|
+
structured_output_model=structured_output_model
|
|
228
|
+
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional, Type
|
|
2
|
+
from pydantic import BaseModel, Field, create_model
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
TYPE_MAP = {
|
|
6
|
+
"text": str,
|
|
7
|
+
"number": int,
|
|
8
|
+
"double": float,
|
|
9
|
+
"boolean": bool,
|
|
10
|
+
"list": list,
|
|
11
|
+
"dict": dict,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_structured_output_model(
|
|
16
|
+
fields: List[Dict[str, Any]],
|
|
17
|
+
model_name: str = "StructuredOutput",
|
|
18
|
+
needs_intent_change: bool = False,
|
|
19
|
+
) -> Type[BaseModel]:
|
|
20
|
+
if not fields:
|
|
21
|
+
raise ValueError("At least one field definition is required")
|
|
22
|
+
|
|
23
|
+
field_definitions = {"bot_response": (Optional[str], Field(None, description="bot response for the user query"))}
|
|
24
|
+
|
|
25
|
+
if needs_intent_change:
|
|
26
|
+
field_definitions["intent_change"] = (Optional[str], Field(None, description="node name for handling new intent"))
|
|
27
|
+
|
|
28
|
+
for field_def in fields:
|
|
29
|
+
field_name = field_def.get("name")
|
|
30
|
+
field_type = field_def.get("type")
|
|
31
|
+
field_description = field_def.get("description", "")
|
|
32
|
+
is_required = field_def.get("required", True)
|
|
33
|
+
|
|
34
|
+
if not field_name:
|
|
35
|
+
raise ValueError("Field definition missing 'name'")
|
|
36
|
+
|
|
37
|
+
if not field_type:
|
|
38
|
+
raise ValueError(f"Field '{field_name}' missing 'type'")
|
|
39
|
+
|
|
40
|
+
python_type = TYPE_MAP.get(field_type)
|
|
41
|
+
if python_type is None:
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"Unknown type '{field_type}' for field '{field_name}'. "
|
|
44
|
+
f"Supported types: {list(TYPE_MAP.keys())}"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if is_required:
|
|
48
|
+
field_definitions[field_name] = (
|
|
49
|
+
python_type,
|
|
50
|
+
Field(..., description=field_description)
|
|
51
|
+
)
|
|
52
|
+
else:
|
|
53
|
+
python_type = Optional[python_type]
|
|
54
|
+
field_definitions[field_name] = (
|
|
55
|
+
python_type,
|
|
56
|
+
Field(default=None, description=field_description)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
model = create_model(model_name, **field_definitions)
|
|
61
|
+
return model
|
|
62
|
+
except Exception as e:
|
|
63
|
+
raise ValueError(f"Failed to create model '{model_name}': {e}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def validate_field_definitions(fields: List[Dict[str, Any]]) -> bool:
|
|
67
|
+
if not isinstance(fields, list):
|
|
68
|
+
raise ValueError("Field definitions must be a list")
|
|
69
|
+
|
|
70
|
+
if not fields:
|
|
71
|
+
raise ValueError("At least one field definition is required")
|
|
72
|
+
|
|
73
|
+
field_names = set()
|
|
74
|
+
|
|
75
|
+
for i, field_def in enumerate(fields):
|
|
76
|
+
if not isinstance(field_def, dict):
|
|
77
|
+
raise ValueError(f"Field definition at index {i} must be a dictionary")
|
|
78
|
+
|
|
79
|
+
required_keys = ["name", "type", "description"]
|
|
80
|
+
for key in required_keys:
|
|
81
|
+
if key not in field_def:
|
|
82
|
+
raise ValueError(f"Field definition at index {i} missing required key '{key}'")
|
|
83
|
+
|
|
84
|
+
field_name = field_def["name"]
|
|
85
|
+
|
|
86
|
+
if field_name in field_names:
|
|
87
|
+
raise ValueError(f"Duplicate field name '{field_name}' found")
|
|
88
|
+
field_names.add(field_name)
|
|
89
|
+
|
|
90
|
+
field_type = field_def["type"]
|
|
91
|
+
if field_type not in TYPE_MAP:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"Invalid type '{field_type}' for field '{field_name}'. "
|
|
94
|
+
f"Supported types: {list(TYPE_MAP.keys())}"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return True
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class WorkflowKeys:
|
|
5
|
+
STEP_ID = '_step_id'
|
|
6
|
+
STATUS = '_status'
|
|
7
|
+
OUTCOME_ID = '_outcome_id'
|
|
8
|
+
MESSAGES = '_messages'
|
|
9
|
+
CONVERSATIONS = '_conversations'
|
|
10
|
+
STATE_HISTORY = '_state_history'
|
|
11
|
+
COLLECTOR_NODES = '_collector_nodes'
|
|
12
|
+
ATTEMPT_COUNTS = '_attempt_counts'
|
|
13
|
+
NODE_EXECUTION_ORDER = '_node_execution_order'
|
|
14
|
+
NODE_FIELD_MAP = '_node_field_map'
|
|
15
|
+
COMPUTED_FIELDS = '_computed_fields'
|
|
16
|
+
ERROR = 'error'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ActionType(Enum):
|
|
20
|
+
COLLECT_INPUT_WITH_AGENT = 'collect_input_with_agent'
|
|
21
|
+
CALL_FUNCTION = 'call_function'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DataType(Enum):
|
|
25
|
+
TEXT = 'text'
|
|
26
|
+
NUMBER = 'number'
|
|
27
|
+
DOUBLE = 'double'
|
|
28
|
+
BOOLEAN = 'boolean'
|
|
29
|
+
LIST = 'list'
|
|
30
|
+
DICT = 'dict'
|
|
31
|
+
ANY = "any"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class OutcomeType(Enum):
|
|
35
|
+
SUCCESS = 'success'
|
|
36
|
+
FAILURE = 'failure'
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class StatusPattern:
|
|
40
|
+
COLLECTING = '{step_id}_collecting'
|
|
41
|
+
MAX_ATTEMPTS = '{step_id}_max_attempts'
|
|
42
|
+
NEXT_STEP = '{step_id}_{next_step}'
|
|
43
|
+
SUCCESS = '{step_id}_success'
|
|
44
|
+
FAILED = '{step_id}_failed'
|
|
45
|
+
INTENT_CHANGE = '{step_id}_{target_node}'
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TransitionPattern:
|
|
49
|
+
CAPTURED = '{field}_CAPTURED:'
|
|
50
|
+
FAILED = '{field}_FAILED:'
|
|
51
|
+
INTENT_CHANGE = 'INTENT_CHANGE:'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
DEFAULT_MAX_ATTEMPTS = 3
|
|
55
|
+
DEFAULT_MODEL = 'gpt-4o-mini'
|
|
56
|
+
DEFAULT_TIMEOUT = 300
|
|
57
|
+
|
|
58
|
+
MAX_ATTEMPTS_MESSAGE = "I'm having trouble understanding your {field}. Please contact customer service for assistance."
|
|
59
|
+
WORKFLOW_COMPLETE_MESSAGE = "Workflow completed."
|