soe-ai 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. soe/builtin_tools/__init__.py +39 -0
  2. soe/builtin_tools/soe_add_signal.py +82 -0
  3. soe/builtin_tools/soe_call_tool.py +111 -0
  4. soe/builtin_tools/soe_copy_context.py +80 -0
  5. soe/builtin_tools/soe_explore_docs.py +290 -0
  6. soe/builtin_tools/soe_get_available_tools.py +42 -0
  7. soe/builtin_tools/soe_get_context.py +50 -0
  8. soe/builtin_tools/soe_get_workflows.py +63 -0
  9. soe/builtin_tools/soe_inject_node.py +86 -0
  10. soe/builtin_tools/soe_inject_workflow.py +105 -0
  11. soe/builtin_tools/soe_list_contexts.py +73 -0
  12. soe/builtin_tools/soe_remove_node.py +72 -0
  13. soe/builtin_tools/soe_remove_workflow.py +62 -0
  14. soe/builtin_tools/soe_update_context.py +54 -0
  15. soe/docs/_config.yml +10 -0
  16. soe/docs/advanced_patterns/guide_fanout_and_aggregations.md +318 -0
  17. soe/docs/advanced_patterns/guide_inheritance.md +435 -0
  18. soe/docs/advanced_patterns/hybrid_intelligence.md +237 -0
  19. soe/docs/advanced_patterns/index.md +49 -0
  20. soe/docs/advanced_patterns/operational.md +781 -0
  21. soe/docs/advanced_patterns/self_evolving_workflows.md +385 -0
  22. soe/docs/advanced_patterns/swarm_intelligence.md +211 -0
  23. soe/docs/builtins/context.md +164 -0
  24. soe/docs/builtins/explore_docs.md +135 -0
  25. soe/docs/builtins/tools.md +164 -0
  26. soe/docs/builtins/workflows.md +199 -0
  27. soe/docs/guide_00_getting_started.md +341 -0
  28. soe/docs/guide_01_tool.md +206 -0
  29. soe/docs/guide_02_llm.md +143 -0
  30. soe/docs/guide_03_router.md +146 -0
  31. soe/docs/guide_04_patterns.md +475 -0
  32. soe/docs/guide_05_agent.md +159 -0
  33. soe/docs/guide_06_schema.md +397 -0
  34. soe/docs/guide_07_identity.md +540 -0
  35. soe/docs/guide_08_child.md +612 -0
  36. soe/docs/guide_09_ecosystem.md +690 -0
  37. soe/docs/guide_10_infrastructure.md +427 -0
  38. soe/docs/guide_11_builtins.md +118 -0
  39. soe/docs/index.md +104 -0
  40. soe/docs/primitives/backends.md +281 -0
  41. soe/docs/primitives/context.md +256 -0
  42. soe/docs/primitives/node_reference.md +259 -0
  43. soe/docs/primitives/primitives.md +331 -0
  44. soe/docs/primitives/signals.md +865 -0
  45. soe/docs_index.py +1 -1
  46. soe/lib/__init__.py +0 -0
  47. soe/lib/child_context.py +46 -0
  48. soe/lib/context_fields.py +51 -0
  49. soe/lib/inheritance.py +172 -0
  50. soe/lib/jinja_render.py +113 -0
  51. soe/lib/operational.py +51 -0
  52. soe/lib/parent_sync.py +71 -0
  53. soe/lib/register_event.py +75 -0
  54. soe/lib/schema_validation.py +134 -0
  55. soe/lib/yaml_parser.py +14 -0
  56. soe/local_backends/__init__.py +18 -0
  57. soe/local_backends/factory.py +124 -0
  58. soe/local_backends/in_memory/context.py +38 -0
  59. soe/local_backends/in_memory/conversation_history.py +60 -0
  60. soe/local_backends/in_memory/identity.py +52 -0
  61. soe/local_backends/in_memory/schema.py +40 -0
  62. soe/local_backends/in_memory/telemetry.py +38 -0
  63. soe/local_backends/in_memory/workflow.py +33 -0
  64. soe/local_backends/storage/context.py +57 -0
  65. soe/local_backends/storage/conversation_history.py +82 -0
  66. soe/local_backends/storage/identity.py +118 -0
  67. soe/local_backends/storage/schema.py +96 -0
  68. soe/local_backends/storage/telemetry.py +72 -0
  69. soe/local_backends/storage/workflow.py +56 -0
  70. soe/nodes/__init__.py +13 -0
  71. soe/nodes/agent/__init__.py +10 -0
  72. soe/nodes/agent/factory.py +134 -0
  73. soe/nodes/agent/lib/loop_handlers.py +150 -0
  74. soe/nodes/agent/lib/loop_state.py +157 -0
  75. soe/nodes/agent/lib/prompts.py +65 -0
  76. soe/nodes/agent/lib/tools.py +35 -0
  77. soe/nodes/agent/stages/__init__.py +12 -0
  78. soe/nodes/agent/stages/parameter.py +37 -0
  79. soe/nodes/agent/stages/response.py +54 -0
  80. soe/nodes/agent/stages/router.py +37 -0
  81. soe/nodes/agent/state.py +111 -0
  82. soe/nodes/agent/types.py +66 -0
  83. soe/nodes/agent/validation/__init__.py +11 -0
  84. soe/nodes/agent/validation/config.py +95 -0
  85. soe/nodes/agent/validation/operational.py +24 -0
  86. soe/nodes/child/__init__.py +3 -0
  87. soe/nodes/child/factory.py +61 -0
  88. soe/nodes/child/state.py +59 -0
  89. soe/nodes/child/validation/__init__.py +11 -0
  90. soe/nodes/child/validation/config.py +126 -0
  91. soe/nodes/child/validation/operational.py +28 -0
  92. soe/nodes/lib/conditions.py +71 -0
  93. soe/nodes/lib/context.py +24 -0
  94. soe/nodes/lib/conversation_history.py +77 -0
  95. soe/nodes/lib/identity.py +64 -0
  96. soe/nodes/lib/llm_resolver.py +142 -0
  97. soe/nodes/lib/output.py +68 -0
  98. soe/nodes/lib/response_builder.py +91 -0
  99. soe/nodes/lib/signal_emission.py +79 -0
  100. soe/nodes/lib/signals.py +54 -0
  101. soe/nodes/lib/tools.py +100 -0
  102. soe/nodes/llm/__init__.py +7 -0
  103. soe/nodes/llm/factory.py +103 -0
  104. soe/nodes/llm/state.py +76 -0
  105. soe/nodes/llm/types.py +12 -0
  106. soe/nodes/llm/validation/__init__.py +11 -0
  107. soe/nodes/llm/validation/config.py +89 -0
  108. soe/nodes/llm/validation/operational.py +23 -0
  109. soe/nodes/router/__init__.py +3 -0
  110. soe/nodes/router/factory.py +37 -0
  111. soe/nodes/router/state.py +32 -0
  112. soe/nodes/router/validation/__init__.py +11 -0
  113. soe/nodes/router/validation/config.py +58 -0
  114. soe/nodes/router/validation/operational.py +16 -0
  115. soe/nodes/tool/factory.py +66 -0
  116. soe/nodes/tool/lib/__init__.py +11 -0
  117. soe/nodes/tool/lib/conditions.py +35 -0
  118. soe/nodes/tool/lib/failure.py +28 -0
  119. soe/nodes/tool/lib/parameters.py +67 -0
  120. soe/nodes/tool/state.py +66 -0
  121. soe/nodes/tool/types.py +27 -0
  122. soe/nodes/tool/validation/__init__.py +15 -0
  123. soe/nodes/tool/validation/config.py +132 -0
  124. soe/nodes/tool/validation/operational.py +16 -0
  125. soe/validation/__init__.py +18 -0
  126. soe/validation/config.py +195 -0
  127. soe/validation/jinja.py +54 -0
  128. soe/validation/operational.py +110 -0
  129. {soe_ai-0.1.1.dist-info → soe_ai-0.1.3.dist-info}/METADATA +5 -5
  130. soe_ai-0.1.3.dist-info/RECORD +137 -0
  131. {soe_ai-0.1.1.dist-info → soe_ai-0.1.3.dist-info}/WHEEL +1 -1
  132. soe_ai-0.1.1.dist-info/RECORD +0 -10
  133. {soe_ai-0.1.1.dist-info → soe_ai-0.1.3.dist-info}/licenses/LICENSE +0 -0
  134. {soe_ai-0.1.1.dist-info → soe_ai-0.1.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,427 @@
1
+ # SOE Guide: Chapter 10 - Custom Infrastructure
2
+
3
+ ## Introduction
4
+
5
+ SOE is **infrastructure agnostic** by design. The core orchestration engine doesn't care *where* your data lives or *how* signals are broadcast—it only requires that you provide implementations that follow the defined protocols.
6
+
7
+ This chapter covers two distinct infrastructure concerns:
8
+
9
+ 1. **Persistent Infrastructure (Backends)** — Where data is stored
10
+ 2. **Communication Infrastructure (Callers)** — How signals are broadcast
11
+
12
+ ---
13
+
14
+ ## Part 1: Persistent Infrastructure (Backends)
15
+
16
+ ### What Are Backends?
17
+
18
+ Backends are the **persistence layer** of SOE. They store:
19
+
20
+ | Backend | Purpose | Example Use Cases |
21
+ |---------|---------|-------------------|
22
+ | `context` | Workflow execution state | DynamoDB, Redis, PostgreSQL |
23
+ | `workflow` | Workflow definitions | S3, local files, database |
24
+ | `telemetry` | Logs and events | Datadog, CloudWatch, Elasticsearch |
25
+ | `conversation_history` | LLM chat history | MongoDB, PostgreSQL, text files |
26
+ | `schema` | Context validation schemas | Database, config files |
27
+
28
+ ### Built-in Backends
29
+
30
+ SOE ships with two backend implementations for immediate use:
31
+
32
+ #### In-Memory Backends
33
+ ```python
34
+ from soe.local_backends import create_in_memory_backends
35
+
36
+ backends = create_in_memory_backends()
37
+ ```
38
+ - **Use case**: Unit tests, prototyping
39
+ - **Pros**: Fast, no setup required
40
+ - **Cons**: Data lost on process exit, not distributable
41
+
42
+ #### Local File Backends
43
+ ```python
44
+ from soe.local_backends import create_local_backends
45
+
46
+ backends = create_local_backends(
47
+ context_storage_dir="./orchestration_data/contexts",
48
+ workflow_storage_dir="./orchestration_data/workflows",
49
+ telemetry_storage_dir="./orchestration_data/telemetry", # Optional
50
+ conversation_history_storage_dir="./orchestration_data/conversations", # Optional
51
+ schema_storage_dir="./orchestration_data/schemas", # Optional
52
+ )
53
+ ```
54
+ - **Use case**: Local development, debugging, simple deployments
55
+ - **Pros**: Persistent, human-readable (JSON files)
56
+ - **Cons**: Not distributable, no concurrent access
57
+
58
+ ### The Backend Protocols
59
+
60
+ Each backend type follows a Python `Protocol` (structural typing). Here are the required interfaces:
61
+
62
+ #### ContextBackend Protocol
63
+ ```python
64
+ class ContextBackend(Protocol):
65
+ def save_context(self, id: str, context: dict) -> None: ...
66
+ def get_context(self, id: str) -> dict: ...
67
+ ```
68
+
69
+ #### WorkflowBackend Protocol
70
+ ```python
71
+ class WorkflowBackend(Protocol):
72
+ def save_workflows_registry(self, id: str, workflows: Any) -> None: ...
73
+ def get_workflows_registry(self, id: str) -> Any: ...
74
+ def save_current_workflow_name(self, id: str, name: str) -> None: ...
75
+ def get_current_workflow_name(self, id: str) -> str: ...
76
+ ```
77
+
78
+ #### TelemetryBackend Protocol (Optional)
79
+ ```python
80
+ class TelemetryBackend(Protocol):
81
+ def log_event(self, execution_id: str, event_type: str, **event_data) -> None: ...
82
+ ```
83
+
84
+ #### ConversationHistoryBackend Protocol (Optional)
85
+ ```python
86
+ class ConversationHistoryBackend(Protocol):
87
+ def get_conversation_history(self, identity: str) -> List[Dict[str, Any]]: ...
88
+ def append_to_conversation_history(self, identity: str, entry: Dict[str, Any]) -> None: ...
89
+ def save_conversation_history(self, identity: str, history: List[Dict[str, Any]]) -> None: ...
90
+ def delete_conversation_history(self, identity: str) -> None: ...
91
+ ```
92
+
93
+ #### ContextSchemaBackend Protocol (Optional)
94
+ ```python
95
+ class ContextSchemaBackend(Protocol):
96
+ def save_context_schema(self, execution_id: str, schema: Dict[str, Any]) -> None: ...
97
+ def get_context_schema(self, execution_id: str) -> Optional[Dict[str, Any]]: ...
98
+ def get_field_schema(self, execution_id: str, field_name: str) -> Optional[Dict[str, Any]]: ...
99
+ def delete_context_schema(self, execution_id: str) -> bool: ...
100
+ ```
101
+
102
+ **Note**: Context schemas are keyed by `execution_id` (specifically `main_execution_id`), not workflow name. This allows child workflows to access the parent's schema definitions.
103
+
104
+ #### IdentityBackend Protocol (Optional)
105
+ ```python
106
+ class IdentityBackend(Protocol):
107
+ def save_identities(self, execution_id: str, identities: Dict[str, str]) -> None: ...
108
+ def get_identities(self, execution_id: str) -> Optional[Dict[str, str]]: ...
109
+ def get_identity(self, execution_id: str, identity_name: str) -> Optional[str]: ...
110
+ def delete_identities(self, execution_id: str) -> bool: ...
111
+ ```
112
+
113
+ **Note**: Identities are simple mappings of `identity_name` → `system_prompt` (string). Like context schemas, they're keyed by `main_execution_id` for child workflow access.
114
+
115
+ ### Database Recommendations
116
+
117
+ For production deployments, we recommend using **the same database** for all config-related backends:
118
+
119
+ | Backend | Recommended Storage | Why |
120
+ |---------|---------------------|-----|
121
+ | `context` | Same DB, separate table | Simplifies connection management |
122
+ | `workflow` | Same DB, separate table | Allows atomic config updates |
123
+ | `context_schema` | Same DB, separate table | Related to workflows |
124
+ | `identity` | Same DB, separate table | Related to workflows |
125
+ | `conversation_history` | Same DB, separate table | Per-execution keying |
126
+ | `telemetry` | Can be separate | High volume, different access patterns |
127
+
128
+ The backend methods handle table creation. Using one database (with separate tables) is simpler to manage than multiple databases.
129
+
130
+ ### Creating Custom Backends
131
+
132
+ #### Example: PostgreSQL Context Backend
133
+
134
+ ```python
135
+ import psycopg2
136
+ import json
137
+ from typing import Dict, Any
138
+
139
+ class PostgresContextBackend:
140
+ """PostgreSQL-based context storage"""
141
+
142
+ def __init__(self, connection_string: str):
143
+ self.conn = psycopg2.connect(connection_string)
144
+ self._ensure_table()
145
+
146
+ def _ensure_table(self):
147
+ with self.conn.cursor() as cur:
148
+ cur.execute("""
149
+ CREATE TABLE IF NOT EXISTS soe_context (
150
+ execution_id VARCHAR(255) PRIMARY KEY,
151
+ context JSONB NOT NULL,
152
+ updated_at TIMESTAMP DEFAULT NOW()
153
+ )
154
+ """)
155
+ self.conn.commit()
156
+
157
+ def save_context(self, id: str, context: Dict[str, Any]) -> None:
158
+ with self.conn.cursor() as cur:
159
+ cur.execute("""
160
+ INSERT INTO soe_context (execution_id, context)
161
+ VALUES (%s, %s)
162
+ ON CONFLICT (execution_id)
163
+ DO UPDATE SET context = %s, updated_at = NOW()
164
+ """, (id, json.dumps(context), json.dumps(context)))
165
+ self.conn.commit()
166
+
167
+ def get_context(self, id: str) -> Dict[str, Any]:
168
+ with self.conn.cursor() as cur:
169
+ cur.execute(
170
+ "SELECT context FROM soe_context WHERE execution_id = %s",
171
+ (id,)
172
+ )
173
+ row = cur.fetchone()
174
+ return row[0] if row else {}
175
+
176
+ def cleanup_all(self) -> None:
177
+ with self.conn.cursor() as cur:
178
+ cur.execute("DELETE FROM soe_context")
179
+ self.conn.commit()
180
+ ```
181
+
182
+ #### Example: DynamoDB Context Backend
183
+
184
+ ```python
185
+ import boto3
186
+ import json
187
+ from typing import Dict, Any
188
+
189
+ class DynamoDBContextBackend:
190
+ """AWS DynamoDB-based context storage"""
191
+
192
+ def __init__(self, table_name: str, region: str = "us-east-1"):
193
+ self.dynamodb = boto3.resource('dynamodb', region_name=region)
194
+ self.table = self.dynamodb.Table(table_name)
195
+
196
+ def save_context(self, id: str, context: Dict[str, Any]) -> None:
197
+ self.table.put_item(Item={
198
+ 'execution_id': id,
199
+ 'context': json.dumps(context)
200
+ })
201
+
202
+ def get_context(self, id: str) -> Dict[str, Any]:
203
+ response = self.table.get_item(Key={'execution_id': id})
204
+ if 'Item' in response:
205
+ return json.loads(response['Item']['context'])
206
+ return {}
207
+
208
+ def cleanup_all(self) -> None:
209
+ # Scan and delete all items (use with caution in production)
210
+ scan = self.table.scan()
211
+ with self.table.batch_writer() as batch:
212
+ for item in scan['Items']:
213
+ batch.delete_item(Key={'execution_id': item['execution_id']})
214
+ ```
215
+
216
+ #### Example: Datadog Telemetry Backend
217
+
218
+ ```python
219
+ from datadog import initialize, statsd
220
+ from typing import Any
221
+
222
+ class DatadogTelemetryBackend:
223
+ """Datadog-based telemetry backend"""
224
+
225
+ def __init__(self, api_key: str, app_key: str):
226
+ initialize(api_key=api_key, app_key=app_key)
227
+
228
+ def log_event(self, execution_id: str, event_type: str, **event_data) -> None:
229
+ # Send as a custom metric
230
+ statsd.event(
231
+ title=f"SOE: {event_type}",
232
+ text=f"Execution: {execution_id}",
233
+ tags=[
234
+ f"execution_id:{execution_id}",
235
+ f"event_type:{event_type}",
236
+ *[f"{k}:{v}" for k, v in event_data.items()]
237
+ ]
238
+ )
239
+
240
+ def cleanup_all(self) -> None:
241
+ # Datadog events are immutable; no cleanup needed
242
+ pass
243
+ ```
244
+
245
+ ### Assembling Custom Backends
246
+
247
+ Create a `Backends` container with your custom implementations:
248
+
249
+ ```python
250
+ from soe.local_backends.factory import LocalBackends
251
+
252
+ # Mix and match backends based on your infrastructure
253
+ backends = LocalBackends(
254
+ context_backend=PostgresContextBackend("postgresql://..."),
255
+ workflow_backend=S3WorkflowBackend("my-bucket"),
256
+ telemetry_backend=DatadogTelemetryBackend(api_key="...", app_key="..."),
257
+ conversation_history_backend=MongoConversationBackend("mongodb://..."),
258
+ schema_backend=None, # Optional
259
+ )
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Part 2: Communication Infrastructure (Callers)
265
+
266
+ ### What Are Callers?
267
+
268
+ Callers are the **communication layer** of SOE. The most important is `broadcast_signals_caller`, which controls how signals propagate through the system.
269
+
270
+ ### The Default Pattern (In-Process)
271
+
272
+ ```python
273
+ from soe import broadcast_signals
274
+
275
+ def broadcast_signals_caller(id: str, signals: List[str]) -> None:
276
+ broadcast_signals(id, signals, nodes, backends)
277
+ ```
278
+
279
+ This is synchronous and in-process—perfect for testing and simple deployments.
280
+
281
+ ### Distributed Callers
282
+
283
+ For production systems, you might want signals to trigger external services.
284
+
285
+ #### Example: AWS Lambda Caller
286
+
287
+ ```python
288
+ import boto3
289
+ import json
290
+
291
+ def create_lambda_caller(function_name: str, region: str = "us-east-1"):
292
+ """Create a caller that invokes AWS Lambda for signal broadcasting"""
293
+ lambda_client = boto3.client('lambda', region_name=region)
294
+
295
+ def broadcast_signals_caller(id: str, signals: List[str]) -> None:
296
+ payload = {
297
+ 'execution_id': id,
298
+ 'signals': signals
299
+ }
300
+ lambda_client.invoke(
301
+ FunctionName=function_name,
302
+ InvocationType='Event', # Async invocation
303
+ Payload=json.dumps(payload)
304
+ )
305
+
306
+ return broadcast_signals_caller
307
+ ```
308
+
309
+ #### Example: HTTP Webhook Caller
310
+
311
+ ```python
312
+ import requests
313
+
314
+ def create_http_caller(webhook_url: str, auth_token: str = None):
315
+ """Create a caller that sends signals via HTTP POST"""
316
+ headers = {'Content-Type': 'application/json'}
317
+ if auth_token:
318
+ headers['Authorization'] = f'Bearer {auth_token}'
319
+
320
+ def broadcast_signals_caller(id: str, signals: List[str]) -> None:
321
+ payload = {
322
+ 'execution_id': id,
323
+ 'signals': signals
324
+ }
325
+ response = requests.post(webhook_url, json=payload, headers=headers)
326
+ response.raise_for_status()
327
+
328
+ return broadcast_signals_caller
329
+ ```
330
+
331
+ #### Example: Message Queue Caller (SQS)
332
+
333
+ ```python
334
+ import boto3
335
+ import json
336
+
337
+ def create_sqs_caller(queue_url: str, region: str = "us-east-1"):
338
+ """Create a caller that sends signals to an SQS queue"""
339
+ sqs = boto3.client('sqs', region_name=region)
340
+
341
+ def broadcast_signals_caller(id: str, signals: List[str]) -> None:
342
+ message = {
343
+ 'execution_id': id,
344
+ 'signals': signals
345
+ }
346
+ sqs.send_message(
347
+ QueueUrl=queue_url,
348
+ MessageBody=json.dumps(message)
349
+ )
350
+
351
+ return broadcast_signals_caller
352
+ ```
353
+
354
+ ---
355
+
356
+ ## Part 3: The LLM Caller
357
+
358
+ ### SOE Doesn't Provide an LLM
359
+
360
+ Unlike some frameworks that bundle specific LLM providers, SOE is **LLM agnostic**. You provide a `call_llm` function that wraps your chosen provider.
361
+
362
+ ### The CallLlm Protocol
363
+
364
+ ```python
365
+ class CallLlm(Protocol):
366
+ def __call__(self, prompt: str, config: Dict[str, Any]) -> str:
367
+ ...
368
+ ```
369
+
370
+ ### Example: OpenAI Caller
371
+
372
+ ```python
373
+ import openai
374
+
375
+ def create_openai_caller(api_key: str, default_model: str = "gpt-4o"):
376
+ """Create an LLM caller for OpenAI API"""
377
+ client = openai.OpenAI(api_key=api_key)
378
+
379
+ def call_llm(prompt: str, config: dict) -> str:
380
+ model = config.get("model", default_model)
381
+ temperature = config.get("temperature", 1.0)
382
+
383
+ response = client.chat.completions.create(
384
+ model=model,
385
+ temperature=temperature,
386
+ messages=[{"role": "user", "content": prompt}]
387
+ )
388
+ return response.choices[0].message.content
389
+
390
+ return call_llm
391
+ ```
392
+
393
+ ### Example: Test Stub Caller
394
+
395
+ ```python
396
+ def create_stub_caller(responses: dict = None):
397
+ """Create a stub caller for testing"""
398
+ responses = responses or {}
399
+
400
+ def call_llm(prompt: str, config: dict) -> str:
401
+ for pattern, response in responses.items():
402
+ if pattern in prompt:
403
+ return response
404
+ return '{"response": "stub response"}'
405
+
406
+ return call_llm
407
+ ```
408
+
409
+ ---
410
+
411
+ ## Summary
412
+
413
+ | Concern | Component | Built-in Options | Custom Examples |
414
+ |---------|-----------|------------------|-----------------|
415
+ | **Persistence** | Backends | In-Memory, Local Files | PostgreSQL, DynamoDB, MongoDB |
416
+ | **Telemetry** | TelemetryBackend | In-Memory, Local Files | Datadog, CloudWatch |
417
+ | **Communication** | Callers | In-process | Lambda, HTTP, SQS |
418
+ | **LLM** | CallLlm | None (you provide) | OpenAI, Anthropic, Ollama |
419
+
420
+ The key principle: **SOE defines the protocols, you provide the implementations**.
421
+
422
+ ---
423
+
424
+ ## Next Steps
425
+
426
+ Now that you've mastered the infrastructure, explore the capabilities built directly into the engine:
427
+ - **[Chapter 11: Built-in Tools](guide_11_builtins.md)** — Self-evolution, documentation exploration, and runtime modification
@@ -0,0 +1,118 @@
1
+
2
+ # SOE Guide: Chapter 11 - Built-in Tools
3
+
4
+ ## The Power of Self-Evolution
5
+
6
+ SOE includes a set of **built-in tools** that are always available to your workflows. These aren't ordinary utilities—they're the foundation for **self-evolving systems**.
7
+
8
+ Built-in tools enable workflows to:
9
+
10
+ - **Explore their own documentation** — Understand what they can do
11
+ - **Modify workflows at runtime** — Inject, remove, or reconfigure nodes
12
+ - **Manage execution context** — Read, update, and copy context data
13
+ - **Query available capabilities** — Discover registered tools dynamically
14
+
15
+ ---
16
+
17
+ ## Naming Convention
18
+
19
+ All built-in tools use the `soe_` prefix to clearly distinguish them from user-defined tools. This prevents naming conflicts and makes it clear these are system-provided utilities.
20
+
21
+ ---
22
+
23
+ ## Principles
24
+
25
+ ### Always Available
26
+
27
+ Built-in tools require no registration. Simply reference them by name in any tool node:
28
+
29
+ ```yaml
30
+ example_workflow:
31
+ ExploreDocs:
32
+ node_type: tool
33
+ event_triggers: [START]
34
+ tool_name: soe_explore_docs
35
+ context_parameter_field: explore_params
36
+ output_field: docs_list
37
+ event_emissions:
38
+ - signal_name: DOCS_LISTED
39
+ ```
40
+
41
+ ### Essential for Self-Evolution
42
+
43
+ These tools are the building blocks for autonomous systems. An LLM can:
44
+
45
+ 1. **Read documentation** to understand capabilities
46
+ 2. **Query workflows** to see current structure
47
+ 3. **Inject new nodes** to extend behavior
48
+ 4. **Manage context** to persist learned patterns
49
+
50
+ ### No Registration Required
51
+
52
+ Unlike custom tools that need a `tools_registry`, built-ins work immediately. SOE provides them automatically during orchestration.
53
+
54
+ ---
55
+
56
+ ## Available Built-ins
57
+
58
+ | Built-in | Purpose | Documentation |
59
+ |----------|---------|---------------|
60
+ | `soe_explore_docs` | Make SOE self-aware by exploring its documentation | [explore_docs](builtins/explore_docs.md) |
61
+ | `soe_get_workflows` | Query registered workflow definitions | [workflows](builtins/workflows.md) |
62
+ | `soe_inject_workflow` | Add new workflows at runtime | [workflows](builtins/workflows.md) |
63
+ | `soe_inject_node` | Add or modify nodes in workflows | [workflows](builtins/workflows.md) |
64
+ | `soe_remove_workflow` | Remove workflows from registry | [workflows](builtins/workflows.md) |
65
+ | `soe_remove_node` | Remove nodes from workflows | [workflows](builtins/workflows.md) |
66
+ | `soe_get_context` | Read execution context | [context](builtins/context.md) |
67
+ | `soe_update_context` | Modify execution context | [context](builtins/context.md) |
68
+ | `soe_copy_context` | Clone context for parallel execution | [context](builtins/context.md) |
69
+ | `soe_list_contexts` | Discover available contexts | [context](builtins/context.md) |
70
+ | `soe_get_available_tools` | List all registered tools | [tools](builtins/tools.md) |
71
+ | `soe_call_tool` | Invoke a tool by name dynamically | [tools](builtins/tools.md) |
72
+ | `soe_add_signal` | Emit signals programmatically | [workflows](builtins/workflows.md) |
73
+
74
+ ---
75
+
76
+ ## Self-Awareness in Practice
77
+
78
+ Here's a workflow that becomes self-aware by exploring docs and querying its own state:
79
+
80
+ ```yaml
81
+ self_aware_workflow:
82
+ ExploreCapabilities:
83
+ node_type: tool
84
+ event_triggers: [START]
85
+ tool_name: soe_explore_docs
86
+ context_parameter_field: explore_params
87
+ output_field: capabilities_tree
88
+ event_emissions:
89
+ - signal_name: CAPABILITIES_KNOWN
90
+
91
+ QueryCurrentState:
92
+ node_type: tool
93
+ event_triggers: [CAPABILITIES_KNOWN]
94
+ tool_name: soe_get_workflows
95
+ output_field: current_workflows
96
+ event_emissions:
97
+ - signal_name: STATE_KNOWN
98
+ ```
99
+
100
+ This pattern is the foundation for metacognitive workflows that can reason about their own capabilities.
101
+
102
+ ---
103
+
104
+ ## Next Steps
105
+
106
+ Explore each built-in category in detail:
107
+
108
+ - **[explore_docs](builtins/explore_docs.md)** — Self-awareness through documentation
109
+ - **[workflows](builtins/workflows.md)** — Runtime workflow modification
110
+ - **[context](builtins/context.md)** — Execution state management
111
+ - **[tools](builtins/tools.md)** — Dynamic tool discovery and invocation
112
+
113
+ ---
114
+
115
+ ## Related
116
+
117
+ - [Advanced Patterns](advanced_patterns/index.md) — Complex workflow patterns
118
+ - [Self-Evolving Workflows](advanced_patterns/self_evolving_workflows.md) — Full self-evolution guide
soe/docs/index.md ADDED
@@ -0,0 +1,104 @@
1
+ # SOE User Guide
2
+
3
+ Welcome to the **Signal-driven Orchestration Engine** user guide. This is your starting point for learning how to build workflows with SOE.
4
+
5
+ ---
6
+
7
+ ## Quick Start
8
+
9
+ New to SOE? Start here:
10
+
11
+ 1. **[Getting Started](guide_00_getting_started.md)** — Installation, core concepts, and your first workflow
12
+ 2. **[Tool Nodes](guide_01_tool.md)** — Execute Python functions in your workflows
13
+ 3. **[LLM Nodes](guide_02_llm.md)** — Integrate language models into your workflows
14
+ 4. **[Router Nodes](guide_03_router.md)** — Pure routing and branching (recommended)
15
+
16
+ ---
17
+
18
+ ## The Guide
19
+
20
+ ### The Three Core Node Types
21
+
22
+ SOE has three core node types that can build **any** workflow pattern:
23
+
24
+ | Chapter | Topic | What You'll Learn |
25
+ |---------|-------|-------------------|
26
+ | [00 - Getting Started](guide_00_getting_started.md) | Installation & First Run | How SOE works, synchronous execution, copy-paste template |
27
+ | [01 - Tool](guide_01_tool.md) | Tool Nodes | Execute Python functions—APIs, databases, real work |
28
+ | [02 - LLM](guide_02_llm.md) | LLM Nodes | Call language models, prompt templating, signal selection |
29
+ | [03 - Router](guide_03_router.md) | Router Nodes | Pure routing—entry points, branching, no execution |
30
+ | [04 - Patterns](guide_04_patterns.md) | Building Custom Workflows | Combine core nodes: ReAct, chain-of-thought, metacognition |
31
+
32
+ With just **Tool**, **LLM**, and **Router**, you can build remarkably sophisticated workflows—including custom agent loops, reasoning chains, and multi-step AI systems.
33
+
34
+ ### Convenience & Advanced Features
35
+
36
+ These chapters cover higher-level abstractions and advanced capabilities:
37
+
38
+ | Chapter | Topic | What You'll Learn |
39
+ |---------|-------|-------------------|
40
+ | [05 - Agent](guide_05_agent.md) | Agent Nodes | Built-in ReAct loop—convenience wrapper for tool-using agents |
41
+ | [06 - Schema](guide_06_schema.md) | Context Schema | Type validation for structured LLM output |
42
+ | [07 - Identity](guide_07_identity.md) | Identity & History | System prompts and conversation history across nodes |
43
+ | [08 - Child Workflows](guide_08_child.md) | Sub-orchestration | Nested workflows with signal communication |
44
+ | [09 - Ecosystem](guide_09_ecosystem.md) | The Workflows Ecosystem | Multi-workflow registries, parallel execution, versioning |
45
+ | [10 - Infrastructure](guide_10_infrastructure.md) | Custom Backends & Callers | PostgreSQL, DynamoDB, Lambda, HTTP webhooks |
46
+ | [11 - Built-in Tools](guide_11_builtins.md) | Self-Evolution | Always-available tools for introspection and evolution |
47
+
48
+ ---
49
+
50
+ ## Primitives
51
+
52
+ Understand the core building blocks:
53
+
54
+ | Concept | Description |
55
+ |---------|-------------|
56
+ | [The 7 Primitives](primitives/primitives.md) | Signals, Context, Workflows, Backends, Nodes, Identities, Context Schema |
57
+ | [Signals Reference](primitives/signals.md) | Signal emission, conditions, and propagation |
58
+ | [Context Deep Dive](primitives/context.md) | History, accumulated filter, Jinja access |
59
+ | [Backends Reference](primitives/backends.md) | Setup, protocols, custom implementations |
60
+ | [Node Reference](primitives/node_reference.md) | Complete node configuration reference |
61
+
62
+ ---
63
+
64
+ ## Advanced Patterns
65
+
66
+ For researchers and advanced users exploring SOE's full potential:
67
+
68
+ | Pattern | Description |
69
+ |---------|-------------|
70
+ | [Advanced Patterns Index](advanced_patterns/index.md) | Overview of all advanced patterns |
71
+ | [Fan-Out & Aggregations](advanced_patterns/guide_fanout_and_aggregations.md) | Parallel processing and accumulated context |
72
+ | [Self-Evolving Workflows](advanced_patterns/self_evolving_workflows.md) | LLM-driven workflow generation and injection |
73
+ | [Swarm Intelligence](advanced_patterns/swarm_intelligence.md) | Multi-agent voting and consensus |
74
+ | [Hybrid Intelligence](advanced_patterns/hybrid_intelligence.md) | Mixing deterministic logic with AI |
75
+ | [Inheritance](advanced_patterns/guide_inheritance.md) | Config and context inheritance between executions |
76
+ | [Operational Features](advanced_patterns/operational.md) | Runtime control, limits, and guardrails |
77
+
78
+ ### Built-in Tools for Self-Evolution
79
+
80
+ Built-in tools enable granular runtime modifications:
81
+
82
+ | Built-in | Description |
83
+ |----------|-------------|
84
+ | [explore_docs](builtins/explore_docs.md) | Make SOE self-aware by exploring its documentation |
85
+ | [workflows](builtins/workflows.md) | Query, inject, and modify workflows at runtime |
86
+ | [context](builtins/context.md) | Read, update, and copy execution context |
87
+ | [tools](builtins/tools.md) | Discover and dynamically call registered tools |
88
+
89
+ ---
90
+
91
+ ## Philosophy
92
+
93
+ SOE is designed around three core principles:
94
+
95
+ 1. **Signal-Driven** — Nodes communicate through signals, not direct calls
96
+ 2. **Infrastructure-Agnostic** — Plug in your own databases, LLMs, and distribution mechanisms
97
+ 3. **Data-Driven** — Everything flows through context; master the primitives to build anything
98
+
99
+ ---
100
+
101
+ ## Getting Help
102
+
103
+ - **Source Code**: [github.com/pgarcia14180/soe](https://github.com/pgarcia14180/soe)
104
+ - **PyPI Package**: [pypi.org/project/soe](https://pypi.org/project/soe/)