soe-ai 0.2.0b1__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.
- soe/__init__.py +50 -0
- soe/broker.py +168 -0
- soe/builtin_tools/__init__.py +51 -0
- soe/builtin_tools/soe_add_signal.py +82 -0
- soe/builtin_tools/soe_call_tool.py +111 -0
- soe/builtin_tools/soe_copy_context.py +80 -0
- soe/builtin_tools/soe_explore_docs.py +290 -0
- soe/builtin_tools/soe_get_available_tools.py +42 -0
- soe/builtin_tools/soe_get_context.py +50 -0
- soe/builtin_tools/soe_get_context_schema.py +56 -0
- soe/builtin_tools/soe_get_identities.py +63 -0
- soe/builtin_tools/soe_get_workflows.py +63 -0
- soe/builtin_tools/soe_inject_context_schema_field.py +80 -0
- soe/builtin_tools/soe_inject_identity.py +64 -0
- soe/builtin_tools/soe_inject_node.py +86 -0
- soe/builtin_tools/soe_inject_workflow.py +105 -0
- soe/builtin_tools/soe_list_contexts.py +73 -0
- soe/builtin_tools/soe_remove_context_schema_field.py +61 -0
- soe/builtin_tools/soe_remove_identity.py +61 -0
- soe/builtin_tools/soe_remove_node.py +72 -0
- soe/builtin_tools/soe_remove_workflow.py +62 -0
- soe/builtin_tools/soe_update_context.py +54 -0
- soe/docs/_config.yml +10 -0
- soe/docs/advanced_patterns/guide_fanout_and_aggregations.md +318 -0
- soe/docs/advanced_patterns/guide_inheritance.md +435 -0
- soe/docs/advanced_patterns/hybrid_intelligence.md +237 -0
- soe/docs/advanced_patterns/index.md +49 -0
- soe/docs/advanced_patterns/operational.md +781 -0
- soe/docs/advanced_patterns/self_evolving_workflows.md +385 -0
- soe/docs/advanced_patterns/swarm_intelligence.md +211 -0
- soe/docs/builtins/context.md +164 -0
- soe/docs/builtins/context_schema.md +158 -0
- soe/docs/builtins/identity.md +139 -0
- soe/docs/builtins/soe_explore_docs.md +135 -0
- soe/docs/builtins/tools.md +164 -0
- soe/docs/builtins/workflows.md +199 -0
- soe/docs/guide_00_getting_started.md +341 -0
- soe/docs/guide_01_tool.md +206 -0
- soe/docs/guide_02_llm.md +143 -0
- soe/docs/guide_03_router.md +146 -0
- soe/docs/guide_04_patterns.md +475 -0
- soe/docs/guide_05_agent.md +159 -0
- soe/docs/guide_06_schema.md +397 -0
- soe/docs/guide_07_identity.md +540 -0
- soe/docs/guide_08_child.md +612 -0
- soe/docs/guide_09_ecosystem.md +690 -0
- soe/docs/guide_10_infrastructure.md +427 -0
- soe/docs/guide_11_builtins.md +126 -0
- soe/docs/index.md +104 -0
- soe/docs/primitives/backends.md +281 -0
- soe/docs/primitives/context.md +256 -0
- soe/docs/primitives/node_reference.md +259 -0
- soe/docs/primitives/primitives.md +331 -0
- soe/docs/primitives/signals.md +865 -0
- soe/docs_index.py +2 -0
- soe/init.py +165 -0
- soe/lib/__init__.py +0 -0
- soe/lib/child_context.py +46 -0
- soe/lib/context_fields.py +51 -0
- soe/lib/inheritance.py +172 -0
- soe/lib/jinja_render.py +113 -0
- soe/lib/operational.py +51 -0
- soe/lib/parent_sync.py +71 -0
- soe/lib/register_event.py +75 -0
- soe/lib/schema_validation.py +134 -0
- soe/lib/yaml_parser.py +14 -0
- soe/local_backends/__init__.py +18 -0
- soe/local_backends/factory.py +124 -0
- soe/local_backends/in_memory/context.py +38 -0
- soe/local_backends/in_memory/conversation_history.py +60 -0
- soe/local_backends/in_memory/identity.py +52 -0
- soe/local_backends/in_memory/schema.py +40 -0
- soe/local_backends/in_memory/telemetry.py +38 -0
- soe/local_backends/in_memory/workflow.py +33 -0
- soe/local_backends/storage/context.py +57 -0
- soe/local_backends/storage/conversation_history.py +82 -0
- soe/local_backends/storage/identity.py +118 -0
- soe/local_backends/storage/schema.py +96 -0
- soe/local_backends/storage/telemetry.py +72 -0
- soe/local_backends/storage/workflow.py +56 -0
- soe/nodes/__init__.py +13 -0
- soe/nodes/agent/__init__.py +10 -0
- soe/nodes/agent/factory.py +134 -0
- soe/nodes/agent/lib/loop_handlers.py +150 -0
- soe/nodes/agent/lib/loop_state.py +157 -0
- soe/nodes/agent/lib/prompts.py +65 -0
- soe/nodes/agent/lib/tools.py +35 -0
- soe/nodes/agent/stages/__init__.py +12 -0
- soe/nodes/agent/stages/parameter.py +37 -0
- soe/nodes/agent/stages/response.py +54 -0
- soe/nodes/agent/stages/router.py +37 -0
- soe/nodes/agent/state.py +111 -0
- soe/nodes/agent/types.py +66 -0
- soe/nodes/agent/validation/__init__.py +11 -0
- soe/nodes/agent/validation/config.py +95 -0
- soe/nodes/agent/validation/operational.py +24 -0
- soe/nodes/child/__init__.py +3 -0
- soe/nodes/child/factory.py +61 -0
- soe/nodes/child/state.py +59 -0
- soe/nodes/child/validation/__init__.py +11 -0
- soe/nodes/child/validation/config.py +126 -0
- soe/nodes/child/validation/operational.py +28 -0
- soe/nodes/lib/conditions.py +71 -0
- soe/nodes/lib/context.py +24 -0
- soe/nodes/lib/conversation_history.py +77 -0
- soe/nodes/lib/identity.py +64 -0
- soe/nodes/lib/llm_resolver.py +142 -0
- soe/nodes/lib/output.py +68 -0
- soe/nodes/lib/response_builder.py +91 -0
- soe/nodes/lib/signal_emission.py +79 -0
- soe/nodes/lib/signals.py +54 -0
- soe/nodes/lib/tools.py +100 -0
- soe/nodes/llm/__init__.py +7 -0
- soe/nodes/llm/factory.py +103 -0
- soe/nodes/llm/state.py +76 -0
- soe/nodes/llm/types.py +12 -0
- soe/nodes/llm/validation/__init__.py +11 -0
- soe/nodes/llm/validation/config.py +89 -0
- soe/nodes/llm/validation/operational.py +23 -0
- soe/nodes/router/__init__.py +3 -0
- soe/nodes/router/factory.py +37 -0
- soe/nodes/router/state.py +32 -0
- soe/nodes/router/validation/__init__.py +11 -0
- soe/nodes/router/validation/config.py +58 -0
- soe/nodes/router/validation/operational.py +16 -0
- soe/nodes/tool/factory.py +66 -0
- soe/nodes/tool/lib/__init__.py +11 -0
- soe/nodes/tool/lib/conditions.py +35 -0
- soe/nodes/tool/lib/failure.py +28 -0
- soe/nodes/tool/lib/parameters.py +67 -0
- soe/nodes/tool/state.py +66 -0
- soe/nodes/tool/types.py +27 -0
- soe/nodes/tool/validation/__init__.py +15 -0
- soe/nodes/tool/validation/config.py +132 -0
- soe/nodes/tool/validation/operational.py +16 -0
- soe/types.py +209 -0
- soe/validation/__init__.py +18 -0
- soe/validation/config.py +195 -0
- soe/validation/jinja.py +54 -0
- soe/validation/operational.py +110 -0
- soe_ai-0.2.0b1.dist-info/METADATA +262 -0
- soe_ai-0.2.0b1.dist-info/RECORD +145 -0
- soe_ai-0.2.0b1.dist-info/WHEEL +5 -0
- soe_ai-0.2.0b1.dist-info/licenses/LICENSE +21 -0
- soe_ai-0.2.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Built-in identity injection tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, Callable
|
|
4
|
+
from ..types import EventTypes
|
|
5
|
+
from ..lib.register_event import register_event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_soe_inject_identity_tool(
|
|
9
|
+
execution_id: str,
|
|
10
|
+
backends,
|
|
11
|
+
tools_registry: dict = None,
|
|
12
|
+
) -> Callable:
|
|
13
|
+
"""
|
|
14
|
+
Factory function to create soe_inject_identity tool.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
execution_id: ID to access identity data via backends
|
|
18
|
+
backends: Backend services to fetch/update identities
|
|
19
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Configured soe_inject_identity function that can add/update identities
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def soe_inject_identity(identity_name: str, system_prompt: str) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Add or update an identity definition.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
identity_name: Name/key for the identity
|
|
31
|
+
system_prompt: The system prompt text for this identity
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Success confirmation with identity info and action taken
|
|
35
|
+
"""
|
|
36
|
+
identities = backends.identity.get_identities(execution_id)
|
|
37
|
+
|
|
38
|
+
if identities is None:
|
|
39
|
+
identities = {}
|
|
40
|
+
|
|
41
|
+
action = "updated" if identity_name in identities else "created"
|
|
42
|
+
|
|
43
|
+
identities[identity_name] = system_prompt
|
|
44
|
+
backends.identity.save_identities(execution_id, identities)
|
|
45
|
+
|
|
46
|
+
register_event(
|
|
47
|
+
backends,
|
|
48
|
+
execution_id,
|
|
49
|
+
EventTypes.NODE_EXECUTION,
|
|
50
|
+
{
|
|
51
|
+
"tool": "soe_inject_identity",
|
|
52
|
+
"identity_name": identity_name,
|
|
53
|
+
"action": action,
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
"success": True,
|
|
59
|
+
"identity_name": identity_name,
|
|
60
|
+
"action": action,
|
|
61
|
+
"message": f"Successfully {action} identity '{identity_name}'",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return soe_inject_identity
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Built-in node configuration injection tool."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any, Callable
|
|
5
|
+
from ..types import EventTypes
|
|
6
|
+
from ..lib.register_event import register_event
|
|
7
|
+
from ..lib.yaml_parser import parse_yaml
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_soe_inject_node_tool(
|
|
11
|
+
execution_id: str,
|
|
12
|
+
backends,
|
|
13
|
+
tools_registry: dict = None,
|
|
14
|
+
) -> Callable:
|
|
15
|
+
"""
|
|
16
|
+
Factory function to create soe_inject_node tool with workflow access
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
execution_id: ID to access workflow data via backends
|
|
20
|
+
backends: Backend services to fetch/update workflows
|
|
21
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Configured soe_inject_node function that can inject node config into workflows
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def soe_soe_inject_node(
|
|
28
|
+
workflow_name: str, node_name: str, node_config_data: str
|
|
29
|
+
) -> Dict[str, Any]:
|
|
30
|
+
"""
|
|
31
|
+
Built-in tool: Inject a node configuration into an existing workflow
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
workflow_name: Name of the workflow to modify
|
|
35
|
+
node_name: Name of the node to inject
|
|
36
|
+
node_config_data: YAML or JSON string containing the node configuration
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Success confirmation with injected node info
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# Get current workflows registry and validate workflow exists
|
|
43
|
+
workflows_registry = backends.workflow.get_workflows_registry(execution_id)
|
|
44
|
+
|
|
45
|
+
if workflow_name not in workflows_registry:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
f"Workflow '{workflow_name}' not found in workflows registry"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Parse the node configuration data (prefer JSON, fallback to YAML)
|
|
51
|
+
node_config = None
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
node_config = json.loads(node_config_data)
|
|
55
|
+
except json.JSONDecodeError:
|
|
56
|
+
node_config = parse_yaml(node_config_data)
|
|
57
|
+
|
|
58
|
+
if not isinstance(node_config, dict):
|
|
59
|
+
raise ValueError("Node configuration must be a dictionary/object")
|
|
60
|
+
|
|
61
|
+
# Inject the node configuration into the workflow
|
|
62
|
+
target_workflow = workflows_registry[workflow_name]
|
|
63
|
+
target_workflow[node_name] = node_config
|
|
64
|
+
|
|
65
|
+
# Save the updated workflows registry back
|
|
66
|
+
backends.workflow.save_workflows_registry(execution_id, workflows_registry)
|
|
67
|
+
|
|
68
|
+
register_event(
|
|
69
|
+
backends,
|
|
70
|
+
execution_id,
|
|
71
|
+
EventTypes.NODE_EXECUTION,
|
|
72
|
+
{
|
|
73
|
+
"tool": "soe_inject_node",
|
|
74
|
+
"workflow_name": workflow_name,
|
|
75
|
+
"node_name": node_name,
|
|
76
|
+
},
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
"injected": True,
|
|
81
|
+
"workflow_name": workflow_name,
|
|
82
|
+
"node_name": node_name,
|
|
83
|
+
"message": f"Successfully injected node '{node_name}' into workflow '{workflow_name}'",
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return soe_soe_inject_node
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Built-in workflow injection tool."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any, Callable
|
|
5
|
+
from ..types import EventTypes
|
|
6
|
+
from ..lib.register_event import register_event
|
|
7
|
+
from ..lib.yaml_parser import parse_yaml
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_soe_inject_workflow_tool(
|
|
11
|
+
execution_id: str,
|
|
12
|
+
backends,
|
|
13
|
+
tools_registry: dict = None,
|
|
14
|
+
) -> Callable:
|
|
15
|
+
"""
|
|
16
|
+
Factory function to create soe_inject_workflow tool with workflow access
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
execution_id: ID to access workflow data via backends
|
|
20
|
+
backends: Backend services to fetch/update workflows
|
|
21
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Configured soe_inject_workflow function that can inject new workflows
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def soe_inject_workflow(workflow_name: str, workflow_data: str) -> Dict[str, Any]:
|
|
28
|
+
"""
|
|
29
|
+
Built-in tool: Inject a new workflow into the global workflows configuration
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
workflow_name: Name of the new workflow to inject
|
|
33
|
+
workflow_data: JSON or YAML string containing the workflow definition
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Success confirmation with injected workflow info
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
# Parse the workflow definition (prefer JSON, fallback to YAML)
|
|
40
|
+
parsed_workflow = None
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
parsed_workflow = json.loads(workflow_data)
|
|
44
|
+
except json.JSONDecodeError:
|
|
45
|
+
parsed_workflow = parse_yaml(workflow_data)
|
|
46
|
+
|
|
47
|
+
if not isinstance(parsed_workflow, dict):
|
|
48
|
+
raise ValueError("Workflow data must be a dictionary/object")
|
|
49
|
+
|
|
50
|
+
# Determine the workflow definition to inject
|
|
51
|
+
workflow_definition = None
|
|
52
|
+
|
|
53
|
+
# If workflow_name is specified in the parsed data, use that specific workflow
|
|
54
|
+
if workflow_name in parsed_workflow:
|
|
55
|
+
workflow_definition = parsed_workflow[workflow_name]
|
|
56
|
+
else:
|
|
57
|
+
# Check if all keys in parsed_workflow look like node names (have node_type)
|
|
58
|
+
all_nodes = True
|
|
59
|
+
for _, value in parsed_workflow.items():
|
|
60
|
+
if not isinstance(value, dict) or "node_type" not in value:
|
|
61
|
+
all_nodes = False
|
|
62
|
+
break
|
|
63
|
+
|
|
64
|
+
if all_nodes:
|
|
65
|
+
# All top-level keys are nodes, use the entire structure as the workflow
|
|
66
|
+
workflow_definition = parsed_workflow
|
|
67
|
+
elif len(parsed_workflow) == 1:
|
|
68
|
+
# Single non-node entry, assume it's a workflow container
|
|
69
|
+
first_workflow_key = list(parsed_workflow.keys())[0]
|
|
70
|
+
workflow_definition = parsed_workflow[first_workflow_key]
|
|
71
|
+
else:
|
|
72
|
+
# Multiple entries, assume entire structure is the workflow
|
|
73
|
+
workflow_definition = parsed_workflow
|
|
74
|
+
|
|
75
|
+
if not workflow_definition:
|
|
76
|
+
raise ValueError(f"No workflow definition found for injection")
|
|
77
|
+
|
|
78
|
+
# Validate the workflow before injecting
|
|
79
|
+
from ..validation.config import validate_workflow
|
|
80
|
+
validate_workflow(workflow_name, workflow_definition)
|
|
81
|
+
|
|
82
|
+
# Get current workflows registry via backends and inject new workflow
|
|
83
|
+
workflows_registry = backends.workflow.get_workflows_registry(execution_id)
|
|
84
|
+
workflows_registry[workflow_name] = workflow_definition
|
|
85
|
+
|
|
86
|
+
# Save the updated workflows registry back
|
|
87
|
+
backends.workflow.save_workflows_registry(execution_id, workflows_registry)
|
|
88
|
+
|
|
89
|
+
register_event(
|
|
90
|
+
backends,
|
|
91
|
+
execution_id,
|
|
92
|
+
EventTypes.NODE_EXECUTION,
|
|
93
|
+
{
|
|
94
|
+
"tool": "soe_inject_workflow",
|
|
95
|
+
"workflow_name": workflow_name,
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
"injected": True,
|
|
101
|
+
"workflow_name": workflow_name,
|
|
102
|
+
"message": f"Successfully injected workflow '{workflow_name}'",
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return soe_inject_workflow
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Built-in tool: list_contexts
|
|
3
|
+
Allows agents to list available execution contexts.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import List, Dict, Any
|
|
7
|
+
import os
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def create_soe_list_contexts_tool(backends, execution_id: str, tools_registry=None):
|
|
12
|
+
"""
|
|
13
|
+
Factory that creates a list_contexts tool bound to the current execution.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
backends: Backend instances (needs context backend)
|
|
17
|
+
execution_id: Current execution ID
|
|
18
|
+
tools_registry: Tool registry (unused, for interface compatibility)
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Configured tool function
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def list_contexts(include_current: bool = True) -> Dict[str, Any]:
|
|
25
|
+
"""
|
|
26
|
+
List available execution contexts.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
include_current: Whether to include current execution in list
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Dict with current_execution_id and list of context summaries
|
|
33
|
+
"""
|
|
34
|
+
result = {
|
|
35
|
+
"current_execution_id": execution_id,
|
|
36
|
+
"contexts": []
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Get context storage directory from backend
|
|
40
|
+
storage_dir = getattr(backends.context, 'storage_dir', None)
|
|
41
|
+
if not storage_dir or not os.path.exists(storage_dir):
|
|
42
|
+
return result
|
|
43
|
+
|
|
44
|
+
for filename in os.listdir(storage_dir):
|
|
45
|
+
if not filename.endswith('.json'):
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
ctx_id = filename.replace('.json', '')
|
|
49
|
+
|
|
50
|
+
if not include_current and ctx_id == execution_id:
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
# Read minimal info from each context
|
|
54
|
+
filepath = os.path.join(storage_dir, filename)
|
|
55
|
+
try:
|
|
56
|
+
with open(filepath, 'r') as f:
|
|
57
|
+
ctx = json.load(f)
|
|
58
|
+
|
|
59
|
+
# Get summary info
|
|
60
|
+
ops = ctx.get("__operational__", {})
|
|
61
|
+
result["contexts"].append({
|
|
62
|
+
"execution_id": ctx_id,
|
|
63
|
+
"is_current": ctx_id == execution_id,
|
|
64
|
+
"user_request": ctx.get("user_request", [])[-1] if ctx.get("user_request") else None,
|
|
65
|
+
"signals": ops.get("signals", [])[-5:], # Last 5 signals
|
|
66
|
+
"node_count": sum(ops.get("nodes", {}).values()),
|
|
67
|
+
})
|
|
68
|
+
except Exception:
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
return list_contexts
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Built-in context schema field removal tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, Callable
|
|
4
|
+
from ..types import EventTypes
|
|
5
|
+
from ..lib.register_event import register_event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_soe_remove_context_schema_field_tool(
|
|
9
|
+
execution_id: str,
|
|
10
|
+
backends,
|
|
11
|
+
tools_registry: dict = None,
|
|
12
|
+
) -> Callable:
|
|
13
|
+
"""
|
|
14
|
+
Factory function to create soe_remove_context_schema_field tool.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
execution_id: ID to access context schema data via backends
|
|
18
|
+
backends: Backend services to fetch/update context schema
|
|
19
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Configured soe_remove_context_schema_field function
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def soe_remove_context_schema_field(field_name: str) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Remove a field from the context schema.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
field_name: Name of the field to remove
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Success confirmation with removed field info
|
|
34
|
+
"""
|
|
35
|
+
schema = backends.context_schema.get_context_schema(execution_id)
|
|
36
|
+
|
|
37
|
+
if schema is None or field_name not in schema:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
f"Field '{field_name}' not found in context schema"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
del schema[field_name]
|
|
43
|
+
backends.context_schema.save_context_schema(execution_id, schema)
|
|
44
|
+
|
|
45
|
+
register_event(
|
|
46
|
+
backends,
|
|
47
|
+
execution_id,
|
|
48
|
+
EventTypes.NODE_EXECUTION,
|
|
49
|
+
{
|
|
50
|
+
"tool": "soe_remove_context_schema_field",
|
|
51
|
+
"field_name": field_name,
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
"removed": True,
|
|
57
|
+
"field_name": field_name,
|
|
58
|
+
"message": f"Successfully removed field '{field_name}' from context schema",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return soe_remove_context_schema_field
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Built-in identity removal tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, Callable
|
|
4
|
+
from ..types import EventTypes
|
|
5
|
+
from ..lib.register_event import register_event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_soe_remove_identity_tool(
|
|
9
|
+
execution_id: str,
|
|
10
|
+
backends,
|
|
11
|
+
tools_registry: dict = None,
|
|
12
|
+
) -> Callable:
|
|
13
|
+
"""
|
|
14
|
+
Factory function to create soe_remove_identity tool.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
execution_id: ID to access identity data via backends
|
|
18
|
+
backends: Backend services to fetch/update identities
|
|
19
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Configured soe_remove_identity function that can remove identities
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def soe_remove_identity(identity_name: str) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Remove an identity definition.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
identity_name: Name of the identity to remove
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Success confirmation with removed identity info
|
|
34
|
+
"""
|
|
35
|
+
identities = backends.identity.get_identities(execution_id)
|
|
36
|
+
|
|
37
|
+
if identities is None or identity_name not in identities:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
f"Identity '{identity_name}' not found"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
del identities[identity_name]
|
|
43
|
+
backends.identity.save_identities(execution_id, identities)
|
|
44
|
+
|
|
45
|
+
register_event(
|
|
46
|
+
backends,
|
|
47
|
+
execution_id,
|
|
48
|
+
EventTypes.NODE_EXECUTION,
|
|
49
|
+
{
|
|
50
|
+
"tool": "soe_remove_identity",
|
|
51
|
+
"identity_name": identity_name,
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
"removed": True,
|
|
57
|
+
"identity_name": identity_name,
|
|
58
|
+
"message": f"Successfully removed identity '{identity_name}'",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return soe_remove_identity
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Built-in node removal tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, Callable
|
|
4
|
+
from ..types import EventTypes
|
|
5
|
+
from ..lib.register_event import register_event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_soe_remove_node_tool(
|
|
9
|
+
execution_id: str,
|
|
10
|
+
backends,
|
|
11
|
+
tools_registry: dict = None,
|
|
12
|
+
) -> Callable:
|
|
13
|
+
"""
|
|
14
|
+
Factory function to create soe_remove_node tool with workflow access
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
execution_id: ID to access workflow data via backends
|
|
18
|
+
backends: Backend services to fetch/update workflows
|
|
19
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Configured soe_remove_node function that can remove nodes from workflows
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def soe_remove_node(workflow_name: str, node_name: str) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Built-in tool: Remove a node from an existing workflow
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
workflow_name: Name of the workflow to modify
|
|
31
|
+
node_name: Name of the node to remove
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Success confirmation with removed node info
|
|
35
|
+
"""
|
|
36
|
+
workflows_registry = backends.workflow.get_workflows_registry(execution_id)
|
|
37
|
+
|
|
38
|
+
if workflow_name not in workflows_registry:
|
|
39
|
+
raise ValueError(
|
|
40
|
+
f"Workflow '{workflow_name}' not found in workflows registry"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
target_workflow = workflows_registry[workflow_name]
|
|
44
|
+
|
|
45
|
+
if node_name not in target_workflow:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
f"Node '{node_name}' not found in workflow '{workflow_name}'"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
del target_workflow[node_name]
|
|
51
|
+
|
|
52
|
+
backends.workflow.save_workflows_registry(execution_id, workflows_registry)
|
|
53
|
+
|
|
54
|
+
register_event(
|
|
55
|
+
backends,
|
|
56
|
+
execution_id,
|
|
57
|
+
EventTypes.NODE_EXECUTION,
|
|
58
|
+
{
|
|
59
|
+
"tool": "soe_remove_node",
|
|
60
|
+
"workflow_name": workflow_name,
|
|
61
|
+
"node_name": node_name,
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
"removed": True,
|
|
67
|
+
"workflow_name": workflow_name,
|
|
68
|
+
"node_name": node_name,
|
|
69
|
+
"message": f"Successfully removed node '{node_name}' from workflow '{workflow_name}'",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return soe_remove_node
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Built-in workflow removal tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, Callable
|
|
4
|
+
from ..types import EventTypes
|
|
5
|
+
from ..lib.register_event import register_event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_soe_remove_workflow_tool(
|
|
9
|
+
execution_id: str,
|
|
10
|
+
backends,
|
|
11
|
+
tools_registry: dict = None,
|
|
12
|
+
) -> Callable:
|
|
13
|
+
"""
|
|
14
|
+
Factory function to create soe_remove_workflow tool with workflow access
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
execution_id: ID to access workflow data via backends
|
|
18
|
+
backends: Backend services to fetch/update workflows
|
|
19
|
+
tools_registry: Optional registry of available tools (unused by this tool)
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Configured soe_remove_workflow function that can remove workflows
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def soe_remove_workflow(workflow_name: str) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Built-in tool: Remove a workflow from the global workflows configuration
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
workflow_name: Name of the workflow to remove
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Success confirmation with removed workflow info
|
|
34
|
+
"""
|
|
35
|
+
workflows_registry = backends.workflow.get_workflows_registry(execution_id)
|
|
36
|
+
|
|
37
|
+
if workflow_name not in workflows_registry:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
f"Workflow '{workflow_name}' not found in workflows registry"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
del workflows_registry[workflow_name]
|
|
43
|
+
|
|
44
|
+
backends.workflow.save_workflows_registry(execution_id, workflows_registry)
|
|
45
|
+
|
|
46
|
+
register_event(
|
|
47
|
+
backends,
|
|
48
|
+
execution_id,
|
|
49
|
+
EventTypes.NODE_EXECUTION,
|
|
50
|
+
{
|
|
51
|
+
"tool": "soe_remove_workflow",
|
|
52
|
+
"workflow_name": workflow_name,
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
"removed": True,
|
|
58
|
+
"workflow_name": workflow_name,
|
|
59
|
+
"message": f"Successfully removed workflow '{workflow_name}'",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return soe_remove_workflow
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Built-in tool: update_context
|
|
3
|
+
Allows agents to write context fields dynamically.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, Dict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_soe_update_context_tool(backends, execution_id: str, tools_registry=None):
|
|
10
|
+
"""
|
|
11
|
+
Factory that creates an update_context tool bound to the current execution.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
backends: Backend instances (needs context backend)
|
|
15
|
+
execution_id: Current execution ID
|
|
16
|
+
tools_registry: Tool registry (unused, for interface compatibility)
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Configured tool function
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def update_context(updates: Dict[str, Any]) -> Dict[str, str]:
|
|
23
|
+
"""
|
|
24
|
+
Update context fields for the current execution.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
updates: Dictionary of field names to values to set
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Confirmation of updated fields
|
|
31
|
+
"""
|
|
32
|
+
if not updates:
|
|
33
|
+
return {"status": "no updates provided"}
|
|
34
|
+
|
|
35
|
+
# Don't allow updating operational fields
|
|
36
|
+
filtered_updates = {
|
|
37
|
+
k: v for k, v in updates.items()
|
|
38
|
+
if not k.startswith("__")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if not filtered_updates:
|
|
42
|
+
return {"status": "no valid updates (operational fields cannot be updated)"}
|
|
43
|
+
|
|
44
|
+
# Get current context and update
|
|
45
|
+
context = backends.context.get_context(execution_id)
|
|
46
|
+
context.update(filtered_updates)
|
|
47
|
+
backends.context.save_context(execution_id, context)
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
"status": "updated",
|
|
51
|
+
"fields": list(filtered_updates.keys())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return update_context
|
soe/docs/_config.yml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
title: SOE - Signal-driven Orchestration Engine
|
|
2
|
+
description: Infrastructure-agnostic AI workflow orchestration
|
|
3
|
+
theme: jekyll-theme-minimal
|
|
4
|
+
markdown: GFM
|
|
5
|
+
highlighter: rouge
|
|
6
|
+
|
|
7
|
+
# Navigation structure
|
|
8
|
+
header_pages:
|
|
9
|
+
- index.md
|
|
10
|
+
- guide_00_getting_started.md
|