soe-ai 0.1.2__py3-none-any.whl → 0.1.4__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.
Files changed (36) hide show
  1. soe/broker.py +14 -32
  2. soe/builtin_tools/__init__.py +12 -0
  3. soe/builtin_tools/soe_get_context_schema.py +56 -0
  4. soe/builtin_tools/soe_get_identities.py +63 -0
  5. soe/builtin_tools/soe_inject_context_schema_field.py +80 -0
  6. soe/builtin_tools/soe_inject_identity.py +64 -0
  7. soe/builtin_tools/soe_remove_context_schema_field.py +61 -0
  8. soe/builtin_tools/soe_remove_identity.py +61 -0
  9. soe/builtin_tools/soe_update_context.py +5 -2
  10. soe/docs/builtins/context_schema.md +158 -0
  11. soe/docs/builtins/identity.md +139 -0
  12. soe/docs/guide_01_tool.md +52 -0
  13. soe/docs/guide_02_llm.md +5 -5
  14. soe/docs/guide_11_builtins.md +11 -3
  15. soe/docs/index.md +3 -1
  16. soe/docs/primitives/node_reference.md +1 -0
  17. soe/docs/primitives/signals.md +10 -9
  18. soe/docs_index.py +1 -1
  19. soe/init.py +7 -1
  20. soe/lib/inheritance.py +42 -1
  21. soe/nodes/agent/factory.py +1 -1
  22. soe/nodes/agent/stages/response.py +3 -3
  23. soe/nodes/agent/types.py +1 -1
  24. soe/nodes/lib/response_builder.py +14 -12
  25. soe/nodes/lib/signal_emission.py +6 -10
  26. soe/nodes/llm/factory.py +3 -3
  27. soe/nodes/tool/state.py +21 -1
  28. soe/nodes/tool/validation/config.py +15 -0
  29. soe/validation/__init__.py +7 -1
  30. soe/validation/config.py +22 -0
  31. {soe_ai-0.1.2.dist-info → soe_ai-0.1.4.dist-info}/METADATA +3 -3
  32. {soe_ai-0.1.2.dist-info → soe_ai-0.1.4.dist-info}/RECORD +36 -28
  33. {soe_ai-0.1.2.dist-info → soe_ai-0.1.4.dist-info}/WHEEL +1 -1
  34. /soe/docs/builtins/{explore_docs.md → soe_explore_docs.md} +0 -0
  35. {soe_ai-0.1.2.dist-info → soe_ai-0.1.4.dist-info}/licenses/LICENSE +0 -0
  36. {soe_ai-0.1.2.dist-info → soe_ai-0.1.4.dist-info}/top_level.txt +0 -0
soe/init.py CHANGED
@@ -62,7 +62,13 @@ def create_all_nodes(
62
62
 
63
63
  tools_list = []
64
64
  if tools_registry:
65
- tools_list = [{"function": func, "max_retries": 0} for func in tools_registry.values()]
65
+ for entry in tools_registry.values():
66
+ if callable(entry):
67
+ # Simple function format: {"name": function}
68
+ tools_list.append({"function": entry, "max_retries": 0})
69
+ elif isinstance(entry, dict) and "function" in entry:
70
+ # Full config format: {"name": {"function": fn, ...}}
71
+ tools_list.append(entry)
66
72
  nodes["agent"] = create_agent_node_caller(backends, tools_list, call_llm, broadcast_signals_caller)
67
73
 
68
74
  if tools_registry is not None:
soe/lib/inheritance.py CHANGED
@@ -12,7 +12,9 @@ Used for workflow initialization and chaining.
12
12
  import copy
13
13
  from typing import Dict, Any, Optional
14
14
 
15
- from ..types import Backends
15
+ from ..types import Backends, EventTypes
16
+ from .register_event import register_event
17
+ from .context_fields import set_field
16
18
 
17
19
 
18
20
  def save_config_sections(
@@ -170,3 +172,42 @@ def inherit_context(
170
172
  }
171
173
 
172
174
  return inherited_context
175
+
176
+
177
+ def prepare_initial_context(
178
+ execution_id: str,
179
+ initial_context: Dict[str, Any],
180
+ backends: Backends,
181
+ inherit_context_from_id: Optional[str] = None,
182
+ ) -> Dict[str, Any]:
183
+ """
184
+ Prepare initial context, optionally inheriting from another execution.
185
+
186
+ Args:
187
+ execution_id: Target execution ID
188
+ initial_context: Initial context data provided by user
189
+ backends: Backend services
190
+ inherit_context_from_id: Optional source execution ID to inherit from
191
+
192
+ Returns:
193
+ Prepared context dictionary
194
+ """
195
+ if inherit_context_from_id:
196
+ register_event(
197
+ backends, execution_id, EventTypes.CONTEXT_INHERITANCE_START,
198
+ )
199
+ context = inherit_context(inherit_context_from_id, backends)
200
+ if initial_context:
201
+ register_event(
202
+ backends, execution_id, EventTypes.CONTEXT_MERGE,
203
+ {"fields": list(initial_context.keys())}
204
+ )
205
+ for field, value in initial_context.items():
206
+ set_field(context, field, value)
207
+ else:
208
+ context = {
209
+ k: [v] if not k.startswith("__") else v
210
+ for k, v in initial_context.items()
211
+ }
212
+
213
+ return context
@@ -97,7 +97,7 @@ def create_agent_node_caller(
97
97
  operational_state.context[operational_state.output_field] = [final_response.output]
98
98
 
99
99
  emit_completion_signals(
100
- selected_signal=final_response.selected_signal,
100
+ selected_signals=final_response.selected_signals,
101
101
  node_config=node_config,
102
102
  operational_state=operational_state,
103
103
  broadcast_signals_caller=broadcast_signals_caller,
@@ -4,7 +4,7 @@ from ...lib.llm_resolver import resolve_llm_call
4
4
  from ...lib.response_builder import (
5
5
  build_response_model,
6
6
  extract_output_from_response,
7
- extract_signal_from_response,
7
+ extract_signals_from_response,
8
8
  )
9
9
  from ....types import CallLlm
10
10
  from ..types import ResponseStageInput, FinalResponse
@@ -46,9 +46,9 @@ def execute_response_stage(
46
46
  )
47
47
 
48
48
  output_value = extract_output_from_response(raw_response, output_field)
49
- selected_signal = extract_signal_from_response(raw_response)
49
+ selected_signals = extract_signals_from_response(raw_response)
50
50
 
51
51
  return FinalResponse(
52
52
  output=output_value,
53
- selected_signal=selected_signal,
53
+ selected_signals=selected_signals,
54
54
  )
soe/nodes/agent/types.py CHANGED
@@ -63,4 +63,4 @@ class ResponseStageInput(BaseModel):
63
63
  class FinalResponse(BaseModel):
64
64
  """Standardized output from the Response stage."""
65
65
  output: Any
66
- selected_signal: Optional[str] = None
66
+ selected_signals: List[str] = []
@@ -5,9 +5,8 @@ Dynamic Pydantic response model builder.
5
5
  from typing import Type, Any, Optional, List, Dict, Literal
6
6
  from pydantic import RootModel
7
7
  from pydantic import BaseModel, Field, create_model
8
- from typing import Type, Any, Optional, List, Dict, Literal
9
8
 
10
- from pydantic import RootModel
9
+
11
10
  def build_response_model(
12
11
  output_field: Optional[str] = None,
13
12
  output_schema: Optional[Type[BaseModel]] = None,
@@ -18,8 +17,8 @@ def build_response_model(
18
17
 
19
18
  root_schema = None
20
19
  if output_schema and isinstance(output_schema, type) and issubclass(output_schema, RootModel):
21
- # Only return RootModel directly if no output_field is requested AND no signal selection needed
22
- if not output_field and (not signal_options or len(signal_options) <= 1):
20
+ # Use RootModel directly if no signal selection is needed (standard case for single output)
21
+ if not signal_options or len(signal_options) <= 1:
23
22
  return output_schema
24
23
  root_schema = output_schema
25
24
  if output_field:
@@ -51,11 +50,11 @@ def build_response_model(
51
50
  else:
52
51
  descriptions.append(f"- {s['name']}")
53
52
 
54
- desc_text = "Select the most appropriate signal:\n" + "\n".join(descriptions)
53
+ desc_text = "Select ALL signals that apply (can be none, one, or multiple):\n" + "\n".join(descriptions)
55
54
 
56
- fields["selected_signal"] = (
57
- signal_literal,
58
- Field(..., description=desc_text)
55
+ fields["selected_signals"] = (
56
+ List[signal_literal],
57
+ Field(default=[], description=desc_text)
59
58
  )
60
59
 
61
60
  model_name = "DynamicResponse"
@@ -81,11 +80,14 @@ def extract_output_from_response(
81
80
  return data.get("output")
82
81
 
83
82
 
84
- def extract_signal_from_response(response: BaseModel) -> Optional[str]:
83
+ def extract_signals_from_response(response: BaseModel) -> List[str]:
85
84
  """
86
- Extract the selected signal from a dynamic response model.
85
+ Extract the selected signals from a dynamic response model.
86
+ Returns a list of signal names (can be empty).
87
87
  """
88
88
  data = response.model_dump()
89
89
  if isinstance(data, dict):
90
- return data.get("selected_signal")
91
- return None
90
+ signals = data.get("selected_signals", [])
91
+ if isinstance(signals, list):
92
+ return signals
93
+ return []
@@ -39,7 +39,7 @@ def handle_llm_failure(
39
39
 
40
40
 
41
41
  def emit_completion_signals(
42
- selected_signal: Optional[str],
42
+ selected_signals: List[str],
43
43
  node_config: Dict[str, Any],
44
44
  operational_state: OperationalState,
45
45
  broadcast_signals_caller: BroadcastSignalsCaller,
@@ -49,17 +49,16 @@ def emit_completion_signals(
49
49
  Emit signals after successful node completion.
50
50
 
51
51
  Signal emission priority:
52
- 1. LLM-selected signal (when multiple signals with plain-text conditions)
52
+ 1. LLM-selected signals (when multiple signals with plain-text conditions)
53
53
  2. Jinja-conditioned emissions (evaluate {{ }} templates)
54
54
  3. Single unconditional signal (emit it)
55
- 4. Multiple signals without selection → error (shouldn't happen)
56
55
 
57
56
  The 'condition' field has dual purpose:
58
- - Plain text: used as description for LLM signal selection
57
+ - Plain text: used as description for LLM signal selection (multi-select)
59
58
  - Jinja template ({{ }}): evaluated to determine if signal should emit
60
59
  """
61
- if selected_signal:
62
- broadcast_signals_caller(execution_id, [selected_signal])
60
+ if selected_signals:
61
+ broadcast_signals_caller(execution_id, selected_signals)
63
62
  elif operational_state.event_emissions:
64
63
  if has_jinja_conditions(operational_state.event_emissions):
65
64
  handle_signal_emission(
@@ -73,7 +72,4 @@ def emit_completion_signals(
73
72
  ]
74
73
  if len(signals) == 1:
75
74
  broadcast_signals_caller(execution_id, signals)
76
- elif len(signals) > 1:
77
- raise RuntimeError(
78
- f"Multiple signals defined but no selection made: {signals}"
79
- )
75
+ # Multiple signals with no selection = LLM chose none, which is valid
soe/nodes/llm/factory.py CHANGED
@@ -12,7 +12,7 @@ from ..lib.signal_emission import emit_completion_signals, handle_llm_failure
12
12
  from ..lib.response_builder import (
13
13
  build_response_model,
14
14
  extract_output_from_response,
15
- extract_signal_from_response,
15
+ extract_signals_from_response,
16
16
  )
17
17
  from ...types import CallLlm, BroadcastSignalsCaller, Backends, LlmNodeCaller, EventTypes
18
18
  from ...lib.register_event import register_event
@@ -80,10 +80,10 @@ def create_llm_node_caller(
80
80
  rendered_prompt, str(output_value), backends
81
81
  )
82
82
 
83
- selected_signal = extract_signal_from_response(raw_response)
83
+ selected_signals = extract_signals_from_response(raw_response)
84
84
 
85
85
  emit_completion_signals(
86
- selected_signal=selected_signal,
86
+ selected_signals=selected_signals,
87
87
  node_config=node_config,
88
88
  operational_state=state,
89
89
  broadcast_signals_caller=broadcast_signals_caller,
soe/nodes/tool/state.py CHANGED
@@ -42,8 +42,14 @@ def get_operational_state(
42
42
  tool_name, tools_registry, execution_id, backends
43
43
  )
44
44
 
45
+ # Priority: 1) inline parameters, 2) context_parameter_field, 3) empty dict
46
+ inline_parameters = node_config.get("parameters")
45
47
  context_parameter_field = node_config.get("context_parameter_field")
46
- if context_parameter_field and context_parameter_field in context:
48
+
49
+ if inline_parameters is not None:
50
+ # Inline parameters from YAML - render any Jinja templates
51
+ parameters = _render_parameters(inline_parameters, context)
52
+ elif context_parameter_field and context_parameter_field in context:
47
53
  if process_accumulated:
48
54
  raw_params = context[context_parameter_field]
49
55
  else:
@@ -64,3 +70,17 @@ def get_operational_state(
64
70
  parameters=parameters,
65
71
  process_accumulated=process_accumulated,
66
72
  )
73
+
74
+
75
+ def _render_parameters(params: Any, context: Dict[str, Any]) -> Any:
76
+ """Render Jinja templates in parameter values."""
77
+ from ...lib.jinja_render import render_prompt
78
+
79
+ if isinstance(params, dict):
80
+ return {k: _render_parameters(v, context) for k, v in params.items()}
81
+ elif isinstance(params, list):
82
+ return [_render_parameters(item, context) for item in params]
83
+ elif isinstance(params, str) and "{{" in params:
84
+ rendered, _ = render_prompt(params, context)
85
+ return rendered
86
+ return params
@@ -108,6 +108,21 @@ def validate_node_config(node_config: Dict[str, Any]) -> None:
108
108
  "'output_field' cannot be '__operational__' - this is a reserved system field"
109
109
  )
110
110
 
111
+ # Validate parameters field (inline tool parameters)
112
+ parameters = node_config.get("parameters")
113
+ if parameters is not None:
114
+ if not isinstance(parameters, dict):
115
+ raise WorkflowValidationError(
116
+ "'parameters' must be a dict - the kwargs to pass to the tool"
117
+ )
118
+
119
+ # Cannot have both parameters and context_parameter_field
120
+ context_parameter_field = node_config.get("context_parameter_field")
121
+ if parameters is not None and context_parameter_field is not None:
122
+ raise WorkflowValidationError(
123
+ "Cannot specify both 'parameters' and 'context_parameter_field' - use one or the other"
124
+ )
125
+
111
126
 
112
127
  def validate_tool_node_config(
113
128
  node_config: Dict[str, Any], tools_registry: ToolsRegistry
@@ -6,13 +6,19 @@ Two types of validation:
6
6
  2. operational.py - Validates runtime state before node execution (fail-fast)
7
7
  """
8
8
 
9
- from .config import validate_config, validate_workflow, validate_orchestrate_params
9
+ from .config import (
10
+ validate_config,
11
+ validate_workflow,
12
+ validate_orchestrate_params,
13
+ validate_initial_workflow,
14
+ )
10
15
  from .operational import validate_operational, OperationalValidationError
11
16
 
12
17
  __all__ = [
13
18
  "validate_config",
14
19
  "validate_workflow",
15
20
  "validate_orchestrate_params",
21
+ "validate_initial_workflow",
16
22
  "validate_operational",
17
23
  "OperationalValidationError",
18
24
  ]
soe/validation/config.py CHANGED
@@ -193,3 +193,25 @@ def validate_orchestrate_params(
193
193
  raise WorkflowValidationError(
194
194
  "'initial_workflow_name' must be a non-empty string"
195
195
  )
196
+
197
+
198
+ def validate_initial_workflow(
199
+ initial_workflow_name: str,
200
+ parsed_registry: Dict[str, Any],
201
+ ) -> None:
202
+ """
203
+ Validate that the initial workflow exists in the registry.
204
+
205
+ Args:
206
+ initial_workflow_name: Name of workflow to start with
207
+ parsed_registry: Dictionary of available workflows
208
+
209
+ Raises:
210
+ WorkflowValidationError: If workflow not found
211
+ """
212
+ if initial_workflow_name not in parsed_registry:
213
+ available = list(parsed_registry.keys())
214
+ raise WorkflowValidationError(
215
+ f"Workflow '{initial_workflow_name}' not found in config. "
216
+ f"Available workflows: {available}"
217
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soe-ai
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Signal-driven Orchestration Engine - Agent orchestration with event-driven workflow engine
5
5
  Author-email: Pedro Garcia <pgarcia14180@gmail.com>
6
6
  License-Expression: MIT
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://github.com/pgarcia14180/soe/tree/master/docs
9
9
  Project-URL: Repository, https://github.com/pgarcia14180/soe
10
10
  Project-URL: Issues, https://github.com/pgarcia14180/soe/issues
11
11
  Keywords: orchestration,agent,workflow,automation
12
- Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Programming Language :: Python :: 3.8
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: pyyaml>=6.0
24
24
  Requires-Dist: pydantic>=2.0.0
25
- Requires-Dist: jinja2>=3.0.0
25
+ Requires-Dist: jinja2>=2.11.3
26
26
  Provides-Extra: dev
27
27
  Requires-Dist: pytest>=7.0; extra == "dev"
28
28
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
@@ -1,26 +1,32 @@
1
1
  soe/__init__.py,sha256=4g0b-2C4wlr3Aq9eSmISxEMeWRCI4fim_I1v4nfW_Cs,1131
2
- soe/broker.py,sha256=F_lKV0uqi9_dY1NIzQnUFJm84r6xd1CmvXjjfgRpwrM,5956
3
- soe/docs_index.py,sha256=CQZKGozZWB-uovDQxUts-vjIlS5vq6PmH824k8AJNbo,3507566
4
- soe/init.py,sha256=SdVV1oTmh63BCtJpaYZavyO0ALfffsFgd75Vb8aJmXI,5928
2
+ soe/broker.py,sha256=XLcjauBqpzNMyBj0ECPsoO9K2_UVnOFTDmkmOiEe6aQ,5043
3
+ soe/docs_index.py,sha256=LYrm2bVohGXKy5767IcE1jH9dL9sRGFYwgZdLrAYVdk,1325490
4
+ soe/init.py,sha256=Aaw1p5wEsk4Eo08K1oEkwKBmWdFsejzUf8YxWz79A-0,6245
5
5
  soe/types.py,sha256=3CERX7rti_xRSliH2knZKeNDWqbetWg0z-tTQaGZODk,5929
6
- soe/builtin_tools/__init__.py,sha256=DgFnCFYJ0tsyQqIbkiqe-rYjzaFMxKCuhG5X3ws31R0,1739
6
+ soe/builtin_tools/__init__.py,sha256=wC4eyf7pO7Oc81RnxekhJJ-E7352Q_Rtzoh9lUq_Aps,2593
7
7
  soe/builtin_tools/soe_add_signal.py,sha256=G85UkaOzYEtQDX5CcYk1HL8-aBd48mytVsvzC20fm9w,2583
8
8
  soe/builtin_tools/soe_call_tool.py,sha256=2aFPIHhKIvQIwtWbKOyvHBn4tMp_75YurgvRhKH-4QA,3370
9
9
  soe/builtin_tools/soe_copy_context.py,sha256=kuffSBSd8qgiqQQCzNr2qp9idW-aQMeQou-CXMHR5po,2812
10
10
  soe/builtin_tools/soe_explore_docs.py,sha256=yKanIF8XuSHkN9di3cWDBXdByLUz4L4E2VlfATrpZrk,9957
11
11
  soe/builtin_tools/soe_get_available_tools.py,sha256=WtE0EpumNfIc-EGQo8uCG87xQhFaShZwmZf_fJOQiUc,1154
12
12
  soe/builtin_tools/soe_get_context.py,sha256=wmWsV_lV_fzzjGyUpM2KQ1A6P1s0DqRA32sBU-coaVY,1463
13
+ soe/builtin_tools/soe_get_context_schema.py,sha256=zJkajWdARK74BCq1l6Ijg0rAwCNkp8qf0jYsE4maakA,1684
14
+ soe/builtin_tools/soe_get_identities.py,sha256=HYX0rRdb_RRjpHNHdd0A8zKrxvoAayKdO2VkvoeEiYs,2018
13
15
  soe/builtin_tools/soe_get_workflows.py,sha256=l04xLHHq87T69_9GRdQCzZ9eiv3cvFoJRpvZwxy63-M,2223
16
+ soe/builtin_tools/soe_inject_context_schema_field.py,sha256=zTKlMCTrpBgSs8aVD-zBXUNAEaUeSbXDD_leNr5iEts,2447
17
+ soe/builtin_tools/soe_inject_identity.py,sha256=oL3WEC8xoxCUJttSHL4NV1KgFT1gT9Goz0Dk9fCYEe0,1888
14
18
  soe/builtin_tools/soe_inject_node.py,sha256=0X1GP23Jqjp3Bm-W-TVToI5VSvYZQ0cCgg2jWfiDpEM,2830
15
19
  soe/builtin_tools/soe_inject_workflow.py,sha256=VqLcLObBJHNxG_LphzeXp7WK_YLEJukOGY6WUhyqSkY,3859
16
20
  soe/builtin_tools/soe_list_contexts.py,sha256=yDZI4feISa0sue_PYIe96De46-NondA9E3J6fur12kU,2290
21
+ soe/builtin_tools/soe_remove_context_schema_field.py,sha256=pNWEq8yMTyRSoVymyQFhc4lA2USFLus3PF30ag0gaYg,1811
22
+ soe/builtin_tools/soe_remove_identity.py,sha256=LMUwONg5pcxON5o4vM_IHD8vfJ1hCrZYL7tix-UcZBI,1739
17
23
  soe/builtin_tools/soe_remove_node.py,sha256=rDe8az7K9FaM4L4nTFdWFJRhte2p4eRXha6iv-5DoZg,2197
18
24
  soe/builtin_tools/soe_remove_workflow.py,sha256=AlhjPU1xrj6VqKSwAbBVpt1sv1B3gcnWasKcrJvw12w,1848
19
- soe/builtin_tools/soe_update_context.py,sha256=1gu0dTYtK-EY1n3qysJQeusfZYmxWoXCt3c7nhXTcRY,1547
25
+ soe/builtin_tools/soe_update_context.py,sha256=qXInqfM8UQnbbeYV1MUepMYaNsIXqTyMO_EfeXVtQTg,1690
20
26
  soe/docs/_config.yml,sha256=PBTNeE97HoDj80tgMtpfxrAAGQxr0OiCaMZaJF-qVmo,255
21
27
  soe/docs/guide_00_getting_started.md,sha256=ULHQfKSyex5I3FVwENVa3AmOQkMMKVKJ8TaVPpYVVXA,11279
22
- soe/docs/guide_01_tool.md,sha256=twDxHgQhHYgdWDlmoY0v9xnC-5RX_NbOMCRi68l_b_s,6964
23
- soe/docs/guide_02_llm.md,sha256=2t9td-V37vWdtdxfsPNFIT4y5w0vXZVQtc-gy6A3Jko,4839
28
+ soe/docs/guide_01_tool.md,sha256=SscNALq0V3-tCiWmhUqN9oX7EUqE-ktxDkKlFMsERFs,8242
29
+ soe/docs/guide_02_llm.md,sha256=dCjvCzHCTky9MasuQdaJNRXmQFcfALczTwaefG3NvSQ,4822
24
30
  soe/docs/guide_03_router.md,sha256=614FW8jhwJBZ6TBeyhBfRRDyw3xV6_6byZH74hlgO6A,5645
25
31
  soe/docs/guide_04_patterns.md,sha256=Yyzhb0yyFuHZSiPam7UCj6HagkTcqrI3K2MJbwA2nQU,15368
26
32
  soe/docs/guide_05_agent.md,sha256=eZAYryU1AypunOM3V8i9DOeCDPcvk0FjMg97355DCPw,6075
@@ -29,8 +35,8 @@ soe/docs/guide_07_identity.md,sha256=s2FGdS5rB5YD9GW64SYontIw-STreGkb0QRNvEkwlUw
29
35
  soe/docs/guide_08_child.md,sha256=whBLBmCH9si17lQfoUgN6U9A5Mc71_TywCYq_XQSfeg,17888
30
36
  soe/docs/guide_09_ecosystem.md,sha256=rfoKjskQmpOc4Fl1h6HUSqRExMd8DVnvH2rLNhxjVac,20219
31
37
  soe/docs/guide_10_infrastructure.md,sha256=oGZWtE-PJ-CpqGOF5aM5hM4CCXRjuMAA-C4IBhK-ZlE,14154
32
- soe/docs/guide_11_builtins.md,sha256=rxndeJ8INNxH7w7fWDQOfmCsNbpKwha3ZKPrcw4gZEo,4234
33
- soe/docs/index.md,sha256=kVJsInGngoHGUf0shEIgPKnaRo7BWTtrXSuS2YCOcQU,5084
38
+ soe/docs/guide_11_builtins.md,sha256=3kP_FL05G-DrVFHD4ySm6d9I12_vB191Fw7CuvrPMXU,4983
39
+ soe/docs/index.md,sha256=kW2wizdhNVaO6qpB8-uBGvu27ieBcondrl44SiMcdjs,5277
34
40
  soe/docs/advanced_patterns/guide_fanout_and_aggregations.md,sha256=vWs6-sBqczHI4knFBi7EtNUGdYmknb4Pp_vXp8lHMtY,9459
35
41
  soe/docs/advanced_patterns/guide_inheritance.md,sha256=xDC0MYn1oGQfiwy-4z01PpwUcpuLMREHqh61H-oCQWg,12212
36
42
  soe/docs/advanced_patterns/hybrid_intelligence.md,sha256=BoxK-MN8WRZOckqigWzOtwHsA47SKSAbzO9ekK06lGs,7142
@@ -39,18 +45,20 @@ soe/docs/advanced_patterns/operational.md,sha256=uk7r3Uh5yNIanbW6JrKD-_n_VPO5WZE
39
45
  soe/docs/advanced_patterns/self_evolving_workflows.md,sha256=HICTmuwIg-zjmiAXdbyPKmgD0hELoBLn9y54bbwYV1w,11072
40
46
  soe/docs/advanced_patterns/swarm_intelligence.md,sha256=rGKReC1beiU4x5pnKF9hWEXAmqrntQj9TnQ8KvKv8YY,6210
41
47
  soe/docs/builtins/context.md,sha256=l1sc9q2jFHCSm8w4klcZN32LNsq5xiMT6mk09oynMC8,3655
42
- soe/docs/builtins/explore_docs.md,sha256=XJRDNAGsxi98k9BHSyRHs06av_gqEVLwgaC1YFKG6NE,3646
48
+ soe/docs/builtins/context_schema.md,sha256=GomB-zpDRdjLph1JRVN29PrCb34U0K5eN80T44zQqVw,3697
49
+ soe/docs/builtins/identity.md,sha256=zFTRXE08hz1hl5CUJT-28o7u-XGldUxmHzhjRO_c81g,3386
50
+ soe/docs/builtins/soe_explore_docs.md,sha256=XJRDNAGsxi98k9BHSyRHs06av_gqEVLwgaC1YFKG6NE,3646
43
51
  soe/docs/builtins/tools.md,sha256=a5QZLEdddK6WZ1jJ1UPxlmTHHOjm4QhQZ8pC2GOEbr0,3753
44
52
  soe/docs/builtins/workflows.md,sha256=M1n2tGECcrCUQwZ-OzF-GqVRx-LNUxTvKDxIv41esx4,4774
45
53
  soe/docs/primitives/backends.md,sha256=T_6jhjum6af9gPil4vIZdJtX9tgSGCJk6IQUuiISnyo,8209
46
54
  soe/docs/primitives/context.md,sha256=FJ5d_7H8hOYJeSQ5MPzsapMS13WZ2f9IJ6of8TvmwdY,5325
47
- soe/docs/primitives/node_reference.md,sha256=S8Ifwmhtl3PDex5XpzQAgFd-MmbZRg84vIIdGP0b0Gs,8208
55
+ soe/docs/primitives/node_reference.md,sha256=rmYdB5DjgHlyB5hTC57WtbJajC9an5J8a7O2najAhXw,8304
48
56
  soe/docs/primitives/primitives.md,sha256=LUtIb1h5b2b3QCWSJrPYHUWAwE4KJjagCDCNJjj_UJo,11519
49
- soe/docs/primitives/signals.md,sha256=1TBzz5hdTVsvSl1tNKwKl-hRJeLiYatyRplxgxx0za0,26287
57
+ soe/docs/primitives/signals.md,sha256=n-rPlYFORVcm1Fmizmk6ZoNpFVa3eR7URCu3_b6saso,26382
50
58
  soe/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
59
  soe/lib/child_context.py,sha256=qIosNpCjhvEuLpJUHxRkgXjA78FyasnGrsTTcq9DN-4,1431
52
60
  soe/lib/context_fields.py,sha256=Fct7JlzWLQ2268pdKHo8P2o2DVhpIDNwVMQ3o5bcqtI,1363
53
- soe/lib/inheritance.py,sha256=m8BP-G8UIKuDYZBTXOcz1Jbecr1Tjg31GBTtYGA-GwU,5122
61
+ soe/lib/inheritance.py,sha256=4XEWSyhT6CMmqOaUrYSAGCPyqc1vpOVSM3MVhhOSjSQ,6440
54
62
  soe/lib/jinja_render.py,sha256=MTWNvv0XU2WmhcTupTfLkp_n348dL9nBlz0J4oDDm4Q,4041
55
63
  soe/lib/operational.py,sha256=pgx-nSOhYXD9pj1vlQqyCMloLLfPazL0WYp785K4mjQ,1416
56
64
  soe/lib/parent_sync.py,sha256=h5x20aop3zqgtLWaIJ848sd6hkRcEFvVed99JFBTdxQ,2504
@@ -73,16 +81,16 @@ soe/local_backends/storage/telemetry.py,sha256=K6gcpXDsoH9Pll_Lz-27ff_ad48nCNwfH
73
81
  soe/local_backends/storage/workflow.py,sha256=d3DiwfjR1OP4bnhRLgzdTZQ6xYUnwBh5B3sz0W5sH_k,2094
74
82
  soe/nodes/__init__.py,sha256=soAkTMdrAuc82la7TRabTtpiQW2kngd8MlWuJuCRCrM,305
75
83
  soe/nodes/agent/__init__.py,sha256=SQaDB9TAiMv5ZjGLX4B1nBnOwX_DGUxqzzDJ4BIT534,171
76
- soe/nodes/agent/factory.py,sha256=skqPpMcfA9qYtcFEJ2FqjRXhVrvn2XgEPg40dt8KnHw,5359
84
+ soe/nodes/agent/factory.py,sha256=b9EG5WsooG6uAmnKz0Hb2x34fo83ekTvXNmJLwxB_x8,5361
77
85
  soe/nodes/agent/state.py,sha256=2fznePHA-0etOlCepMKVnguFDpooYynTBD21VjI_Fgw,3716
78
- soe/nodes/agent/types.py,sha256=t25gHmsJ_oYxGXWSWvychvXcXcSenbQAMkET1CA-iO4,1837
86
+ soe/nodes/agent/types.py,sha256=MHbm6oJyOf91CsFW7ntRTpLPi3yOA3HxOKVigR8nRs4,1832
79
87
  soe/nodes/agent/lib/loop_handlers.py,sha256=ndCoW_hQbtEkoj7UYlvXskZxXc-IgTCG3kBQzjJqQUE,4642
80
88
  soe/nodes/agent/lib/loop_state.py,sha256=oft2uP5Rrl5iYrKZ31JX9nslKhi6GZRQZFclTU0w6DU,5474
81
89
  soe/nodes/agent/lib/prompts.py,sha256=Nk3115Hq7Pa5FX1w_YZel7Yi1BLcMjLGme-p3UgyOxY,2002
82
90
  soe/nodes/agent/lib/tools.py,sha256=8XDof2qYnUw8BWC0VXybMaBx-QwzEfZM5fAbA9VMwc0,986
83
91
  soe/nodes/agent/stages/__init__.py,sha256=l3jXE7U4B41w7iTvuvgVrymD_BNIQSNA65oWfMRYtgs,330
84
92
  soe/nodes/agent/stages/parameter.py,sha256=R6ylX2Lprf24FGiohN9LQk3C6jrQkTtOWdNNQHKST9g,1052
85
- soe/nodes/agent/stages/response.py,sha256=khoyIr8nX10DLKvw-fNE7NUZh5uB_rpmmKm6pOt0OG0,1671
93
+ soe/nodes/agent/stages/response.py,sha256=h5I5wUkONA_UmDugD5dvgxupCZHW6iSBcpqWCsbClL4,1676
86
94
  soe/nodes/agent/stages/router.py,sha256=AWtcYD8ae25QQFySg7iKyn9kKIq-8LLEZyqBG7XxL4I,1138
87
95
  soe/nodes/agent/validation/__init__.py,sha256=ELLoSXqr1NeVwG766QzTuP2Fm3rLMKBXdhsgRUYOy_E,314
88
96
  soe/nodes/agent/validation/config.py,sha256=YQABnBSS4bLZvdhl2N5AfSPsZmhVljWS8ibxDxAeyWs,3834
@@ -99,12 +107,12 @@ soe/nodes/lib/conversation_history.py,sha256=WTQscCSTElWShehij3lEVSWebHtrGpM_s2R
99
107
  soe/nodes/lib/identity.py,sha256=HxSVJrjPAyAjMujFOgq-uZkGYrSz6sZbjM1VFi2PSVk,1861
100
108
  soe/nodes/lib/llm_resolver.py,sha256=KJYh9Rt3T85XDe8wWyf1p-UPPxF6EYqGCdnd87rUk3o,4138
101
109
  soe/nodes/lib/output.py,sha256=bfTwwSmSFr8i5_AoKwrPU-bEMqImo8QDd-AWEY9mac4,2231
102
- soe/nodes/lib/response_builder.py,sha256=xnx7iKGRay3UNAfWRl934kUEmtb3VfxAoLG7aPWUa8o,3078
103
- soe/nodes/lib/signal_emission.py,sha256=o69AtiUctwP9E8UCKrfKUcFQJ5USlx-nhiY-F2I2Ibg,2773
110
+ soe/nodes/lib/response_builder.py,sha256=OJoR84JcySsVRwzccr2kVLFJ0-5jcwsICNCVb34CK5Y,3122
111
+ soe/nodes/lib/signal_emission.py,sha256=pf_7gPQShKnqFnEKqAKx2o-mAjm1fg7hLrz1NYPs5nc,2627
104
112
  soe/nodes/lib/signals.py,sha256=GD5PnwACVNvQ8VnH5o60ixhwZrO6cFlAb0DwEjW06T4,1829
105
113
  soe/nodes/lib/tools.py,sha256=2m5kQQWC46zL0wjj7Amo-m4Hzar56UH11q1z8XMlgmo,3105
106
114
  soe/nodes/llm/__init__.py,sha256=2iUEslXqRO5izJZLdecLBUZ0cXsQsD0pWg0CaBY13MI,159
107
- soe/nodes/llm/factory.py,sha256=3wiZxHGDWdTEi-_rZNAoPz_QTKYUurtd3Hd_aR9goCs,3743
115
+ soe/nodes/llm/factory.py,sha256=7OSRcN71r_0cCwpz-CdppcL7invm9K_wVt4bKaKpC5A,3748
108
116
  soe/nodes/llm/state.py,sha256=c4x_22SdYTa1NRz5APjex8Ro_l3ISAixg55-rIG6ucQ,2775
109
117
  soe/nodes/llm/types.py,sha256=hqUrvnNRCw_vnqJWIvdru9k4sLh6O3Zk9DSY-7jOE7c,223
110
118
  soe/nodes/llm/validation/__init__.py,sha256=HAArh6mw4ixTRx4v8CW44BcpIRpU6tLjLGPd06X9m4Y,308
@@ -117,21 +125,21 @@ soe/nodes/router/validation/__init__.py,sha256=DgU37MHrR90GI1VvvfaUltrFtwpVGlGOc
117
125
  soe/nodes/router/validation/config.py,sha256=iR07s31GsyJJBInljRu8qh7zMKHKGoYVf2auLb0lSQQ,2195
118
126
  soe/nodes/router/validation/operational.py,sha256=Chldb5tpMe1MfFV3ym5XzneIF2OA8cBTvbfdWchX21c,519
119
127
  soe/nodes/tool/factory.py,sha256=cWJD-tNsCQnp6vNGtdbdX7pnQWlsCu1RdClKH6q2KSA,2460
120
- soe/nodes/tool/state.py,sha256=ncJ0huYPwkKqU_2ITEc3hXOnB7S9a4RbLytZKVxs2uQ,2263
128
+ soe/nodes/tool/state.py,sha256=MkJpSAtdXCj7pqKy55shjn92S6jhnZcuTTjIzcp5Yxk,3113
121
129
  soe/nodes/tool/types.py,sha256=l3ZjXlOReqYEe8jg1ohzmldaPqQGEmZpkgNFCvWejw4,566
122
130
  soe/nodes/tool/lib/__init__.py,sha256=KG1pnYuOAdPofsmX9LZgNc61bqagj1SMv-mzw8J5Hvc,201
123
131
  soe/nodes/tool/lib/conditions.py,sha256=3xoBEjBeCZQGGjh8cRumH1IGwvZqv3vw_2zk9Ha6AWU,1111
124
132
  soe/nodes/tool/lib/failure.py,sha256=miCrV2Mbx8b6sle1WT_zoaAoAyB7tHQhkwcjxgiDmRY,891
125
133
  soe/nodes/tool/lib/parameters.py,sha256=q0c7znyqpRY3L0iI8x3WXTWyjSQ-XzDGw6baVJVdvDw,2182
126
134
  soe/nodes/tool/validation/__init__.py,sha256=9sdtiYrPZg4zJ3WXAWg6h4c_oS9SIVgL7Oc7JQTiMfI,382
127
- soe/nodes/tool/validation/config.py,sha256=tI8mHawFjbXLQ6xSMOJ9mnQUirnoqqK5Gfi9kclB3DE,4632
135
+ soe/nodes/tool/validation/config.py,sha256=E0QSAFXdDah9F-ljnuaRhqo3HAcmatlE-LHzEfwmtKo,5305
128
136
  soe/nodes/tool/validation/operational.py,sha256=5he58ssGzQ_kXfdy26y4kqNEjo_CAVx989JJxNa5fi0,488
129
- soe/validation/__init__.py,sha256=oZGAT3Mp8Pzu_D_FSObLUEBTf10dk8C-GhM4tipfAxw,523
130
- soe/validation/config.py,sha256=hB7Gk_bkoqvf0iES9PNmVTcKgyUm_0UgiCSXcc30ztc,6834
137
+ soe/validation/__init__.py,sha256=BjNN7MCR6OMBwFgKfw3NbKixYKkd0iPHk8zRi0dUMrg,604
138
+ soe/validation/config.py,sha256=ibkPUjeD8jmjsuoHzbcwzDSyKmx_0iLrER255HTuIHM,7497
131
139
  soe/validation/jinja.py,sha256=_Ykj-UT9i3wQRXCyQgja3boCZuI3lrqOnf5C3iB1Kmg,1746
132
140
  soe/validation/operational.py,sha256=P5SrE_8345IhHvsXpJ-XDEp1sIQVFhGXDBNQhuh7sTo,3628
133
- soe_ai-0.1.2.dist-info/licenses/LICENSE,sha256=SvEn330zvSOu83Vi4lDCX2QHgr6bmSSXOV1YClLGk1Y,1069
134
- soe_ai-0.1.2.dist-info/METADATA,sha256=ro4JH1Nr4YbaGYsgVpq-cz3_sGsKyKOzX4q35aJ4MaQ,8794
135
- soe_ai-0.1.2.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
136
- soe_ai-0.1.2.dist-info/top_level.txt,sha256=TUufXyVAQnzN6iT6zRb4dRHdfBSiWXuAL8EoyvugZuY,4
137
- soe_ai-0.1.2.dist-info/RECORD,,
141
+ soe_ai-0.1.4.dist-info/licenses/LICENSE,sha256=SvEn330zvSOu83Vi4lDCX2QHgr6bmSSXOV1YClLGk1Y,1069
142
+ soe_ai-0.1.4.dist-info/METADATA,sha256=0UYq6qWSIkvL3uU2xIg8mr2TtazHzcmDOp7qPTcfBP4,8794
143
+ soe_ai-0.1.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
144
+ soe_ai-0.1.4.dist-info/top_level.txt,sha256=TUufXyVAQnzN6iT6zRb4dRHdfBSiWXuAL8EoyvugZuY,4
145
+ soe_ai-0.1.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5