soe-ai 0.1.4__tar.gz → 0.2.0b2__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.
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/PKG-INFO +1 -1
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/pyproject.toml +1 -1
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/broker.py +32 -14
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_01_tool.md +0 -52
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_02_llm.md +5 -5
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/primitives/node_reference.md +0 -1
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/primitives/signals.md +9 -10
- soe_ai-0.2.0b2/soe/docs_index.py +2 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/init.py +1 -7
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/inheritance.py +1 -42
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/factory.py +1 -1
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/stages/response.py +3 -3
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/types.py +1 -1
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/response_builder.py +10 -12
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/signal_emission.py +10 -6
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/factory.py +3 -3
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/state.py +1 -21
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/validation/config.py +0 -15
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/validation/__init__.py +1 -7
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/validation/config.py +0 -22
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe_ai.egg-info/PKG-INFO +1 -1
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe_ai.egg-info/SOURCES.txt +0 -1
- soe_ai-0.1.4/soe/docs_index.py +0 -2
- soe_ai-0.1.4/tests/test_setup_orchestration.py +0 -146
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/LICENSE +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/README.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/setup.cfg +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_add_signal.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_call_tool.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_copy_context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_explore_docs.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_get_available_tools.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_get_context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_get_context_schema.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_get_identities.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_get_workflows.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_inject_context_schema_field.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_inject_identity.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_inject_node.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_inject_workflow.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_list_contexts.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_remove_context_schema_field.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_remove_identity.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_remove_node.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_remove_workflow.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/builtin_tools/soe_update_context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/_config.yml +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/guide_fanout_and_aggregations.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/guide_inheritance.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/hybrid_intelligence.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/index.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/operational.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/self_evolving_workflows.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/advanced_patterns/swarm_intelligence.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/builtins/context.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/builtins/context_schema.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/builtins/identity.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/builtins/soe_explore_docs.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/builtins/tools.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/builtins/workflows.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_00_getting_started.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_03_router.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_04_patterns.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_05_agent.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_06_schema.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_07_identity.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_08_child.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_09_ecosystem.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_10_infrastructure.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/guide_11_builtins.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/index.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/primitives/backends.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/primitives/context.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/docs/primitives/primitives.md +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/child_context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/context_fields.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/jinja_render.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/parent_sync.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/register_event.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/schema_validation.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/lib/yaml_parser.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/factory.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/in_memory/context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/in_memory/conversation_history.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/in_memory/identity.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/in_memory/schema.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/in_memory/telemetry.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/in_memory/workflow.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/storage/context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/storage/conversation_history.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/storage/identity.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/storage/schema.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/storage/telemetry.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/local_backends/storage/workflow.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/lib/loop_handlers.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/lib/loop_state.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/lib/prompts.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/lib/tools.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/stages/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/stages/parameter.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/stages/router.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/state.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/validation/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/validation/config.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/agent/validation/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/child/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/child/factory.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/child/state.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/child/validation/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/child/validation/config.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/child/validation/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/conditions.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/context.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/conversation_history.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/identity.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/llm_resolver.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/output.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/signals.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/lib/tools.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/state.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/types.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/validation/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/validation/config.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/llm/validation/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/router/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/router/factory.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/router/state.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/router/validation/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/router/validation/config.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/router/validation/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/factory.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/lib/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/lib/conditions.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/lib/failure.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/lib/parameters.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/types.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/validation/__init__.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/nodes/tool/validation/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/types.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/validation/jinja.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe/validation/operational.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe_ai.egg-info/dependency_links.txt +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe_ai.egg-info/requires.txt +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/soe_ai.egg-info/top_level.txt +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/tests/test_local_storage_backends.py +0 -0
- {soe_ai-0.1.4 → soe_ai-0.2.0b2}/tests/test_validation_errors.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "soe-ai"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0b2"
|
|
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"
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
101
|
-
|
|
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)
|
|
@@ -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: "{{ context.current_user_id }}"
|
|
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
|
|
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: "
|
|
107
|
-
4. The LLM returns
|
|
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
|
|
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
|
|
126
|
+
- **No (plain text)**: Ask LLM to choose which signal best matches its output
|
|
127
127
|
|
|
128
128
|
## Testing LLM Nodes
|
|
129
129
|
|
|
@@ -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
|
|
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
|
|
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 `
|
|
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
|
|
630
|
+
When the LLM selects a signal, SOE:
|
|
632
631
|
|
|
633
|
-
1. **Builds a response model** with a `
|
|
632
|
+
1. **Builds a response model** with a `selected_signal` field:
|
|
634
633
|
```python
|
|
635
634
|
class Response(BaseModel):
|
|
636
635
|
response: str
|
|
637
|
-
|
|
636
|
+
selected_signal: Literal["POSITIVE", "NEGATIVE", "NEUTRAL"]
|
|
638
637
|
```
|
|
639
638
|
|
|
640
639
|
2. **Provides descriptions** from the `condition` field:
|
|
641
640
|
```
|
|
642
|
-
Select
|
|
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
|
|
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
|
|
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
|
|