swarm_memory 2.1.2 → 2.1.4

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/lib/claude_swarm/claude_mcp_server.rb +1 -0
  3. data/lib/claude_swarm/cli.rb +5 -18
  4. data/lib/claude_swarm/configuration.rb +30 -19
  5. data/lib/claude_swarm/mcp_generator.rb +5 -10
  6. data/lib/claude_swarm/openai/chat_completion.rb +4 -12
  7. data/lib/claude_swarm/openai/executor.rb +3 -1
  8. data/lib/claude_swarm/openai/responses.rb +13 -32
  9. data/lib/claude_swarm/version.rb +1 -1
  10. data/lib/swarm_cli/commands/mcp_serve.rb +2 -2
  11. data/lib/swarm_cli/commands/run.rb +2 -2
  12. data/lib/swarm_cli/config_loader.rb +14 -14
  13. data/lib/swarm_cli/formatters/human_formatter.rb +70 -0
  14. data/lib/swarm_cli/interactive_repl.rb +11 -5
  15. data/lib/swarm_cli/ui/icons.rb +0 -23
  16. data/lib/swarm_cli/version.rb +1 -1
  17. data/lib/swarm_memory/adapters/base.rb +4 -4
  18. data/lib/swarm_memory/adapters/filesystem_adapter.rb +11 -34
  19. data/lib/swarm_memory/core/storage_read_tracker.rb +51 -14
  20. data/lib/swarm_memory/integration/cli_registration.rb +3 -2
  21. data/lib/swarm_memory/integration/sdk_plugin.rb +98 -12
  22. data/lib/swarm_memory/tools/memory_edit.rb +2 -2
  23. data/lib/swarm_memory/tools/memory_multi_edit.rb +2 -2
  24. data/lib/swarm_memory/tools/memory_read.rb +3 -3
  25. data/lib/swarm_memory/version.rb +1 -1
  26. data/lib/swarm_memory.rb +6 -1
  27. data/lib/swarm_sdk/agent/builder.rb +91 -0
  28. data/lib/swarm_sdk/agent/chat.rb +540 -925
  29. data/lib/swarm_sdk/agent/{chat → chat_helpers}/context_tracker.rb +33 -79
  30. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +204 -0
  31. data/lib/swarm_sdk/agent/{chat → chat_helpers}/hook_integration.rb +147 -39
  32. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +78 -0
  33. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +233 -0
  34. data/lib/swarm_sdk/agent/{chat → chat_helpers}/logging_helpers.rb +1 -1
  35. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +83 -0
  36. data/lib/swarm_sdk/agent/{chat → chat_helpers}/system_reminder_injector.rb +22 -38
  37. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +79 -0
  38. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +98 -0
  39. data/lib/swarm_sdk/agent/context.rb +8 -4
  40. data/lib/swarm_sdk/agent/context_manager.rb +6 -0
  41. data/lib/swarm_sdk/agent/definition.rb +79 -174
  42. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +182 -0
  43. data/lib/swarm_sdk/agent/system_prompt_builder.rb +161 -0
  44. data/lib/swarm_sdk/builders/base_builder.rb +409 -0
  45. data/lib/swarm_sdk/concerns/cleanupable.rb +39 -0
  46. data/lib/swarm_sdk/concerns/snapshotable.rb +67 -0
  47. data/lib/swarm_sdk/concerns/validatable.rb +55 -0
  48. data/lib/swarm_sdk/configuration/parser.rb +353 -0
  49. data/lib/swarm_sdk/configuration/translator.rb +255 -0
  50. data/lib/swarm_sdk/configuration.rb +100 -261
  51. data/lib/swarm_sdk/context_compactor/token_counter.rb +3 -3
  52. data/lib/swarm_sdk/context_compactor.rb +6 -11
  53. data/lib/swarm_sdk/context_management/builder.rb +128 -0
  54. data/lib/swarm_sdk/context_management/context.rb +328 -0
  55. data/lib/swarm_sdk/defaults.rb +196 -0
  56. data/lib/swarm_sdk/events_to_messages.rb +199 -0
  57. data/lib/swarm_sdk/hooks/shell_executor.rb +2 -1
  58. data/lib/swarm_sdk/log_collector.rb +192 -16
  59. data/lib/swarm_sdk/log_stream.rb +66 -8
  60. data/lib/swarm_sdk/model_aliases.json +4 -1
  61. data/lib/swarm_sdk/node_context.rb +1 -1
  62. data/lib/swarm_sdk/observer/builder.rb +81 -0
  63. data/lib/swarm_sdk/observer/config.rb +45 -0
  64. data/lib/swarm_sdk/observer/manager.rb +236 -0
  65. data/lib/swarm_sdk/patterns/agent_observer.rb +160 -0
  66. data/lib/swarm_sdk/plugin.rb +93 -3
  67. data/lib/swarm_sdk/proc_helpers.rb +53 -0
  68. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -126
  69. data/lib/swarm_sdk/restore_result.rb +65 -0
  70. data/lib/swarm_sdk/snapshot.rb +156 -0
  71. data/lib/swarm_sdk/snapshot_from_events.rb +397 -0
  72. data/lib/swarm_sdk/state_restorer.rb +476 -0
  73. data/lib/swarm_sdk/state_snapshot.rb +334 -0
  74. data/lib/swarm_sdk/swarm/agent_initializer.rb +428 -79
  75. data/lib/swarm_sdk/swarm/all_agents_builder.rb +28 -1
  76. data/lib/swarm_sdk/swarm/builder.rb +69 -407
  77. data/lib/swarm_sdk/swarm/executor.rb +213 -0
  78. data/lib/swarm_sdk/swarm/hook_triggers.rb +150 -0
  79. data/lib/swarm_sdk/swarm/logging_callbacks.rb +340 -0
  80. data/lib/swarm_sdk/swarm/mcp_configurator.rb +7 -4
  81. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +67 -0
  82. data/lib/swarm_sdk/swarm/tool_configurator.rb +88 -149
  83. data/lib/swarm_sdk/swarm.rb +366 -631
  84. data/lib/swarm_sdk/swarm_loader.rb +145 -0
  85. data/lib/swarm_sdk/swarm_registry.rb +136 -0
  86. data/lib/swarm_sdk/tools/bash.rb +11 -3
  87. data/lib/swarm_sdk/tools/delegate.rb +127 -24
  88. data/lib/swarm_sdk/tools/edit.rb +8 -13
  89. data/lib/swarm_sdk/tools/glob.rb +9 -1
  90. data/lib/swarm_sdk/tools/grep.rb +7 -0
  91. data/lib/swarm_sdk/tools/multi_edit.rb +15 -11
  92. data/lib/swarm_sdk/tools/path_resolver.rb +51 -2
  93. data/lib/swarm_sdk/tools/read.rb +28 -18
  94. data/lib/swarm_sdk/tools/registry.rb +122 -10
  95. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +23 -2
  96. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +23 -2
  97. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +21 -4
  98. data/lib/swarm_sdk/tools/stores/read_tracker.rb +47 -12
  99. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +53 -5
  100. data/lib/swarm_sdk/tools/stores/storage.rb +0 -6
  101. data/lib/swarm_sdk/tools/think.rb +4 -1
  102. data/lib/swarm_sdk/tools/todo_write.rb +27 -8
  103. data/lib/swarm_sdk/tools/web_fetch.rb +3 -2
  104. data/lib/swarm_sdk/tools/write.rb +8 -13
  105. data/lib/swarm_sdk/utils.rb +18 -0
  106. data/lib/swarm_sdk/validation_result.rb +33 -0
  107. data/lib/swarm_sdk/version.rb +1 -1
  108. data/lib/swarm_sdk/{node → workflow}/agent_config.rb +34 -9
  109. data/lib/swarm_sdk/workflow/builder.rb +143 -0
  110. data/lib/swarm_sdk/workflow/executor.rb +497 -0
  111. data/lib/swarm_sdk/{node/builder.rb → workflow/node_builder.rb} +42 -21
  112. data/lib/swarm_sdk/{node → workflow}/transformer_executor.rb +3 -2
  113. data/lib/swarm_sdk/workflow.rb +554 -0
  114. data/lib/swarm_sdk.rb +393 -22
  115. metadata +51 -16
  116. data/lib/swarm_memory/chat_extension.rb +0 -34
  117. data/lib/swarm_sdk/node_orchestrator.rb +0 -591
  118. data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -582
@@ -82,7 +82,10 @@ module SwarmSDK
82
82
  required: true
83
83
 
84
84
  def execute(**kwargs)
85
- "Thought noted."
85
+ <<~RESP
86
+ Thought noted.
87
+ RESP
88
+ # <system-reminder>The user cannot see your thoughts. You MUST NOT stop without giving the user a response.</system-reminder>
86
89
  end
87
90
 
88
91
  private
@@ -7,18 +7,25 @@ module SwarmSDK
7
7
  # This tool helps agents track progress on complex multi-step tasks.
8
8
  # Each agent maintains its own independent todo list.
9
9
  class TodoWrite < RubyLLM::Tool
10
+ # Factory pattern: declare what parameters this tool needs for instantiation
11
+ class << self
12
+ def creation_requirements
13
+ [:agent_name]
14
+ end
15
+ end
16
+
10
17
  description <<~DESC
11
- Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
18
+ Use this tool to create and manage a structured task list for your current work session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
12
19
  It also helps the user understand the progress of the task and overall progress of their requests.
13
20
 
14
21
  ## When to Use This Tool
15
22
  Use this tool proactively in these scenarios:
16
23
 
17
24
  **CRITICAL**: Follow this workflow for multi-step tasks:
18
- 1. FIRST: Analyze the task scope (search files, read code, understand requirements)
19
- 2. SECOND: Create a COMPLETE todo list with ALL known tasks BEFORE starting implementation
25
+ 1. FIRST: Analyze the task scope (gather information, understand requirements)
26
+ 2. SECOND: Create a COMPLETE todo list with ALL known tasks BEFORE starting work
20
27
  3. THIRD: Execute tasks, marking in_progress → completed as you work
21
- 4. ONLY add new todos if unexpected work is discovered during implementation
28
+ 4. ONLY add new todos if unexpected work is discovered during execution
22
29
 
23
30
  Use the todo list when:
24
31
  1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
@@ -27,7 +34,7 @@ module SwarmSDK
27
34
  4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
28
35
  5. After receiving new instructions - After analyzing scope, create complete todo list before starting work
29
36
  6. When you start working on a task - Mark it as in_progress BEFORE beginning work. Ideally you should only have one todo as in_progress at a time
30
- 7. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
37
+ 7. After completing a task - Mark it as completed and add any new follow-up tasks discovered during execution
31
38
 
32
39
  ## When NOT to Use This Tool
33
40
 
@@ -73,9 +80,21 @@ module SwarmSDK
73
80
  - Create specific, actionable items
74
81
  - Break complex tasks into smaller, manageable steps
75
82
  - Use clear, descriptive task names
76
- - Always provide both forms:
77
- - content: "Fix authentication bug"
78
- - activeForm: "Fixing authentication bug"
83
+ - Always provide both forms (content and activeForm)
84
+
85
+ ## Examples
86
+
87
+ **Coding Tasks**:
88
+ - content: "Fix authentication bug in login handler"
89
+ - activeForm: "Fixing authentication bug in login handler"
90
+
91
+ **Non-Coding Tasks**:
92
+ - content: "Analyze customer feedback from Q4 survey"
93
+ - activeForm: "Analyzing customer feedback from Q4 survey"
94
+
95
+ **Research Tasks**:
96
+ - content: "Research best practices for API rate limiting"
97
+ - activeForm: "Researching best practices for API rate limiting"
79
98
 
80
99
  When in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully.
81
100
  DESC
@@ -51,9 +51,10 @@ module SwarmSDK
51
51
  desc: "The prompt to run on the fetched content. Required when SwarmSDK is configured with webfetch_provider and webfetch_model. Optional otherwise (ignored if LLM processing not configured).",
52
52
  required: false
53
53
 
54
- MAX_CONTENT_LENGTH = 100_000 # characters
54
+ # Backward compatibility aliases - use Defaults module for new code
55
+ MAX_CONTENT_LENGTH = Defaults::Limits::WEB_FETCH_CHARACTERS
55
56
  USER_AGENT = "SwarmSDK WebFetch Tool (https://github.com/parruda/claude-swarm)"
56
- TIMEOUT = 30 # seconds
57
+ TIMEOUT = Defaults::Timeouts::WEB_FETCH_SECONDS
57
58
 
58
59
  def execute(url:, prompt: nil)
59
60
  # Validate inputs
@@ -10,6 +10,13 @@ module SwarmSDK
10
10
  class Write < RubyLLM::Tool
11
11
  include PathResolver
12
12
 
13
+ # Factory pattern: declare what parameters this tool needs for instantiation
14
+ class << self
15
+ def creation_requirements
16
+ [:agent_name, :directory]
17
+ end
18
+ end
19
+
13
20
  description <<~DESC
14
21
  Writes a file to the local filesystem.
15
22
  This tool will overwrite the existing file if there is one at the provided path.
@@ -42,8 +49,7 @@ module SwarmSDK
42
49
  # @param directory [String] Agent's working directory
43
50
  def initialize(agent_name:, directory:)
44
51
  super()
45
- @agent_name = agent_name.to_sym
46
- @directory = File.expand_path(directory)
52
+ initialize_agent_context(agent_name: agent_name, directory: directory)
47
53
  end
48
54
 
49
55
  # Override name to return simple "Write" instead of full class path
@@ -101,17 +107,6 @@ module SwarmSDK
101
107
  rescue StandardError => e
102
108
  error("Unexpected error writing file: #{e.class.name} - #{e.message}")
103
109
  end
104
-
105
- private
106
-
107
- # Helper methods
108
- def validation_error(message)
109
- "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
110
- end
111
-
112
- def error(message)
113
- "Error: #{message}"
114
- end
115
110
  end
116
111
  end
117
112
  end
@@ -45,6 +45,24 @@ module SwarmSDK
45
45
  obj
46
46
  end
47
47
  end
48
+
49
+ # Convert hash to YAML string
50
+ #
51
+ # Converts a Ruby hash to a YAML string. Useful for creating inline
52
+ # swarm definitions from hash configurations.
53
+ #
54
+ # @param hash [Hash] Hash to convert
55
+ # @return [String] YAML string representation
56
+ #
57
+ # @example
58
+ # config = { version: 2, swarm: { name: "Test" } }
59
+ # Utils.hash_to_yaml(config)
60
+ # # => "---\nversion: 2\nswarm:\n name: Test\n"
61
+ def hash_to_yaml(hash)
62
+ # Convert symbols to strings for valid YAML
63
+ stringified = stringify_keys(hash)
64
+ stringified.to_yaml
65
+ end
48
66
  end
49
67
  end
50
68
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SwarmSDK
4
+ # Internal result object for validation phase during snapshot restore
5
+ #
6
+ # Used during restore to track which agents can be restored and which
7
+ # need to be skipped due to configuration mismatches.
8
+ #
9
+ # @api private
10
+ class ValidationResult
11
+ attr_reader :warnings,
12
+ :skipped_agents,
13
+ :restorable_agents,
14
+ :skipped_delegations,
15
+ :restorable_delegations
16
+
17
+ # Initialize validation result
18
+ #
19
+ # @param warnings [Array<Hash>] Warning messages with details
20
+ # @param skipped_agents [Array<Symbol>] Names of agents that can't be restored
21
+ # @param restorable_agents [Array<Symbol>] Names of agents that can be restored
22
+ # @param skipped_delegations [Array<String>] Names of delegations that can't be restored
23
+ # @param restorable_delegations [Array<String>] Names of delegations that can be restored
24
+ def initialize(warnings:, skipped_agents:, restorable_agents:,
25
+ skipped_delegations:, restorable_delegations:)
26
+ @warnings = warnings
27
+ @skipped_agents = skipped_agents
28
+ @restorable_agents = restorable_agents
29
+ @skipped_delegations = skipped_delegations
30
+ @restorable_delegations = restorable_delegations
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmSDK
4
- VERSION = "2.1.2"
4
+ VERSION = "2.3.0"
5
5
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmSDK
4
- module Node
4
+ class Workflow
5
5
  # AgentConfig provides fluent API for configuring agents within a node
6
6
  #
7
7
  # This class enables the chainable syntax:
8
8
  # agent(:backend).delegates_to(:tester, :database)
9
9
  # agent(:backend, reset_context: false) # Preserve context across nodes
10
+ # agent(:backend).tools(:Read, :Edit) # Override tools for this node
10
11
  #
11
12
  # @example Basic delegation
12
13
  # agent(:backend).delegates_to(:tester)
@@ -16,6 +17,12 @@ module SwarmSDK
16
17
  #
17
18
  # @example Preserve agent context
18
19
  # agent(:architect, reset_context: false)
20
+ #
21
+ # @example Override tools for this node
22
+ # agent(:backend).tools(:Read, :Think)
23
+ #
24
+ # @example Combine delegation and tool override
25
+ # agent(:backend).delegates_to(:tester).tools(:Read, :Edit, :Write)
19
26
  class AgentConfig
20
27
  attr_reader :agent_name
21
28
 
@@ -24,6 +31,7 @@ module SwarmSDK
24
31
  @node_builder = node_builder
25
32
  @delegates_to = []
26
33
  @reset_context = reset_context
34
+ @tools = nil # nil means use global agent definition tools
27
35
  @finalized = false
28
36
  end
29
37
 
@@ -33,21 +41,38 @@ module SwarmSDK
33
41
  # @return [self] For method chaining
34
42
  def delegates_to(*agent_names)
35
43
  @delegates_to = agent_names.map(&:to_sym)
36
- finalize
44
+ update_registration
37
45
  self
38
46
  end
39
47
 
40
- # Finalize agent configuration (called automatically)
48
+ # Override tools for this agent in this node
49
+ #
50
+ # @param tool_names [Array<Symbol>] Tool names to use (overrides global agent definition)
51
+ # @return [self] For method chaining
41
52
  #
42
- # Registers this agent configuration with the parent node builder.
43
- # If delegates_to was never called, registers with empty delegation.
53
+ # @example
54
+ # agent(:backend).tools(:Read, :Edit)
55
+ def tools(*tool_names)
56
+ @tools = tool_names.map(&:to_sym)
57
+ update_registration
58
+ self
59
+ end
60
+
61
+ # Update agent registration (called after each fluent method)
62
+ #
63
+ # Always updates the registration with current state.
64
+ # This allows chaining: .delegates_to(...).tools(...)
44
65
  #
45
66
  # @return [void]
46
- def finalize
47
- return if @finalized
67
+ def update_registration
68
+ @node_builder.register_agent(@agent_name, @delegates_to, @reset_context, @tools)
69
+ end
48
70
 
49
- @node_builder.register_agent(@agent_name, @delegates_to, @reset_context)
50
- @finalized = true
71
+ # Finalize agent configuration (backward compatibility)
72
+ #
73
+ # @return [void]
74
+ def finalize
75
+ update_registration
51
76
  end
52
77
  end
53
78
  end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SwarmSDK
4
+ class Workflow
5
+ # Builder provides DSL for building multi-node workflows
6
+ # This is the top-level builder accessed via SwarmSDK.workflow
7
+ #
8
+ # The DSL enables:
9
+ # - Node-based workflow configuration
10
+ # - Agent delegation per node
11
+ # - Input/output transformers for data flow
12
+ # - Context preservation across nodes
13
+ #
14
+ # @example Multi-stage workflow
15
+ # workflow = SwarmSDK.workflow do
16
+ # name "Build Pipeline"
17
+ # start_node :planning
18
+ #
19
+ # agent :architect do
20
+ # model "gpt-5"
21
+ # prompt "You design systems"
22
+ # end
23
+ #
24
+ # agent :coder do
25
+ # model "gpt-4"
26
+ # prompt "You implement code"
27
+ # end
28
+ #
29
+ # node :planning do
30
+ # agent(:architect)
31
+ # end
32
+ #
33
+ # node :implementation do
34
+ # agent(:coder)
35
+ # depends_on :planning
36
+ # end
37
+ # end
38
+ #
39
+ # workflow.execute("Build auth system")
40
+ class Builder < Builders::BaseBuilder
41
+ # Main entry point for DSL
42
+ #
43
+ # @example
44
+ # workflow = SwarmSDK.workflow do
45
+ # name "Pipeline"
46
+ # start_node :planning
47
+ # node(:planning) { agent(:architect) }
48
+ # end
49
+ class << self
50
+ def build(allow_filesystem_tools: nil, &block)
51
+ builder = new(allow_filesystem_tools: allow_filesystem_tools)
52
+ builder.instance_eval(&block)
53
+ builder.build_swarm
54
+ end
55
+ end
56
+
57
+ def initialize(allow_filesystem_tools: nil)
58
+ super
59
+ @nodes = {}
60
+ @start_node = nil
61
+ end
62
+
63
+ # Define a node (mini-swarm execution stage)
64
+ #
65
+ # Nodes enable multi-stage workflows where different agent teams
66
+ # collaborate in sequence. Each node is an independent swarm execution.
67
+ #
68
+ # @param name [Symbol] Node name
69
+ # @yield Block for node configuration
70
+ # @return [void]
71
+ #
72
+ # @example Solo agent node
73
+ # node :planning do
74
+ # agent(:architect)
75
+ # end
76
+ #
77
+ # @example Multi-agent node with delegation
78
+ # node :implementation do
79
+ # agent(:backend).delegates_to(:tester, :database)
80
+ # agent(:tester).delegates_to(:database)
81
+ # agent(:database)
82
+ # depends_on :planning
83
+ # end
84
+ def node(name, &block)
85
+ builder = Workflow::NodeBuilder.new(name)
86
+ builder.instance_eval(&block)
87
+ @nodes[name] = builder
88
+ end
89
+
90
+ # Set the starting node for workflow execution
91
+ #
92
+ # Required when nodes are defined. Specifies which node to execute first.
93
+ #
94
+ # @param name [Symbol] Name of starting node
95
+ # @return [void]
96
+ #
97
+ # @example
98
+ # start_node :planning
99
+ def start_node(name)
100
+ @start_node = name.to_sym
101
+ end
102
+
103
+ # Build the actual Workflow instance
104
+ def build_swarm # Returns Workflow despite method name
105
+ raise ConfigurationError, "Workflow name not set. Use: name 'My Workflow'" unless @swarm_name
106
+ raise ConfigurationError, "No nodes defined. Use: node :name { ... }" if @nodes.empty?
107
+ raise ConfigurationError, "start_node not set. Use: start_node :name" unless @start_node
108
+
109
+ # Validate filesystem tools BEFORE building
110
+ validate_all_agents_filesystem_tools if @all_agents_config
111
+ validate_agent_filesystem_tools
112
+
113
+ build_workflow
114
+ end
115
+
116
+ private
117
+
118
+ # Build a node-based workflow
119
+ #
120
+ # @return [Workflow] Configured workflow instance
121
+ def build_workflow
122
+ # Build agent definitions
123
+ agent_definitions = build_agent_definitions
124
+
125
+ # Create workflow
126
+ workflow = Workflow.new(
127
+ swarm_name: @swarm_name,
128
+ swarm_id: @swarm_id,
129
+ agent_definitions: agent_definitions,
130
+ nodes: @nodes,
131
+ start_node: @start_node,
132
+ scratchpad: @scratchpad,
133
+ allow_filesystem_tools: @allow_filesystem_tools,
134
+ )
135
+
136
+ # Pass swarm registry config to workflow if external swarms registered
137
+ workflow.swarm_registry_config = @swarm_registry_config if @swarm_registry_config.any?
138
+
139
+ workflow
140
+ end
141
+ end
142
+ end
143
+ end