soe-ai 0.2.0b2__tar.gz → 0.2.0b3__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.2.0b2 → soe_ai-0.2.0b3}/PKG-INFO +1 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/pyproject.toml +1 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/broker.py +14 -32
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_01_tool.md +52 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_02_llm.md +5 -5
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/primitives/node_reference.md +1 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/primitives/signals.md +10 -9
- soe_ai-0.2.0b3/soe/docs_index.py +2 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/inheritance.py +42 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/factory.py +1 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/stages/response.py +3 -3
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/types.py +1 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/response_builder.py +12 -10
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/signal_emission.py +6 -10
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/factory.py +3 -3
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/state.py +21 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/validation/config.py +15 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/validation/__init__.py +7 -1
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/validation/config.py +22 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe_ai.egg-info/PKG-INFO +1 -1
- soe_ai-0.2.0b2/soe/docs_index.py +0 -2
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/LICENSE +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/README.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/setup.cfg +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_add_signal.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_call_tool.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_copy_context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_explore_docs.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_get_available_tools.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_get_context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_get_context_schema.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_get_identities.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_get_workflows.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_inject_context_schema_field.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_inject_identity.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_inject_node.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_inject_workflow.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_list_contexts.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_remove_context_schema_field.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_remove_identity.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_remove_node.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_remove_workflow.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/builtin_tools/soe_update_context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/_config.yml +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/guide_fanout_and_aggregations.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/guide_inheritance.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/hybrid_intelligence.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/index.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/operational.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/self_evolving_workflows.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/advanced_patterns/swarm_intelligence.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/builtins/context.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/builtins/context_schema.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/builtins/identity.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/builtins/soe_explore_docs.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/builtins/tools.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/builtins/workflows.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_00_getting_started.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_03_router.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_04_patterns.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_05_agent.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_06_schema.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_07_identity.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_08_child.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_09_ecosystem.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_10_infrastructure.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/guide_11_builtins.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/index.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/primitives/backends.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/primitives/context.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/docs/primitives/primitives.md +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/init.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/child_context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/context_fields.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/jinja_render.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/parent_sync.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/register_event.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/schema_validation.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/lib/yaml_parser.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/factory.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/in_memory/context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/in_memory/conversation_history.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/in_memory/identity.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/in_memory/schema.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/in_memory/telemetry.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/in_memory/workflow.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/storage/context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/storage/conversation_history.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/storage/identity.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/storage/schema.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/storage/telemetry.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/local_backends/storage/workflow.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/lib/loop_handlers.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/lib/loop_state.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/lib/prompts.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/lib/tools.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/stages/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/stages/parameter.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/stages/router.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/state.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/validation/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/validation/config.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/agent/validation/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/child/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/child/factory.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/child/state.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/child/validation/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/child/validation/config.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/child/validation/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/conditions.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/context.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/conversation_history.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/identity.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/llm_resolver.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/output.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/signals.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/lib/tools.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/state.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/types.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/validation/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/validation/config.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/llm/validation/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/router/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/router/factory.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/router/state.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/router/validation/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/router/validation/config.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/router/validation/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/factory.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/lib/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/lib/conditions.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/lib/failure.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/lib/parameters.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/types.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/validation/__init__.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/nodes/tool/validation/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/types.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/validation/jinja.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe/validation/operational.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe_ai.egg-info/SOURCES.txt +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe_ai.egg-info/dependency_links.txt +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe_ai.egg-info/requires.txt +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/soe_ai.egg-info/top_level.txt +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/tests/test_local_storage_backends.py +0 -0
- {soe_ai-0.2.0b2 → soe_ai-0.2.0b3}/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.2.
|
|
7
|
+
version = "0.2.0b3"
|
|
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,15 +4,18 @@ 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
|
|
8
7
|
from .lib.parent_sync import get_signals_for_parent
|
|
9
8
|
from .lib.inheritance import (
|
|
10
9
|
inherit_config,
|
|
11
|
-
inherit_context,
|
|
12
10
|
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,
|
|
13
18
|
)
|
|
14
|
-
from .validation import validate_config, validate_operational, validate_orchestrate_params
|
|
15
|
-
from .types import WorkflowValidationError
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
def orchestrate(
|
|
@@ -70,17 +73,15 @@ def orchestrate(
|
|
|
70
73
|
|
|
71
74
|
id = str(uuid4())
|
|
72
75
|
|
|
76
|
+
parsed_registry = {}
|
|
73
77
|
if inherit_config_from_id:
|
|
74
78
|
register_event(
|
|
75
79
|
backends, id, EventTypes.CONFIG_INHERITANCE_START,
|
|
76
80
|
{"source_execution_id": inherit_config_from_id}
|
|
77
81
|
)
|
|
78
82
|
parsed_registry = inherit_config(inherit_config_from_id, id, backends)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
parsed_config = parse_yaml(config)
|
|
82
|
-
parsed_registry = extract_and_save_config_sections(parsed_config, id, backends)
|
|
83
|
-
else:
|
|
83
|
+
|
|
84
|
+
if config:
|
|
84
85
|
validate_config(config)
|
|
85
86
|
parsed_config = parse_yaml(config)
|
|
86
87
|
parsed_registry = extract_and_save_config_sections(parsed_config, id, backends)
|
|
@@ -92,32 +93,13 @@ def orchestrate(
|
|
|
92
93
|
|
|
93
94
|
backends.workflow.save_workflows_registry(id, parsed_registry)
|
|
94
95
|
|
|
95
|
-
|
|
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
|
-
)
|
|
96
|
+
validate_initial_workflow(initial_workflow_name, parsed_registry)
|
|
101
97
|
|
|
102
98
|
backends.workflow.save_current_workflow_name(id, initial_workflow_name)
|
|
103
99
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
}
|
|
100
|
+
context = prepare_initial_context(
|
|
101
|
+
id, initial_context, backends, inherit_context_from_id
|
|
102
|
+
)
|
|
121
103
|
|
|
122
104
|
context = add_operational_state(id, context)
|
|
123
105
|
backends.context.save_context(id, context)
|
|
@@ -39,6 +39,58 @@ 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
|
+
|
|
42
94
|
### Understanding context_parameter_field
|
|
43
95
|
|
|
44
96
|
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 signals 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: "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)
|
|
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 any/all signals that apply based on the descriptions |
|
|
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 select which signals apply (multi-select)
|
|
127
127
|
|
|
128
128
|
## Testing LLM Nodes
|
|
129
129
|
|
|
@@ -44,6 +44,7 @@ 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) |
|
|
47
48
|
| `context_parameter_field` | `str` | ✗ | ✗ | ✗ | **O** | ✗ | Context field containing tool kwargs |
|
|
48
49
|
|
|
49
50
|
### 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 can select any/all that apply—including none.
|
|
126
126
|
|
|
127
127
|
### Mode 2: Jinja Template (Programmatic)
|
|
128
128
|
|
|
@@ -207,8 +207,9 @@ 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 ANY/ALL that apply │
|
|
211
211
|
│ (uses conditions as semantic descriptions) │
|
|
212
|
+
│ (can select none, one, or multiple) │
|
|
212
213
|
│ │
|
|
213
214
|
└─────────────────────────────────────────────────────────────┘
|
|
214
215
|
|
|
@@ -300,7 +301,7 @@ example_workflow:
|
|
|
300
301
|
condition: "The message is factual, neutral, or emotionally ambiguous"
|
|
301
302
|
```
|
|
302
303
|
|
|
303
|
-
**LLM Selection Mechanism**: SOE adds a `
|
|
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.
|
|
304
305
|
|
|
305
306
|
---
|
|
306
307
|
|
|
@@ -627,26 +628,26 @@ When the child updates these keys, they're automatically copied to the parent's
|
|
|
627
628
|
|
|
628
629
|
## LLM Signal Selection: Under the Hood
|
|
629
630
|
|
|
630
|
-
When the LLM selects
|
|
631
|
+
When the LLM selects signals, SOE:
|
|
631
632
|
|
|
632
|
-
1. **Builds a response model** with a `
|
|
633
|
+
1. **Builds a response model** with a `selected_signals` field (list):
|
|
633
634
|
```python
|
|
634
635
|
class Response(BaseModel):
|
|
635
636
|
response: str
|
|
636
|
-
|
|
637
|
+
selected_signals: List[Literal["POSITIVE", "NEGATIVE", "NEUTRAL"]] = []
|
|
637
638
|
```
|
|
638
639
|
|
|
639
640
|
2. **Provides descriptions** from the `condition` field:
|
|
640
641
|
```
|
|
641
|
-
Select
|
|
642
|
+
Select ALL signals that apply (can be none, one, or multiple):
|
|
642
643
|
- POSITIVE: The message expresses positive sentiment
|
|
643
644
|
- NEGATIVE: The message expresses negative sentiment
|
|
644
645
|
- NEUTRAL: The message is neutral
|
|
645
646
|
```
|
|
646
647
|
|
|
647
|
-
3. **Extracts the selection** and emits
|
|
648
|
+
3. **Extracts the selection** and emits all selected signals (can be empty).
|
|
648
649
|
|
|
649
|
-
This is why plain-text conditions are called "semantic"—the LLM understands the
|
|
650
|
+
This is why plain-text conditions are called "semantic"—the LLM understands the descriptions and selects all that apply.
|
|
650
651
|
|
|
651
652
|
---
|
|
652
653
|
|