soprano-sdk 0.2.14__tar.gz → 0.2.16__tar.gz

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.
Files changed (105) hide show
  1. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/PKG-INFO +2 -2
  2. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/pyproject.toml +2 -2
  3. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/agents/factory.py +88 -19
  4. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/.github/workflows/test_build_and_publish.yaml +0 -0
  5. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/.gitignore +0 -0
  6. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/.python-version +0 -0
  7. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/CLAUDE.md +0 -0
  8. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/LICENSE +0 -0
  9. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/README.md +0 -0
  10. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/concert_booking/__init__.py +0 -0
  11. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/concert_booking/booking_helpers.py +0 -0
  12. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/concert_booking/concert_ticket_booking.yaml +0 -0
  13. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/framework_example.yaml +0 -0
  14. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/greeting_functions.py +0 -0
  15. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/greeting_workflow.yaml +0 -0
  16. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/main.py +0 -0
  17. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/payment_async_functions.py +0 -0
  18. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/payment_async_workflow.yaml +0 -0
  19. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/persistence/README.md +0 -0
  20. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/persistence/conversation_based.py +0 -0
  21. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/persistence/entity_based.py +0 -0
  22. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/persistence/mongodb_demo.py +0 -0
  23. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/return_functions.py +0 -0
  24. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/return_workflow.yaml +0 -0
  25. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/structured_output_example.yaml +0 -0
  26. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/README.md +0 -0
  27. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/crewai_supervisor_ui.py +0 -0
  28. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/langgraph_supervisor_ui.py +0 -0
  29. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/tools/__init__.py +0 -0
  30. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/tools/crewai_tools.py +0 -0
  31. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/tools/langgraph_tools.py +0 -0
  32. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/supervisors/workflow_tools.py +0 -0
  33. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/test_payment_async.py +0 -0
  34. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/tools/__init__.py +0 -0
  35. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/tools/address.py +0 -0
  36. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/examples/validator.py +0 -0
  37. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/langgraph_demo.py +0 -0
  38. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/langgraph_selfloop_demo.py +0 -0
  39. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/langgraph_v.py +0 -0
  40. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/main.py +0 -0
  41. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/return_fsm.excalidraw +0 -0
  42. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/return_state_machine.png +0 -0
  43. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/legacy/ui.py +0 -0
  44. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/scripts/visualize_workflow.py +0 -0
  45. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/scripts/workflow_demo.py +0 -0
  46. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/scripts/workflow_demo_ui.py +0 -0
  47. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/__init__.py +0 -0
  48. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/agents/__init__.py +0 -0
  49. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/agents/adaptor.py +0 -0
  50. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/agents/structured_output.py +0 -0
  51. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/authenticators/__init__.py +0 -0
  52. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/authenticators/mfa.py +0 -0
  53. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/core/__init__.py +0 -0
  54. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/core/constants.py +0 -0
  55. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/core/engine.py +0 -0
  56. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/core/rollback_strategies.py +0 -0
  57. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/core/state.py +0 -0
  58. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/engine.py +0 -0
  59. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/nodes/__init__.py +0 -0
  60. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/nodes/async_function.py +0 -0
  61. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/nodes/base.py +0 -0
  62. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/nodes/call_function.py +0 -0
  63. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/nodes/collect_input.py +0 -0
  64. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/nodes/factory.py +0 -0
  65. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/routing/__init__.py +0 -0
  66. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/routing/router.py +0 -0
  67. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/tools.py +0 -0
  68. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/utils/__init__.py +0 -0
  69. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/utils/function.py +0 -0
  70. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/utils/logger.py +0 -0
  71. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/utils/template.py +0 -0
  72. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/utils/tool.py +0 -0
  73. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/utils/tracing.py +0 -0
  74. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/validation/__init__.py +0 -0
  75. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/validation/schema.py +0 -0
  76. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/soprano_sdk/validation/validator.py +0 -0
  77. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/debug_jinja2.py +0 -0
  78. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_adaptor_logging.py +0 -0
  79. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_agent_factory.py +0 -0
  80. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_async_function.py +0 -0
  81. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_collect_input_refactor.py +0 -0
  82. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_external_values.py +0 -0
  83. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_inputs_validation.py +0 -0
  84. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_jinja2_path.py +0 -0
  85. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_jinja2_standalone.py +0 -0
  86. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_mfa_scenarios.py +0 -0
  87. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_persistence.py +0 -0
  88. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_structured_output.py +0 -0
  89. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_transition_routing.py +0 -0
  90. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/tests/test_workflow_tool_context_update.py +0 -0
  91. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/todo.md +0 -0
  92. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/.eslintrc.cjs +0 -0
  93. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/.gitignore +0 -0
  94. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/README.md +0 -0
  95. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/index.html +0 -0
  96. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/package-lock.json +0 -0
  97. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/package.json +0 -0
  98. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/App.jsx +0 -0
  99. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/CustomNode.jsx +0 -0
  100. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/StepDetailsModal.jsx +0 -0
  101. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/WorkflowGraph.jsx +0 -0
  102. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/WorkflowInfoPanel.jsx +0 -0
  103. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/assets/react.svg +0 -0
  104. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/src/main.jsx +0 -0
  105. {soprano_sdk-0.2.14 → soprano_sdk-0.2.16}/workflow-visualizer/vite.config.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soprano-sdk
3
- Version: 0.2.14
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.81.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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "soprano-sdk"
7
- version = "0.2.14"
7
+ version = "0.2.16"
8
8
  description = "YAML-driven workflow engine with AI agent integration for building conversational SOPs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -30,7 +30,7 @@ dependencies = [
30
30
  "langchain-openai>=1.0.3",
31
31
  "langfuse>=3.10.1",
32
32
  "langgraph==1.0.2",
33
- "litellm>=1.81.1",
33
+ "litellm>=1.74.9",
34
34
  "openai>=1.92.1",
35
35
  "pydantic>=2.0.0",
36
36
  "pydantic-ai>=1.22.0",
@@ -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
- errors.append("API key/Auth callback for model is required in model_config")
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"openai/{model_name}",
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 tool
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
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes