Class: SwarmSDK::Workflow
- Inherits:
-
Object
- Object
- SwarmSDK::Workflow
- Defined in:
- lib/swarm_sdk/workflow.rb,
lib/swarm_sdk/workflow/builder.rb,
lib/swarm_sdk/workflow/executor.rb,
lib/swarm_sdk/workflow/agent_config.rb,
lib/swarm_sdk/workflow/node_builder.rb,
lib/swarm_sdk/workflow/transformer_executor.rb
Overview
Workflow executes a multi-node workflow
Each node represents a mini-swarm execution stage. The workflow:
- Builds execution order from node dependencies (topological sort)
- Creates a separate swarm instance for each node
- Passes output from one node as input to dependent nodes
- Supports input/output transformers for data flow customization
Defined Under Namespace
Classes: AgentConfig, Builder, Executor, NodeBuilder, TransformerExecutor
Instance Attribute Summary collapse
-
#agent_definitions ⇒ Object
readonly
Returns the value of attribute agent_definitions.
-
#agents ⇒ Object
readonly
Returns the value of attribute agents.
-
#config_for_hooks ⇒ Object
writeonly
Sets the attribute config_for_hooks.
-
#delegation_instances ⇒ Object
readonly
Returns the value of attribute delegation_instances.
-
#execution_order ⇒ Object
readonly
Returns the value of attribute execution_order.
-
#mcp_clients ⇒ Object
readonly
Returns the value of attribute mcp_clients.
-
#nodes ⇒ Object
readonly
Returns the value of attribute nodes.
-
#original_prompt ⇒ Object
Returns the value of attribute original_prompt.
-
#parent_swarm_id ⇒ Object
readonly
Returns the value of attribute parent_swarm_id.
-
#scratchpad ⇒ Object
readonly
Returns the value of attribute scratchpad.
-
#start_node ⇒ Object
readonly
Returns the value of attribute start_node.
-
#swarm_id ⇒ Object
Returns the value of attribute swarm_id.
-
#swarm_name ⇒ Object
readonly
Returns the value of attribute swarm_name.
-
#swarm_registry_config ⇒ Object
Returns the value of attribute swarm_registry_config.
Instance Method Summary collapse
-
#all_scratchpads ⇒ Hash
Get all scratchpad storages (for snapshot/restore).
-
#build_swarm_for_node(node) ⇒ Swarm
Build a swarm instance for a specific node.
-
#cache_agent_instances(swarm, node) ⇒ void
Cache agent instances from a swarm for potential reuse.
- #delegation_instances_hash ⇒ Object
-
#execute(prompt, inherit_subscriptions: true) {|Hash| ... } ⇒ Result
Execute the node workflow.
-
#first_message_sent? ⇒ Boolean
No-op for Swarm compatibility (Workflow doesn't track first message).
-
#initialize(swarm_name:, agent_definitions:, nodes:, start_node:, swarm_id: nil, scratchpad: :enabled, allow_filesystem_tools: nil) ⇒ Workflow
constructor
A new instance of Workflow.
-
#lead_agent ⇒ Symbol
Return the lead agent of the start node for CLI compatibility.
-
#name ⇒ Object
Provide name method for interface compatibility.
-
#per_node_scratchpad? ⇒ Boolean
Check if scratchpad is per-node.
-
#primary_agents ⇒ Object
Implement Snapshotable interface.
-
#restore(snapshot, preserve_system_prompts: false) ⇒ RestoreResult
Restore workflow state from snapshot.
-
#scratchpad_enabled? ⇒ Boolean
Check if scratchpad is enabled.
-
#scratchpad_for(node_name) ⇒ Tools::Stores::ScratchpadStorage?
Get scratchpad storage for a specific node.
-
#shared_scratchpad? ⇒ Boolean
Check if scratchpad is shared between nodes (enabled mode).
-
#shared_scratchpad_storage ⇒ Tools::Stores::ScratchpadStorage?
Backward compatibility accessor.
-
#snapshot ⇒ Snapshot
Create snapshot of current workflow state.
Constructor Details
#initialize(swarm_name:, agent_definitions:, nodes:, start_node:, swarm_id: nil, scratchpad: :enabled, allow_filesystem_tools: nil) ⇒ Workflow
Returns a new instance of Workflow.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/swarm_sdk/workflow.rb', line 27 def initialize(swarm_name:, agent_definitions:, nodes:, start_node:, swarm_id: nil, scratchpad: :enabled, allow_filesystem_tools: nil) @swarm_name = swarm_name @swarm_id = swarm_id || generate_swarm_id(swarm_name) @parent_swarm_id = nil # Workflows don't have parent swarms @agent_definitions = agent_definitions @nodes = nodes @start_node = start_node @scratchpad = normalize_scratchpad_mode(scratchpad) @allow_filesystem_tools = allow_filesystem_tools @swarm_registry_config = [] # External swarms config (if using composable swarms) # Simplified structure (matches Swarm) @agents = {} # Cached primary agents from nodes @delegation_instances = {} # Cached delegation instances from nodes # MCP clients per agent (for cleanup compatibility) @mcp_clients = Hash.new { |h, k| h[k] = [] } # Initialize scratchpad storage based on mode case @scratchpad when :enabled # Enabled mode: single scratchpad shared across all nodes @shared_scratchpad_storage = Tools::Stores::ScratchpadStorage.new @node_scratchpads = nil when :per_node # Per-node mode: separate scratchpad per node (lazy initialized) @shared_scratchpad_storage = nil @node_scratchpads = {} when :disabled # Disabled: no storage at all @shared_scratchpad_storage = nil @node_scratchpads = nil end validate! @execution_order = build_execution_order end |
Instance Attribute Details
#agent_definitions ⇒ Object (readonly)
Returns the value of attribute agent_definitions.
21 22 23 |
# File 'lib/swarm_sdk/workflow.rb', line 21 def agent_definitions @agent_definitions end |
#agents ⇒ Object (readonly)
Returns the value of attribute agents.
22 23 24 |
# File 'lib/swarm_sdk/workflow.rb', line 22 def agents @agents end |
#config_for_hooks=(value) ⇒ Object (writeonly)
Sets the attribute config_for_hooks
24 25 26 |
# File 'lib/swarm_sdk/workflow.rb', line 24 def config_for_hooks=(value) @config_for_hooks = value end |
#delegation_instances ⇒ Object (readonly)
Returns the value of attribute delegation_instances.
22 23 24 |
# File 'lib/swarm_sdk/workflow.rb', line 22 def delegation_instances @delegation_instances end |
#execution_order ⇒ Object (readonly)
Returns the value of attribute execution_order.
23 24 25 |
# File 'lib/swarm_sdk/workflow.rb', line 23 def execution_order @execution_order end |
#mcp_clients ⇒ Object (readonly)
Returns the value of attribute mcp_clients.
22 23 24 |
# File 'lib/swarm_sdk/workflow.rb', line 22 def mcp_clients @mcp_clients end |
#nodes ⇒ Object (readonly)
Returns the value of attribute nodes.
21 22 23 |
# File 'lib/swarm_sdk/workflow.rb', line 21 def nodes @nodes end |
#original_prompt ⇒ Object
Returns the value of attribute original_prompt.
25 26 27 |
# File 'lib/swarm_sdk/workflow.rb', line 25 def original_prompt @original_prompt end |
#parent_swarm_id ⇒ Object (readonly)
Returns the value of attribute parent_swarm_id.
22 23 24 |
# File 'lib/swarm_sdk/workflow.rb', line 22 def parent_swarm_id @parent_swarm_id end |
#scratchpad ⇒ Object (readonly)
Returns the value of attribute scratchpad.
21 22 23 |
# File 'lib/swarm_sdk/workflow.rb', line 21 def scratchpad @scratchpad end |
#start_node ⇒ Object (readonly)
Returns the value of attribute start_node.
21 22 23 |
# File 'lib/swarm_sdk/workflow.rb', line 21 def start_node @start_node end |
#swarm_id ⇒ Object
Returns the value of attribute swarm_id.
22 23 24 |
# File 'lib/swarm_sdk/workflow.rb', line 22 def swarm_id @swarm_id end |
#swarm_name ⇒ Object (readonly)
Returns the value of attribute swarm_name.
21 22 23 |
# File 'lib/swarm_sdk/workflow.rb', line 21 def swarm_name @swarm_name end |
#swarm_registry_config ⇒ Object
Returns the value of attribute swarm_registry_config.
25 26 27 |
# File 'lib/swarm_sdk/workflow.rb', line 25 def swarm_registry_config @swarm_registry_config end |
Instance Method Details
#all_scratchpads ⇒ Hash
Get all scratchpad storages (for snapshot/restore)
108 109 110 111 112 113 114 115 116 117 |
# File 'lib/swarm_sdk/workflow.rb', line 108 def all_scratchpads case @scratchpad when :enabled { shared: @shared_scratchpad_storage } when :per_node @node_scratchpads.dup when :disabled {} end end |
#build_swarm_for_node(node) ⇒ Swarm
Build a swarm instance for a specific node
Creates a new Swarm with only the agents specified in the node, configured with the node's delegation topology.
For agents with reset_context: false, injects cached instances to preserve conversation history across nodes.
Scratchpad behavior depends on mode:
- :enabled - all nodes use the same scratchpad instance
- :per_node - each node gets its own scratchpad instance
- :disabled - no scratchpad
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/swarm_sdk/workflow.rb', line 250 def build_swarm_for_node(node) # Build hierarchical swarm_id if parent has one (nil auto-generates) node_swarm_id = @swarm_id ? "#{@swarm_id}/node:#{node.name}" : nil swarm = Swarm.new( name: "#{@swarm_name}:#{node.name}", swarm_id: node_swarm_id, parent_swarm_id: @swarm_id, scratchpad: scratchpad_for(node.name), scratchpad_mode: :enabled, # Mini-swarms always use enabled (scratchpad instance passed in) allow_filesystem_tools: @allow_filesystem_tools, ) # Setup swarm registry if external swarms are registered if @swarm_registry_config&.any? registry = SwarmRegistry.new(parent_swarm_id: node_swarm_id || swarm.swarm_id) @swarm_registry_config.each do |reg| registry.register(reg[:name], source: reg[:source], keep_context: reg[:keep_context]) end swarm.swarm_registry = registry end # Add each agent specified in this node node.agent_configs.each do |config| agent_name = config[:agent] delegates_to = config[:delegates_to] tools_override = config[:tools] # Get global agent definition agent_def = @agent_definitions[agent_name] # Clone definition with node-specific overrides node_specific_def = clone_agent_for_node(agent_def, delegates_to, tools_override) swarm.add_agent(node_specific_def) end # Set lead agent swarm.lead = node.lead_agent # Inject cached agent instances for context preservation inject_cached_agents(swarm, node) swarm end |
#cache_agent_instances(swarm, node) ⇒ void
This method returns an undefined value.
Cache agent instances from a swarm for potential reuse
Only caches agents that have reset_context: false in this node. This allows preserving conversation history across nodes.
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/swarm_sdk/workflow.rb', line 304 def cache_agent_instances(swarm, node) return unless swarm.agents node.agent_configs.each do |config| agent_name = config[:agent] reset_context = config[:reset_context] # Only cache if reset_context: false next if reset_context # Cache primary agent agent_instance = swarm.agents[agent_name] @agents[agent_name] = agent_instance if agent_instance # Cache delegation instances atomically (together with primary) agent_def = @agent_definitions[agent_name] agent_def.delegates_to.each do |delegate_name| delegation_key = "#{delegate_name}@#{agent_name}" delegation_instance = swarm.delegation_instances[delegation_key] if delegation_instance @delegation_instances[delegation_key] = delegation_instance end end end end |
#delegation_instances_hash ⇒ Object
75 76 77 |
# File 'lib/swarm_sdk/workflow.rb', line 75 def delegation_instances_hash @delegation_instances end |
#execute(prompt, inherit_subscriptions: true) {|Hash| ... } ⇒ Result
Execute the node workflow
Executes nodes in topological order, passing output from each node to its dependents. Supports streaming logs if block given.
167 168 169 |
# File 'lib/swarm_sdk/workflow.rb', line 167 def execute(prompt, inherit_subscriptions: true, &block) Executor.new(self).run(prompt, inherit_subscriptions: inherit_subscriptions, &block) end |
#first_message_sent? ⇒ Boolean
No-op for Swarm compatibility (Workflow doesn't track first message)
80 81 82 |
# File 'lib/swarm_sdk/workflow.rb', line 80 def false end |
#lead_agent ⇒ Symbol
Return the lead agent of the start node for CLI compatibility
153 154 155 |
# File 'lib/swarm_sdk/workflow.rb', line 153 def lead_agent @nodes[@start_node].lead_agent end |
#name ⇒ Object
Provide name method for interface compatibility
66 67 68 |
# File 'lib/swarm_sdk/workflow.rb', line 66 def name @swarm_name end |
#per_node_scratchpad? ⇒ Boolean
Check if scratchpad is per-node
136 137 138 |
# File 'lib/swarm_sdk/workflow.rb', line 136 def per_node_scratchpad? @scratchpad == :per_node end |
#primary_agents ⇒ Object
Implement Snapshotable interface
71 72 73 |
# File 'lib/swarm_sdk/workflow.rb', line 71 def primary_agents @agents end |
#restore(snapshot, preserve_system_prompts: false) ⇒ RestoreResult
Restore workflow state from snapshot
Accepts a Snapshot object, hash, or JSON string. Validates compatibility between snapshot and current workflow configuration. Restores agent conversations that exist in the cached agents.
The workflow must be created with the SAME configuration (agent definitions, nodes) as when the snapshot was created. Only conversation state is restored.
For agents with reset_context: false, restored conversations will be injected during node execution. Agents not in cache yet will be skipped (they haven't been used yet, so there's nothing to restore).
Restore workflow state from snapshot
By default, uses current system prompts from agent definitions (YAML + SDK defaults + plugin injections). Set preserve_system_prompts: true to use historical prompts from snapshot.
231 232 233 |
# File 'lib/swarm_sdk/workflow.rb', line 231 def restore(snapshot, preserve_system_prompts: false) StateRestorer.new(self, snapshot, preserve_system_prompts: preserve_system_prompts).restore end |
#scratchpad_enabled? ⇒ Boolean
Check if scratchpad is enabled
122 123 124 |
# File 'lib/swarm_sdk/workflow.rb', line 122 def scratchpad_enabled? @scratchpad != :disabled end |
#scratchpad_for(node_name) ⇒ Tools::Stores::ScratchpadStorage?
Get scratchpad storage for a specific node
Returns the appropriate scratchpad based on mode:
- :enabled - returns the shared scratchpad (same for all nodes)
- :per_node - returns node-specific scratchpad (lazy initialized)
- :disabled - returns nil
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/swarm_sdk/workflow.rb', line 93 def scratchpad_for(node_name) case @scratchpad when :enabled @shared_scratchpad_storage when :per_node # Lazy initialization per node @node_scratchpads[node_name] ||= Tools::Stores::ScratchpadStorage.new when :disabled nil end end |
#shared_scratchpad? ⇒ Boolean
Check if scratchpad is shared between nodes (enabled mode)
129 130 131 |
# File 'lib/swarm_sdk/workflow.rb', line 129 def shared_scratchpad? @scratchpad == :enabled end |
#shared_scratchpad_storage ⇒ Tools::Stores::ScratchpadStorage?
Backward compatibility accessor
143 144 145 146 147 148 |
# File 'lib/swarm_sdk/workflow.rb', line 143 def shared_scratchpad_storage if @scratchpad == :per_node RubyLLM.logger.warn("Workflow: Accessing shared_scratchpad_storage in per-node mode. Use scratchpad_for(node_name) instead.") end @shared_scratchpad_storage end |
#snapshot ⇒ Snapshot
Create snapshot of current workflow state
Returns a Snapshot object containing agent conversations, context state, and scratchpad data from all nodes that have been executed. The snapshot captures the state of agents in the agent_instance_cache (both primary and delegation instances), as well as scratchpad storage.
Configuration (agent definitions, nodes, transformers) stays in your code and is NOT included in snapshots.
Scratchpad behavior depends on scratchpad mode:
- :enabled (default): single scratchpad shared across all nodes
- :per_node: separate scratchpad per node
- :disabled: no scratchpad data
193 194 195 |
# File 'lib/swarm_sdk/workflow.rb', line 193 def snapshot StateSnapshot.new(self).snapshot end |