soprano-sdk 0.2.14__py3-none-any.whl → 0.2.16__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/agents/factory.py +88 -19
- {soprano_sdk-0.2.14.dist-info → soprano_sdk-0.2.16.dist-info}/METADATA +2 -2
- {soprano_sdk-0.2.14.dist-info → soprano_sdk-0.2.16.dist-info}/RECORD +5 -5
- {soprano_sdk-0.2.14.dist-info → soprano_sdk-0.2.16.dist-info}/WHEEL +0 -0
- {soprano_sdk-0.2.14.dist-info → soprano_sdk-0.2.16.dist-info}/licenses/LICENSE +0 -0
soprano_sdk/agents/factory.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import Any, Dict, List, Literal, Tuple, Callable
|
|
2
|
+
from typing import Any, Dict, List, Literal, Tuple, Callable, get_origin, get_args
|
|
3
3
|
|
|
4
4
|
from agno.models.openai import OpenAIChat
|
|
5
5
|
from crewai import LLM
|
|
@@ -18,36 +18,41 @@ from .adaptor import (
|
|
|
18
18
|
|
|
19
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
20
|
errors = []
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
model_name: str = config.get("model_name", "")
|
|
23
23
|
if not model_name:
|
|
24
24
|
errors.append("Model name is required in model_config")
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
# Determine provider (openai, ollama, etc.)
|
|
27
|
+
provider = config.get("provider", "openai").lower()
|
|
28
|
+
|
|
29
|
+
# Handle base_url - required for Ollama, optional for OpenAI
|
|
26
30
|
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
31
|
api_key = config.get("api_key", "")
|
|
31
32
|
if not api_key:
|
|
32
33
|
if auth_callback := config.get("auth_callback"):
|
|
33
34
|
api_key = auth_callback()
|
|
34
35
|
if not api_key:
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
# Ollama doesn't require a real API key
|
|
37
|
+
if provider == "ollama":
|
|
38
|
+
api_key = "ollama"
|
|
39
|
+
else:
|
|
40
|
+
errors.append("API key/Auth callback for model is required in model_config")
|
|
41
|
+
|
|
37
42
|
if errors:
|
|
38
43
|
raise ValueError("; ".join(errors))
|
|
39
|
-
|
|
40
|
-
if framework == "agno"
|
|
44
|
+
|
|
45
|
+
if framework == "agno":
|
|
41
46
|
return OpenAIChat(
|
|
42
47
|
id=model_name,
|
|
43
48
|
api_key=api_key,
|
|
44
49
|
base_url=base_url
|
|
45
50
|
)
|
|
46
51
|
|
|
47
|
-
if framework == "crewai"
|
|
52
|
+
if framework == "crewai":
|
|
48
53
|
return LLM(
|
|
49
54
|
api_key=api_key,
|
|
50
|
-
model=f"
|
|
55
|
+
model=f"{provider}/{model_name}",
|
|
51
56
|
base_url=base_url,
|
|
52
57
|
temperature=0.1,
|
|
53
58
|
top_p=0.7
|
|
@@ -58,7 +63,6 @@ def get_model(config: Dict[str, Any], framework: Literal['langgraph', 'crewai',
|
|
|
58
63
|
api_key=SecretStr(api_key),
|
|
59
64
|
base_url=base_url,
|
|
60
65
|
)
|
|
61
|
-
|
|
62
66
|
if output_schema:
|
|
63
67
|
return llm.with_structured_output(output_schema)
|
|
64
68
|
|
|
@@ -120,12 +124,77 @@ class CrewAIAgentCreator(AgentCreator):
|
|
|
120
124
|
structured_output_model: Any = None
|
|
121
125
|
) -> CrewAIAgentAdapter:
|
|
122
126
|
from crewai.agent import Agent
|
|
123
|
-
from crewai.tools import
|
|
127
|
+
from crewai.tools import BaseTool
|
|
128
|
+
from pydantic import Field, create_model
|
|
129
|
+
from typing import Type
|
|
130
|
+
import inspect
|
|
131
|
+
|
|
132
|
+
def create_crewai_tool(tool_name: str, tool_description: str, tool_callable: Callable) -> Any:
|
|
133
|
+
"""Create a CrewAI tool with proper Pydantic schema for type hints"""
|
|
134
|
+
|
|
135
|
+
# Get function signature to build schema
|
|
136
|
+
sig = inspect.signature(tool_callable)
|
|
137
|
+
|
|
138
|
+
# Build Pydantic fields from function parameters
|
|
139
|
+
schema_fields = {}
|
|
140
|
+
for param_name, param in sig.parameters.items():
|
|
141
|
+
# Skip **kwargs and **state parameters - they shouldn't be in the schema
|
|
142
|
+
# These are used for validators and internal context
|
|
143
|
+
if param.kind == inspect.Parameter.VAR_KEYWORD:
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
# Get parameter annotation, default to str if not specified
|
|
147
|
+
param_type = param.annotation if param.annotation != inspect.Parameter.empty else str
|
|
148
|
+
|
|
149
|
+
# Default description
|
|
150
|
+
description = f"Parameter: {param_name}"
|
|
151
|
+
|
|
152
|
+
# Check if using Annotated type hint for description
|
|
153
|
+
if get_origin(param_type) is not None:
|
|
154
|
+
# Handle Annotated[type, "description", ...]
|
|
155
|
+
try:
|
|
156
|
+
from typing import Annotated
|
|
157
|
+
if get_origin(param_type) is Annotated:
|
|
158
|
+
args = get_args(param_type)
|
|
159
|
+
param_type = args[0] # First arg is the actual type
|
|
160
|
+
# Look for string metadata as description
|
|
161
|
+
for metadata in args[1:]:
|
|
162
|
+
if isinstance(metadata, str):
|
|
163
|
+
description = metadata
|
|
164
|
+
break
|
|
165
|
+
except ImportError:
|
|
166
|
+
# Python < 3.9 doesn't have Annotated in typing
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
# Get default value if exists
|
|
170
|
+
if param.default != inspect.Parameter.empty:
|
|
171
|
+
schema_fields[param_name] = (
|
|
172
|
+
param_type,
|
|
173
|
+
Field(default=param.default, description=description)
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
schema_fields[param_name] = (
|
|
177
|
+
param_type,
|
|
178
|
+
Field(..., description=description)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Create dynamic Pydantic model for tool input schema
|
|
182
|
+
ToolInputSchema = create_model(
|
|
183
|
+
f"{tool_name.title().replace('_', '')}Input",
|
|
184
|
+
**schema_fields
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Create custom BaseTool class with proper schema
|
|
188
|
+
class CustomCrewAITool(BaseTool):
|
|
189
|
+
name: str = tool_name
|
|
190
|
+
description: str = tool_description
|
|
191
|
+
args_schema: Type[BaseModel] = ToolInputSchema
|
|
192
|
+
|
|
193
|
+
def _run(self, **kwargs) -> str:
|
|
194
|
+
return tool_callable(**kwargs)
|
|
195
|
+
|
|
196
|
+
return CustomCrewAITool()
|
|
124
197
|
|
|
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
198
|
tools = [create_crewai_tool(tn, desc, tc) for tn, desc, tc in tools]
|
|
130
199
|
|
|
131
200
|
agent = Agent(
|
|
@@ -136,7 +205,7 @@ class CrewAIAgentCreator(AgentCreator):
|
|
|
136
205
|
llm=get_model(model_config, 'crewai'),
|
|
137
206
|
max_retry_limit=2
|
|
138
207
|
)
|
|
139
|
-
|
|
208
|
+
|
|
140
209
|
return CrewAIAgentAdapter(agent, output_schema=structured_output_model)
|
|
141
210
|
|
|
142
211
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: soprano-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: YAML-driven workflow engine with AI agent integration for building conversational SOPs
|
|
5
5
|
Author: Arvind Thangamani
|
|
6
6
|
License: MIT
|
|
@@ -21,7 +21,7 @@ Requires-Dist: langchain-openai>=1.0.3
|
|
|
21
21
|
Requires-Dist: langchain>=1.0.7
|
|
22
22
|
Requires-Dist: langfuse>=3.10.1
|
|
23
23
|
Requires-Dist: langgraph==1.0.2
|
|
24
|
-
Requires-Dist: litellm>=1.
|
|
24
|
+
Requires-Dist: litellm>=1.74.9
|
|
25
25
|
Requires-Dist: openai>=1.92.1
|
|
26
26
|
Requires-Dist: pydantic-ai>=1.22.0
|
|
27
27
|
Requires-Dist: pydantic>=2.0.0
|
|
@@ -3,7 +3,7 @@ soprano_sdk/engine.py,sha256=EFK91iTHjp72otLN6Kg-yeLye2J3CAKN0QH4FI2taL8,14838
|
|
|
3
3
|
soprano_sdk/tools.py,sha256=dmJ0OZ7Bj3rvjBQvLzgWlYRFVtNJOyMO2jLqaS13cAc,10971
|
|
4
4
|
soprano_sdk/agents/__init__.py,sha256=Yzbtv6iP_ABRgZo0IUjy9vDofEvLFbOjuABw758176A,636
|
|
5
5
|
soprano_sdk/agents/adaptor.py,sha256=0EjLf4sVWboLclLwsm_EbKS0WPeAAd1U8J6YuFB7wFA,3342
|
|
6
|
-
soprano_sdk/agents/factory.py,sha256=
|
|
6
|
+
soprano_sdk/agents/factory.py,sha256=CvXhpvtjf_Hb4Ce8WKAa0FzyY5Jm6lssvIIfSXu7jPY,9788
|
|
7
7
|
soprano_sdk/agents/structured_output.py,sha256=7DSVzfMPsZAqBwI3v6XL15qG5Gh4jJ-qddcVPaa3gdc,3326
|
|
8
8
|
soprano_sdk/authenticators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
soprano_sdk/authenticators/mfa.py,sha256=Vew9Nb8pIRTw9hKbEZTH3YScY-fZ_TLq4ZuCzc-wbr8,7387
|
|
@@ -29,7 +29,7 @@ soprano_sdk/utils/tracing.py,sha256=gSHeBDLe-MbAZ9rkzpCoGFveeMdR9KLaA6tteB0IWjk,
|
|
|
29
29
|
soprano_sdk/validation/__init__.py,sha256=ImChmO86jYHU90xzTttto2-LmOUOmvY_ibOQaLRz5BA,262
|
|
30
30
|
soprano_sdk/validation/schema.py,sha256=SlC4sq-ueEg0p_8Uox_cgPj9S-0AEEiOOlA1Vsu0DsE,15443
|
|
31
31
|
soprano_sdk/validation/validator.py,sha256=GaCvHvjwVe88Z8yatQsueiPnqtq1oo5uN75gogzpQT0,8940
|
|
32
|
-
soprano_sdk-0.2.
|
|
33
|
-
soprano_sdk-0.2.
|
|
34
|
-
soprano_sdk-0.2.
|
|
35
|
-
soprano_sdk-0.2.
|
|
32
|
+
soprano_sdk-0.2.16.dist-info/METADATA,sha256=khucbkyEa4EdkicgGz7xBJMQn6lrxCgSjZOv0fd-EPA,11374
|
|
33
|
+
soprano_sdk-0.2.16.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
34
|
+
soprano_sdk-0.2.16.dist-info/licenses/LICENSE,sha256=A1aBauSjPNtVehOXJe3WuvdU2xvM9H8XmigFMm6665s,1073
|
|
35
|
+
soprano_sdk-0.2.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|