soe-ai 0.1.4__tar.gz → 0.2.0b1__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 (154) hide show
  1. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/PKG-INFO +2 -2
  2. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/pyproject.toml +2 -2
  3. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/broker.py +32 -14
  4. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_update_context.py +2 -5
  5. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_01_tool.md +0 -52
  6. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_02_llm.md +5 -5
  7. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/index.md +1 -3
  8. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/primitives/node_reference.md +0 -1
  9. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/primitives/signals.md +9 -10
  10. soe_ai-0.2.0b1/soe/docs_index.py +2 -0
  11. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/init.py +1 -7
  12. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/inheritance.py +1 -42
  13. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/factory.py +1 -1
  14. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/stages/response.py +3 -3
  15. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/types.py +1 -1
  16. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/response_builder.py +10 -12
  17. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/signal_emission.py +10 -6
  18. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/factory.py +3 -3
  19. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/state.py +1 -21
  20. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/validation/config.py +0 -15
  21. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/validation/__init__.py +1 -7
  22. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/validation/config.py +0 -22
  23. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe_ai.egg-info/PKG-INFO +2 -2
  24. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe_ai.egg-info/SOURCES.txt +0 -1
  25. soe_ai-0.1.4/soe/docs_index.py +0 -2
  26. soe_ai-0.1.4/tests/test_setup_orchestration.py +0 -146
  27. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/LICENSE +0 -0
  28. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/README.md +0 -0
  29. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/setup.cfg +0 -0
  30. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/__init__.py +0 -0
  31. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/__init__.py +0 -0
  32. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_add_signal.py +0 -0
  33. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_call_tool.py +0 -0
  34. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_copy_context.py +0 -0
  35. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_explore_docs.py +0 -0
  36. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_get_available_tools.py +0 -0
  37. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_get_context.py +0 -0
  38. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_get_context_schema.py +0 -0
  39. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_get_identities.py +0 -0
  40. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_get_workflows.py +0 -0
  41. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_inject_context_schema_field.py +0 -0
  42. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_inject_identity.py +0 -0
  43. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_inject_node.py +0 -0
  44. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_inject_workflow.py +0 -0
  45. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_list_contexts.py +0 -0
  46. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_remove_context_schema_field.py +0 -0
  47. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_remove_identity.py +0 -0
  48. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_remove_node.py +0 -0
  49. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/builtin_tools/soe_remove_workflow.py +0 -0
  50. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/_config.yml +0 -0
  51. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/guide_fanout_and_aggregations.md +0 -0
  52. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/guide_inheritance.md +0 -0
  53. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/hybrid_intelligence.md +0 -0
  54. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/index.md +0 -0
  55. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/operational.md +0 -0
  56. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/self_evolving_workflows.md +0 -0
  57. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/advanced_patterns/swarm_intelligence.md +0 -0
  58. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/builtins/context.md +0 -0
  59. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/builtins/context_schema.md +0 -0
  60. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/builtins/identity.md +0 -0
  61. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/builtins/soe_explore_docs.md +0 -0
  62. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/builtins/tools.md +0 -0
  63. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/builtins/workflows.md +0 -0
  64. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_00_getting_started.md +0 -0
  65. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_03_router.md +0 -0
  66. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_04_patterns.md +0 -0
  67. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_05_agent.md +0 -0
  68. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_06_schema.md +0 -0
  69. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_07_identity.md +0 -0
  70. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_08_child.md +0 -0
  71. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_09_ecosystem.md +0 -0
  72. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_10_infrastructure.md +0 -0
  73. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/guide_11_builtins.md +0 -0
  74. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/primitives/backends.md +0 -0
  75. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/primitives/context.md +0 -0
  76. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/docs/primitives/primitives.md +0 -0
  77. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/__init__.py +0 -0
  78. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/child_context.py +0 -0
  79. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/context_fields.py +0 -0
  80. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/jinja_render.py +0 -0
  81. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/operational.py +0 -0
  82. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/parent_sync.py +0 -0
  83. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/register_event.py +0 -0
  84. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/schema_validation.py +0 -0
  85. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/lib/yaml_parser.py +0 -0
  86. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/__init__.py +0 -0
  87. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/factory.py +0 -0
  88. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/in_memory/context.py +0 -0
  89. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/in_memory/conversation_history.py +0 -0
  90. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/in_memory/identity.py +0 -0
  91. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/in_memory/schema.py +0 -0
  92. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/in_memory/telemetry.py +0 -0
  93. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/in_memory/workflow.py +0 -0
  94. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/storage/context.py +0 -0
  95. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/storage/conversation_history.py +0 -0
  96. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/storage/identity.py +0 -0
  97. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/storage/schema.py +0 -0
  98. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/storage/telemetry.py +0 -0
  99. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/local_backends/storage/workflow.py +0 -0
  100. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/__init__.py +0 -0
  101. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/__init__.py +0 -0
  102. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/lib/loop_handlers.py +0 -0
  103. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/lib/loop_state.py +0 -0
  104. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/lib/prompts.py +0 -0
  105. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/lib/tools.py +0 -0
  106. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/stages/__init__.py +0 -0
  107. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/stages/parameter.py +0 -0
  108. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/stages/router.py +0 -0
  109. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/state.py +0 -0
  110. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/validation/__init__.py +0 -0
  111. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/validation/config.py +0 -0
  112. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/agent/validation/operational.py +0 -0
  113. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/child/__init__.py +0 -0
  114. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/child/factory.py +0 -0
  115. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/child/state.py +0 -0
  116. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/child/validation/__init__.py +0 -0
  117. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/child/validation/config.py +0 -0
  118. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/child/validation/operational.py +0 -0
  119. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/conditions.py +0 -0
  120. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/context.py +0 -0
  121. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/conversation_history.py +0 -0
  122. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/identity.py +0 -0
  123. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/llm_resolver.py +0 -0
  124. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/output.py +0 -0
  125. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/signals.py +0 -0
  126. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/lib/tools.py +0 -0
  127. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/__init__.py +0 -0
  128. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/state.py +0 -0
  129. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/types.py +0 -0
  130. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/validation/__init__.py +0 -0
  131. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/validation/config.py +0 -0
  132. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/llm/validation/operational.py +0 -0
  133. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/router/__init__.py +0 -0
  134. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/router/factory.py +0 -0
  135. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/router/state.py +0 -0
  136. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/router/validation/__init__.py +0 -0
  137. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/router/validation/config.py +0 -0
  138. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/router/validation/operational.py +0 -0
  139. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/factory.py +0 -0
  140. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/lib/__init__.py +0 -0
  141. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/lib/conditions.py +0 -0
  142. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/lib/failure.py +0 -0
  143. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/lib/parameters.py +0 -0
  144. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/types.py +0 -0
  145. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/validation/__init__.py +0 -0
  146. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/nodes/tool/validation/operational.py +0 -0
  147. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/types.py +0 -0
  148. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/validation/jinja.py +0 -0
  149. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe/validation/operational.py +0 -0
  150. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe_ai.egg-info/dependency_links.txt +0 -0
  151. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe_ai.egg-info/requires.txt +0 -0
  152. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/soe_ai.egg-info/top_level.txt +0 -0
  153. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/tests/test_local_storage_backends.py +0 -0
  154. {soe_ai-0.1.4 → soe_ai-0.2.0b1}/tests/test_validation_errors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soe-ai
3
- Version: 0.1.4
3
+ Version: 0.2.0b1
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 :: 4 - Beta
12
+ Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Programming Language :: Python :: 3.8
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "soe-ai"
7
- version = "0.1.4"
7
+ version = "0.2.0b1"
8
8
  description = "Signal-driven Orchestration Engine - Agent orchestration with event-driven workflow engine"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -14,7 +14,7 @@ authors = [
14
14
  ]
15
15
  keywords = ["orchestration", "agent", "workflow", "automation"]
16
16
  classifiers = [
17
- "Development Status :: 4 - Beta",
17
+ "Development Status :: 3 - Alpha",
18
18
  "Intended Audience :: Developers",
19
19
  "Programming Language :: Python :: 3",
20
20
  "Programming Language :: Python :: 3.8",
@@ -4,18 +4,15 @@ from .types import Backends, BroadcastSignalsCaller, NodeCaller, EventTypes, Wor
4
4
  from .lib.register_event import register_event
5
5
  from .lib.yaml_parser import parse_yaml
6
6
  from .lib.operational import add_operational_state
7
+ from .lib.context_fields import set_field
7
8
  from .lib.parent_sync import get_signals_for_parent
8
9
  from .lib.inheritance import (
9
10
  inherit_config,
11
+ inherit_context,
10
12
  extract_and_save_config_sections,
11
- prepare_initial_context,
12
- )
13
- from .validation import (
14
- validate_config,
15
- validate_operational,
16
- validate_orchestrate_params,
17
- validate_initial_workflow,
18
13
  )
14
+ from .validation import validate_config, validate_operational, validate_orchestrate_params
15
+ from .types import WorkflowValidationError
19
16
 
20
17
 
21
18
  def orchestrate(
@@ -73,15 +70,17 @@ def orchestrate(
73
70
 
74
71
  id = str(uuid4())
75
72
 
76
- parsed_registry = {}
77
73
  if inherit_config_from_id:
78
74
  register_event(
79
75
  backends, id, EventTypes.CONFIG_INHERITANCE_START,
80
76
  {"source_execution_id": inherit_config_from_id}
81
77
  )
82
78
  parsed_registry = inherit_config(inherit_config_from_id, id, backends)
83
-
84
- if config:
79
+ if config:
80
+ validate_config(config)
81
+ parsed_config = parse_yaml(config)
82
+ parsed_registry = extract_and_save_config_sections(parsed_config, id, backends)
83
+ else:
85
84
  validate_config(config)
86
85
  parsed_config = parse_yaml(config)
87
86
  parsed_registry = extract_and_save_config_sections(parsed_config, id, backends)
@@ -93,13 +92,32 @@ def orchestrate(
93
92
 
94
93
  backends.workflow.save_workflows_registry(id, parsed_registry)
95
94
 
96
- validate_initial_workflow(initial_workflow_name, parsed_registry)
95
+ if initial_workflow_name not in parsed_registry:
96
+ available = list(parsed_registry.keys())
97
+ raise WorkflowValidationError(
98
+ f"Workflow '{initial_workflow_name}' not found in config. "
99
+ f"Available workflows: {available}"
100
+ )
97
101
 
98
102
  backends.workflow.save_current_workflow_name(id, initial_workflow_name)
99
103
 
100
- context = prepare_initial_context(
101
- id, initial_context, backends, inherit_context_from_id
102
- )
104
+ if inherit_context_from_id:
105
+ register_event(
106
+ backends, id, EventTypes.CONTEXT_INHERITANCE_START,
107
+ )
108
+ context = inherit_context(inherit_context_from_id, backends)
109
+ if initial_context:
110
+ register_event(
111
+ backends, id, EventTypes.CONTEXT_MERGE,
112
+ {"fields": list(initial_context.keys())}
113
+ )
114
+ for field, value in initial_context.items():
115
+ set_field(context, field, value)
116
+ else:
117
+ context = {
118
+ k: [v] if not k.startswith("__") else v
119
+ for k, v in initial_context.items()
120
+ }
103
121
 
104
122
  context = add_operational_state(id, context)
105
123
  backends.context.save_context(id, context)
@@ -5,8 +5,6 @@ Allows agents to write context fields dynamically.
5
5
 
6
6
  from typing import Any, Dict
7
7
 
8
- from ..lib.context_fields import set_field
9
-
10
8
 
11
9
  def create_soe_update_context_tool(backends, execution_id: str, tools_registry=None):
12
10
  """
@@ -43,10 +41,9 @@ def create_soe_update_context_tool(backends, execution_id: str, tools_registry=N
43
41
  if not filtered_updates:
44
42
  return {"status": "no valid updates (operational fields cannot be updated)"}
45
43
 
46
- # Get current context and update using set_field for proper list wrapping
44
+ # Get current context and update
47
45
  context = backends.context.get_context(execution_id)
48
- for field, value in filtered_updates.items():
49
- set_field(context, field, value)
46
+ context.update(filtered_updates)
50
47
  backends.context.save_context(execution_id, context)
51
48
 
52
49
  return {
@@ -39,58 +39,6 @@ example_workflow:
39
39
  3. **`output_field`**: Where to store the result in context.
40
40
  4. **`event_emissions`**: Signals to emit after execution (conditions evaluate `result`).
41
41
 
42
- ## Passing Parameters to Tools
43
-
44
- There are two ways to pass parameters to a tool: **inline parameters** (hardcoded in YAML) or **context parameters** (dynamic from context).
45
-
46
- ### Option 1: Inline Parameters (Static)
47
-
48
- Use `parameters` to specify tool arguments directly in the workflow YAML:
49
-
50
- ```yaml
51
- example_workflow:
52
- ReadToolDocs:
53
- node_type: tool
54
- event_triggers: [START]
55
- tool_name: soe_explore_docs
56
- parameters:
57
- path: "soe/docs/guide_01_tool.md"
58
- action: "read"
59
- output_field: tool_documentation
60
- event_emissions:
61
- - signal_name: DOCS_READY
62
- ```
63
-
64
- **Jinja templates work in parameters:**
65
-
66
- ```yaml
67
- example_workflow:
68
- FetchUserData:
69
- node_type: tool
70
- event_triggers: [START]
71
- tool_name: fetch_data
72
- parameters:
73
- user_id: "&#123;&#123; context.current_user_id &#125;&#125;"
74
- include_history: true
75
- output_field: user_data
76
- event_emissions:
77
- - signal_name: DATA_FETCHED
78
- ```
79
-
80
- ### Option 2: Context Parameters (Dynamic)
81
-
82
- Use `context_parameter_field` when the parameters come from another node's output or initial context:
83
-
84
- ```yaml
85
- example_workflow:
86
- SendEmail:
87
- node_type: tool
88
- event_triggers: [START]
89
- tool_name: send_email
90
- context_parameter_field: email_data
91
- output_field: email_result
92
- ```
93
-
94
42
  ### Understanding context_parameter_field
95
43
 
96
44
  The `context_parameter_field` specifies which context field contains the parameters to pass to your tool. This field must contain a dictionary that will be unpacked as keyword arguments.
@@ -79,7 +79,7 @@ This pattern is incredibly useful for:
79
79
 
80
80
  ## LLM Signal Selection (Resolution Step)
81
81
 
82
- When an LLM node has multiple signals with **conditions** (plain text, not Jinja), the LLM itself decides which signals to emit.
82
+ When an LLM node has multiple signals with **conditions** (plain text, not Jinja), the LLM itself decides which signal to emit.
83
83
 
84
84
  ### The Workflow
85
85
 
@@ -103,8 +103,8 @@ example_workflow:
103
103
 
104
104
  1. The LLM analyzes the sentiment
105
105
  2. SOE sees multiple signals with plain-text conditions (no `{{ }}`)
106
- 3. SOE asks the LLM: "Select ALL signals that apply" using the conditions as descriptions
107
- 4. The LLM returns a list of matching signals (can be none, one, or multiple)
106
+ 3. SOE asks the LLM: "Based on your analysis, which signal should be emitted?" using the conditions as descriptions
107
+ 4. The LLM returns the appropriate signal (POSITIVE, NEGATIVE, or NEUTRAL)
108
108
 
109
109
  This is called the **resolution step** - it lets the LLM make routing decisions based on its understanding.
110
110
 
@@ -115,7 +115,7 @@ The `condition` field controls how signals are emitted:
115
115
  | Condition | Behavior |
116
116
  |-----------|----------|
117
117
  | **No condition** | Signal is always emitted |
118
- | **Plain text** | Semantic—LLM selects any/all signals that apply based on the descriptions |
118
+ | **Plain text** | Semantic—LLM selects which signal to emit based on the description |
119
119
  | **Jinja template (`{{ }}`)** | Programmatic—evaluated against `context`, emits if truthy |
120
120
 
121
121
  **How SOE decides:**
@@ -123,7 +123,7 @@ The `condition` field controls how signals are emitted:
123
123
  1. **No conditions**: All signals emit unconditionally after node execution
124
124
  2. **Has conditions**: SOE checks if they contain `{{ }}`:
125
125
  - **Yes (Jinja)**: Evaluate expression against `context`—emit if result is truthy
126
- - **No (plain text)**: Ask LLM to select which signals apply (multi-select)
126
+ - **No (plain text)**: Ask LLM to choose which signal best matches its output
127
127
 
128
128
  ## Testing LLM Nodes
129
129
 
@@ -81,12 +81,10 @@ Built-in tools enable granular runtime modifications:
81
81
 
82
82
  | Built-in | Description |
83
83
  |----------|-------------|
84
- | [soe_explore_docs](builtins/soe_explore_docs.md) | Make SOE self-aware by exploring its documentation |
84
+ | [explore_docs](builtins/explore_docs.md) | Make SOE self-aware by exploring its documentation |
85
85
  | [workflows](builtins/workflows.md) | Query, inject, and modify workflows at runtime |
86
86
  | [context](builtins/context.md) | Read, update, and copy execution context |
87
87
  | [tools](builtins/tools.md) | Discover and dynamically call registered tools |
88
- | [identity](builtins/identity.md) | Query, inject, and remove identity definitions |
89
- | [context_schema](builtins/context_schema.md) | Query, inject, and remove context schema fields |
90
88
 
91
89
  ---
92
90
 
@@ -44,7 +44,6 @@ Complete reference for all node configuration parameters across all node types.
44
44
  |-----------|------|--------|-----|-------|------|-------|-------------|
45
45
  | `tool_name` | `str` | ✗ | ✗ | ✗ | **R** | ✗ | Tool to execute from registry |
46
46
  | `tools` | `List[str]` | ✗ | ✗ | **O** | ✗ | ✗ | Tool names available to agent |
47
- | `parameters` | `Dict` | ✗ | ✗ | ✗ | **O** | ✗ | Inline tool kwargs (supports Jinja) |
48
47
  | `context_parameter_field` | `str` | ✗ | ✗ | ✗ | **O** | ✗ | Context field containing tool kwargs |
49
48
 
50
49
  ### Child Workflow Parameters
@@ -122,7 +122,7 @@ example_workflow:
122
122
 
123
123
  Both `PROCESSING_DONE` and `LOG_EVENT` emit every time the node runs.
124
124
 
125
- > **Note**: For Router nodes, multiple unconditional signals all emit simultaneously (fan-out pattern). For LLM/Agent nodes with multiple signals, the LLM can select any/all that apply—including none.
125
+ > **Note**: For Router nodes, multiple unconditional signals all emit simultaneously (fan-out pattern). For LLM/Agent nodes with multiple signals, the LLM must select one - use Jinja conditions like `{{ true }}` if you want all signals to emit.
126
126
 
127
127
  ### Mode 2: Jinja Template (Programmatic)
128
128
 
@@ -207,9 +207,8 @@ The behavior depends on the node type:
207
207
  │ └─ Zero signals? → Nothing emitted │
208
208
  │ └─ Single signal? → Emit unconditionally │
209
209
  │ └─ Multiple signals? │
210
- │ └─ LLM selects ANY/ALL that apply
210
+ │ └─ LLM selects ONE signal
211
211
  │ (uses conditions as semantic descriptions) │
212
- │ (can select none, one, or multiple) │
213
212
  │ │
214
213
  └─────────────────────────────────────────────────────────────┘
215
214
 
@@ -301,7 +300,7 @@ example_workflow:
301
300
  condition: "The message is factual, neutral, or emotionally ambiguous"
302
301
  ```
303
302
 
304
- **LLM Selection Mechanism**: SOE adds a `selected_signals` field to the response model, allowing the LLM to select any/all signals that apply. The condition text serves as the description.
303
+ **LLM Selection Mechanism**: SOE adds a `selected_signal` field to the response model, forcing the LLM to choose from the options. The condition text serves as the description.
305
304
 
306
305
  ---
307
306
 
@@ -628,26 +627,26 @@ When the child updates these keys, they're automatically copied to the parent's
628
627
 
629
628
  ## LLM Signal Selection: Under the Hood
630
629
 
631
- When the LLM selects signals, SOE:
630
+ When the LLM selects a signal, SOE:
632
631
 
633
- 1. **Builds a response model** with a `selected_signals` field (list):
632
+ 1. **Builds a response model** with a `selected_signal` field:
634
633
  ```python
635
634
  class Response(BaseModel):
636
635
  response: str
637
- selected_signals: List[Literal["POSITIVE", "NEGATIVE", "NEUTRAL"]] = []
636
+ selected_signal: Literal["POSITIVE", "NEGATIVE", "NEUTRAL"]
638
637
  ```
639
638
 
640
639
  2. **Provides descriptions** from the `condition` field:
641
640
  ```
642
- Select ALL signals that apply (can be none, one, or multiple):
641
+ Select one of these signals based on your response:
643
642
  - POSITIVE: The message expresses positive sentiment
644
643
  - NEGATIVE: The message expresses negative sentiment
645
644
  - NEUTRAL: The message is neutral
646
645
  ```
647
646
 
648
- 3. **Extracts the selection** and emits all selected signals (can be empty).
647
+ 3. **Extracts the selection** and emits that signal.
649
648
 
650
- This is why plain-text conditions are called "semantic"—the LLM understands the descriptions and selects all that apply.
649
+ This is why plain-text conditions are called "semantic"—the LLM understands the description and makes a judgment call.
651
650
 
652
651
  ---
653
652