swarm_sdk 2.7.13 → 3.0.0.alpha1

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +43 -22
  3. data/lib/swarm_sdk/ruby_llm_patches/init.rb +6 -0
  4. data/lib/swarm_sdk/ruby_llm_patches/mcp_ssl_patch.rb +144 -0
  5. data/lib/swarm_sdk/ruby_llm_patches/tool_concurrency_patch.rb +3 -4
  6. data/lib/swarm_sdk/v3/agent.rb +1165 -0
  7. data/lib/swarm_sdk/v3/agent_builder.rb +533 -0
  8. data/lib/swarm_sdk/v3/agent_definition.rb +330 -0
  9. data/lib/swarm_sdk/v3/configuration.rb +490 -0
  10. data/lib/swarm_sdk/v3/debug_log.rb +86 -0
  11. data/lib/swarm_sdk/v3/event_stream.rb +130 -0
  12. data/lib/swarm_sdk/v3/hooks/context.rb +112 -0
  13. data/lib/swarm_sdk/v3/hooks/result.rb +115 -0
  14. data/lib/swarm_sdk/v3/hooks/runner.rb +128 -0
  15. data/lib/swarm_sdk/v3/mcp/connector.rb +183 -0
  16. data/lib/swarm_sdk/v3/mcp/mcp_error.rb +15 -0
  17. data/lib/swarm_sdk/v3/mcp/server_definition.rb +125 -0
  18. data/lib/swarm_sdk/v3/mcp/ssl_http_transport.rb +103 -0
  19. data/lib/swarm_sdk/v3/mcp/stdio_transport.rb +135 -0
  20. data/lib/swarm_sdk/v3/mcp/tool_proxy.rb +53 -0
  21. data/lib/swarm_sdk/v3/memory/adapters/base.rb +297 -0
  22. data/lib/swarm_sdk/v3/memory/adapters/faiss_support.rb +194 -0
  23. data/lib/swarm_sdk/v3/memory/adapters/filesystem_adapter.rb +212 -0
  24. data/lib/swarm_sdk/v3/memory/adapters/sqlite_adapter.rb +507 -0
  25. data/lib/swarm_sdk/v3/memory/adapters/vector_utils.rb +88 -0
  26. data/lib/swarm_sdk/v3/memory/card.rb +206 -0
  27. data/lib/swarm_sdk/v3/memory/cluster.rb +146 -0
  28. data/lib/swarm_sdk/v3/memory/compressor.rb +496 -0
  29. data/lib/swarm_sdk/v3/memory/consolidator.rb +427 -0
  30. data/lib/swarm_sdk/v3/memory/context_builder.rb +339 -0
  31. data/lib/swarm_sdk/v3/memory/edge.rb +105 -0
  32. data/lib/swarm_sdk/v3/memory/embedder.rb +185 -0
  33. data/lib/swarm_sdk/v3/memory/exposure_tracker.rb +104 -0
  34. data/lib/swarm_sdk/v3/memory/ingestion_pipeline.rb +394 -0
  35. data/lib/swarm_sdk/v3/memory/retriever.rb +289 -0
  36. data/lib/swarm_sdk/v3/memory/store.rb +489 -0
  37. data/lib/swarm_sdk/v3/skills/loader.rb +147 -0
  38. data/lib/swarm_sdk/v3/skills/manifest.rb +45 -0
  39. data/lib/swarm_sdk/v3/sub_task_agent.rb +248 -0
  40. data/lib/swarm_sdk/v3/tools/base.rb +80 -0
  41. data/lib/swarm_sdk/v3/tools/bash.rb +174 -0
  42. data/lib/swarm_sdk/v3/tools/clock.rb +32 -0
  43. data/lib/swarm_sdk/v3/tools/edit.rb +111 -0
  44. data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
  45. data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
  46. data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
  47. data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
  48. data/lib/swarm_sdk/v3/tools/read.rb +181 -0
  49. data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
  50. data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
  51. data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
  52. data/lib/swarm_sdk/v3/tools/think.rb +88 -0
  53. data/lib/swarm_sdk/v3/tools/write.rb +87 -0
  54. data/lib/swarm_sdk/v3.rb +145 -0
  55. metadata +84 -148
  56. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
  57. data/lib/swarm_sdk/agent/builder.rb +0 -680
  58. data/lib/swarm_sdk/agent/chat.rb +0 -1432
  59. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
  60. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  61. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  62. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -85
  63. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
  64. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  65. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  66. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -134
  67. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  68. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
  69. data/lib/swarm_sdk/agent/context.rb +0 -115
  70. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  71. data/lib/swarm_sdk/agent/definition.rb +0 -581
  72. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
  73. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  74. data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
  75. data/lib/swarm_sdk/agent_registry.rb +0 -146
  76. data/lib/swarm_sdk/builders/base_builder.rb +0 -553
  77. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  78. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  79. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  80. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  81. data/lib/swarm_sdk/config.rb +0 -367
  82. data/lib/swarm_sdk/configuration/parser.rb +0 -397
  83. data/lib/swarm_sdk/configuration/translator.rb +0 -283
  84. data/lib/swarm_sdk/configuration.rb +0 -165
  85. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  86. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
  87. data/lib/swarm_sdk/context_compactor.rb +0 -335
  88. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  89. data/lib/swarm_sdk/context_management/context.rb +0 -328
  90. data/lib/swarm_sdk/custom_tool_registry.rb +0 -226
  91. data/lib/swarm_sdk/defaults.rb +0 -251
  92. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  93. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  94. data/lib/swarm_sdk/hooks/context.rb +0 -197
  95. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  96. data/lib/swarm_sdk/hooks/error.rb +0 -29
  97. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  98. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  99. data/lib/swarm_sdk/hooks/result.rb +0 -150
  100. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -256
  101. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  102. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  103. data/lib/swarm_sdk/log_collector.rb +0 -227
  104. data/lib/swarm_sdk/log_stream.rb +0 -127
  105. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  106. data/lib/swarm_sdk/model_aliases.json +0 -8
  107. data/lib/swarm_sdk/models.json +0 -44002
  108. data/lib/swarm_sdk/models.rb +0 -161
  109. data/lib/swarm_sdk/node_context.rb +0 -245
  110. data/lib/swarm_sdk/observer/builder.rb +0 -81
  111. data/lib/swarm_sdk/observer/config.rb +0 -45
  112. data/lib/swarm_sdk/observer/manager.rb +0 -236
  113. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  114. data/lib/swarm_sdk/permissions/config.rb +0 -239
  115. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  116. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  117. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  118. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  119. data/lib/swarm_sdk/plugin.rb +0 -309
  120. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  121. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  122. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  123. data/lib/swarm_sdk/restore_result.rb +0 -65
  124. data/lib/swarm_sdk/result.rb +0 -212
  125. data/lib/swarm_sdk/snapshot.rb +0 -156
  126. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  127. data/lib/swarm_sdk/state_restorer.rb +0 -476
  128. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  129. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -648
  130. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -195
  131. data/lib/swarm_sdk/swarm/builder.rb +0 -256
  132. data/lib/swarm_sdk/swarm/executor.rb +0 -290
  133. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -151
  134. data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
  135. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -360
  136. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -270
  137. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  138. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
  139. data/lib/swarm_sdk/swarm.rb +0 -843
  140. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  141. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  142. data/lib/swarm_sdk/tools/base.rb +0 -63
  143. data/lib/swarm_sdk/tools/bash.rb +0 -280
  144. data/lib/swarm_sdk/tools/clock.rb +0 -46
  145. data/lib/swarm_sdk/tools/delegate.rb +0 -389
  146. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  147. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  148. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  149. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  150. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  151. data/lib/swarm_sdk/tools/edit.rb +0 -145
  152. data/lib/swarm_sdk/tools/glob.rb +0 -166
  153. data/lib/swarm_sdk/tools/grep.rb +0 -235
  154. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  155. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -167
  156. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  157. data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
  158. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  159. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  160. data/lib/swarm_sdk/tools/read.rb +0 -261
  161. data/lib/swarm_sdk/tools/registry.rb +0 -205
  162. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  165. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  166. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -273
  167. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  168. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  169. data/lib/swarm_sdk/tools/think.rb +0 -100
  170. data/lib/swarm_sdk/tools/todo_write.rb +0 -237
  171. data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
  172. data/lib/swarm_sdk/tools/write.rb +0 -112
  173. data/lib/swarm_sdk/transcript_builder.rb +0 -278
  174. data/lib/swarm_sdk/utils.rb +0 -68
  175. data/lib/swarm_sdk/validation_result.rb +0 -33
  176. data/lib/swarm_sdk/version.rb +0 -5
  177. data/lib/swarm_sdk/workflow/agent_config.rb +0 -95
  178. data/lib/swarm_sdk/workflow/builder.rb +0 -227
  179. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  180. data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
  181. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
  182. data/lib/swarm_sdk/workflow.rb +0 -589
  183. data/lib/swarm_sdk.rb +0 -718
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- # Write tool for writing content to files
6
- #
7
- # Creates new files or overwrites existing files.
8
- # Enforces read-before-write rule for existing files.
9
- # Includes validation and usage guidelines via system reminders.
10
- class Write < Base
11
- include PathResolver
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
-
20
- description <<~DESC
21
- Writes a file to the local filesystem.
22
- This tool will overwrite the existing file if there is one at the provided path.
23
- If this is an existing file, you MUST use the Read tool first to read the file's contents.
24
- This tool will fail if you did not read the file first.
25
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
26
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
27
- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.
28
-
29
- IMPORTANT - Path Handling:
30
- - Relative paths (e.g., "tmp/file.txt", "src/main.rb") are resolved relative to your agent's working directory
31
- - Absolute paths (e.g., "/tmp/file.txt", "/etc/passwd") are treated as system absolute paths
32
- - When the user says "tmp/file.txt" they mean the tmp directory in your working directory, NOT /tmp
33
- - Only use absolute paths (starting with /) when explicitly referring to system-level paths
34
- DESC
35
-
36
- param :file_path,
37
- type: "string",
38
- desc: "Path to the file. Use relative paths (e.g., 'tmp/file.txt') for files in your working directory, or absolute paths (e.g., '/etc/passwd') for system files.",
39
- required: true
40
-
41
- param :content,
42
- type: "string",
43
- desc: "The content to write to the file",
44
- required: true
45
-
46
- # Initialize the Write tool for a specific agent
47
- #
48
- # @param agent_name [Symbol, String] The agent identifier
49
- # @param directory [String] Agent's working directory
50
- def initialize(agent_name:, directory:)
51
- super()
52
- initialize_agent_context(agent_name: agent_name, directory: directory)
53
- end
54
-
55
- # Override name to return simple "Write" instead of full class path
56
- def name
57
- "Write"
58
- end
59
-
60
- def execute(file_path:, content:)
61
- # Validate inputs
62
- return validation_error("file_path is required") if file_path.nil? || file_path.to_s.strip.empty?
63
- return validation_error("content is required") if content.nil?
64
-
65
- # CRITICAL: Resolve path against agent directory
66
- resolved_path = resolve_path(file_path)
67
-
68
- # Check if file already exists (use resolved path)
69
- file_exists = File.exist?(resolved_path)
70
-
71
- # Enforce read-before-write for existing files (use resolved path)
72
- if file_exists && !Stores::ReadTracker.file_read?(@agent_name, resolved_path)
73
- return validation_error(
74
- "Cannot write to existing file without reading it first. " \
75
- "You must use the Read tool on '#{file_path}' before overwriting it. " \
76
- "This ensures you have context about the file's current contents.",
77
- )
78
- end
79
-
80
- # Create parent directory if it doesn't exist (use resolved path)
81
- parent_dir = File.dirname(resolved_path)
82
- FileUtils.mkdir_p(parent_dir) unless File.directory?(parent_dir)
83
-
84
- # Write the file (use resolved path)
85
- File.write(resolved_path, content, encoding: "UTF-8")
86
-
87
- # Build success message
88
- byte_size = content.bytesize
89
- line_count = content.lines.count
90
- action = file_exists ? "overwrote" : "created"
91
-
92
- message = "Successfully #{action} file: #{file_path} (#{line_count} lines, #{byte_size} bytes)"
93
-
94
- # Add system reminder for overwritten files
95
- if file_exists
96
- reminder = "<system-reminder>You overwrote an existing file. Make sure this was intentional and that you read the file first if you needed to preserve any content.</system-reminder>"
97
- "#{message}\n\n#{reminder}"
98
- else
99
- message
100
- end
101
- rescue Errno::EACCES
102
- error("Permission denied: Cannot write to file '#{file_path}'")
103
- rescue Errno::EISDIR
104
- error("Path is a directory, not a file.")
105
- rescue Errno::ENOENT => e
106
- error("Failed to create parent directory: #{e.message}")
107
- rescue StandardError => e
108
- error("Unexpected error writing file: #{e.class.name} - #{e.message}")
109
- end
110
- end
111
- end
112
- end
@@ -1,278 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Transforms raw log events into LLM-readable conversation transcripts
5
- #
6
- # TranscriptBuilder converts the structured event log from swarm execution
7
- # into a human/LLM-readable format suitable for reflection, analysis, or
8
- # memory creation.
9
- #
10
- # @example Basic usage
11
- # transcript = TranscriptBuilder.build(result.logs)
12
- # # => "USER: Help me with CORS\n\nAGENT [assistant]: ..."
13
- #
14
- # @example Filter by agents
15
- # transcript = TranscriptBuilder.build(result.logs, agents: [:backend, :database])
16
- #
17
- # @example Custom options
18
- # transcript = TranscriptBuilder.build(
19
- # result.logs,
20
- # include_tool_results: true,
21
- # max_result_length: 1000,
22
- # include_thinking: false
23
- # )
24
- class TranscriptBuilder
25
- # Default maximum length for tool result content
26
- DEFAULT_MAX_RESULT_LENGTH = 500
27
-
28
- # Default maximum length for tool arguments
29
- DEFAULT_MAX_ARGS_LENGTH = 200
30
-
31
- class << self
32
- # Build a transcript from log events
33
- #
34
- # @param logs [Array<Hash>] Array of log events from Result#logs
35
- # @param agents [Array<Symbol>, nil] Filter to specific agents (nil = all)
36
- # @param include_tool_results [Boolean] Include tool execution results (default: true)
37
- # @param include_thinking [Boolean] Include agent_step content/thinking (default: false)
38
- # @param max_result_length [Integer] Maximum characters for tool results
39
- # @param max_args_length [Integer] Maximum characters for tool arguments
40
- # @return [String] Formatted transcript
41
- def build(logs, agents: nil, include_tool_results: true, include_thinking: false,
42
- max_result_length: DEFAULT_MAX_RESULT_LENGTH, max_args_length: DEFAULT_MAX_ARGS_LENGTH)
43
- new(
44
- logs,
45
- agents: agents,
46
- include_tool_results: include_tool_results,
47
- include_thinking: include_thinking,
48
- max_result_length: max_result_length,
49
- max_args_length: max_args_length,
50
- ).build
51
- end
52
- end
53
-
54
- # Initialize a new TranscriptBuilder
55
- #
56
- # @param logs [Array<Hash>] Array of log events
57
- # @param agents [Array<Symbol>, nil] Filter to specific agents
58
- # @param include_tool_results [Boolean] Include tool execution results
59
- # @param include_thinking [Boolean] Include agent_step content
60
- # @param max_result_length [Integer] Maximum characters for tool results
61
- # @param max_args_length [Integer] Maximum characters for tool arguments
62
- def initialize(logs, agents: nil, include_tool_results: true, include_thinking: false,
63
- max_result_length: DEFAULT_MAX_RESULT_LENGTH, max_args_length: DEFAULT_MAX_ARGS_LENGTH)
64
- @logs = logs || []
65
- @agents = normalize_agents(agents)
66
- @include_tool_results = include_tool_results
67
- @include_thinking = include_thinking
68
- @max_result_length = max_result_length
69
- @max_args_length = max_args_length
70
- end
71
-
72
- # Build the transcript
73
- #
74
- # @return [String] Formatted transcript
75
- def build
76
- @logs
77
- .filter_map { |event| format_event(event) }
78
- .join("\n\n")
79
- end
80
-
81
- private
82
-
83
- # Normalize agent filter to array of symbols
84
- #
85
- # @param agents [Array, Symbol, String, nil] Agent filter input
86
- # @return [Array<Symbol>, nil] Normalized agent list or nil for all
87
- def normalize_agents(agents)
88
- return if agents.nil? || (agents.is_a?(Array) && agents.empty?)
89
-
90
- Array(agents).map(&:to_sym)
91
- end
92
-
93
- # Check if event passes agent filter
94
- #
95
- # @param event [Hash] Log event
96
- # @return [Boolean] True if event should be included
97
- def passes_agent_filter?(event)
98
- return true if @agents.nil?
99
-
100
- agent = event[:agent] || event["agent"]
101
- return true if agent.nil? # Include events without agent (like swarm_start)
102
-
103
- @agents.include?(agent.to_sym)
104
- end
105
-
106
- # Format a single event into transcript text
107
- #
108
- # @param event [Hash] Log event
109
- # @return [String, nil] Formatted text or nil to skip
110
- def format_event(event)
111
- return unless passes_agent_filter?(event)
112
-
113
- type = event[:type] || event["type"]
114
-
115
- case type
116
- when "user_prompt"
117
- format_user_prompt(event)
118
- when "agent_step"
119
- format_agent_step(event)
120
- when "agent_stop"
121
- format_agent_stop(event)
122
- when "tool_call"
123
- format_tool_call(event)
124
- when "tool_result"
125
- format_tool_result(event)
126
- when "pre_delegation", "delegation_start"
127
- format_delegation_start(event)
128
- when "post_delegation", "delegation_complete"
129
- format_delegation_complete(event)
130
- end
131
- end
132
-
133
- # Format user_prompt event
134
- #
135
- # @param event [Hash] Event data
136
- # @return [String, nil] Formatted text
137
- def format_user_prompt(event)
138
- prompt = event[:prompt] || event["prompt"]
139
- return if prompt.nil? || prompt.to_s.strip.empty?
140
-
141
- agent = event[:agent] || event["agent"]
142
- source = event[:source] || event["source"] || "user"
143
-
144
- # Show source if it's a delegation or system message
145
- prefix = case source.to_s
146
- when "delegation"
147
- "DELEGATION REQUEST"
148
- when "system"
149
- "SYSTEM"
150
- else
151
- "USER"
152
- end
153
-
154
- if agent && source.to_s != "user"
155
- "#{prefix} → [#{agent}]: #{prompt}"
156
- else
157
- "#{prefix}: #{prompt}"
158
- end
159
- end
160
-
161
- # Format agent_step event (intermediate response with tool calls)
162
- #
163
- # @param event [Hash] Event data
164
- # @return [String, nil] Formatted text
165
- def format_agent_step(event)
166
- return unless @include_thinking
167
-
168
- content = event[:content] || event["content"]
169
- return if content.nil? || content.to_s.strip.empty?
170
-
171
- agent = event[:agent] || event["agent"]
172
- "AGENT [#{agent}] (thinking): #{content}"
173
- end
174
-
175
- # Format agent_stop event (final response)
176
- #
177
- # @param event [Hash] Event data
178
- # @return [String, nil] Formatted text
179
- def format_agent_stop(event)
180
- content = event[:content] || event["content"]
181
- return if content.nil? || content.to_s.strip.empty?
182
-
183
- agent = event[:agent] || event["agent"]
184
- "AGENT [#{agent}]: #{content}"
185
- end
186
-
187
- # Format tool_call event
188
- #
189
- # @param event [Hash] Event data
190
- # @return [String] Formatted text
191
- def format_tool_call(event)
192
- tool = event[:tool] || event["tool"] || event[:tool_name] || event["tool_name"]
193
- agent = event[:agent] || event["agent"]
194
- arguments = event[:arguments] || event["arguments"]
195
-
196
- args_str = format_arguments(arguments)
197
- "TOOL [#{agent}] → #{tool}(#{args_str})"
198
- end
199
-
200
- # Format tool_result event
201
- #
202
- # @param event [Hash] Event data
203
- # @return [String, nil] Formatted text
204
- def format_tool_result(event)
205
- return unless @include_tool_results
206
-
207
- tool = event[:tool] || event["tool"] || event[:tool_name] || event["tool_name"]
208
- result = event[:result] || event["result"]
209
- # Use key existence check since false || nil would lose the false value
210
- success = event.key?(:success) ? event[:success] : event["success"]
211
-
212
- # Handle RubyLLM::ToolResult objects
213
- result_content = if result.respond_to?(:content)
214
- result.content
215
- else
216
- result.to_s
217
- end
218
-
219
- truncated = truncate(result_content, @max_result_length)
220
-
221
- status = success == false ? " [FAILED]" : ""
222
- "RESULT [#{tool}]#{status}: #{truncated}"
223
- end
224
-
225
- # Format delegation_start event
226
- #
227
- # @param event [Hash] Event data
228
- # @return [String, nil] Formatted text
229
- def format_delegation_start(event)
230
- from = event[:from_agent] || event["from_agent"] || event[:agent] || event["agent"]
231
- to = event[:to_agent] || event["to_agent"]
232
- task = event[:task] || event["task"] || event[:message] || event["message"]
233
-
234
- return unless to
235
-
236
- task_preview = truncate(task.to_s, 200)
237
- "DELEGATE: #{from} → #{to}: #{task_preview}"
238
- end
239
-
240
- # Format delegation_complete event
241
- #
242
- # @param event [Hash] Event data
243
- # @return [String, nil] Formatted text
244
- def format_delegation_complete(event)
245
- from = event[:from_agent] || event["from_agent"] || event[:agent] || event["agent"]
246
- to = event[:to_agent] || event["to_agent"]
247
-
248
- return unless to
249
-
250
- "DELEGATE COMPLETE: #{to} → #{from}"
251
- end
252
-
253
- # Format tool arguments for display
254
- #
255
- # @param arguments [Hash, String, nil] Tool arguments
256
- # @return [String] Formatted arguments
257
- def format_arguments(arguments)
258
- return "{}" if arguments.nil?
259
-
260
- str = arguments.is_a?(String) ? arguments : arguments.to_json
261
- truncate(str, @max_args_length)
262
- end
263
-
264
- # Truncate text to maximum length with ellipsis
265
- #
266
- # @param text [String, nil] Text to truncate
267
- # @param max [Integer] Maximum length
268
- # @return [String] Truncated text
269
- def truncate(text, max)
270
- return "" if text.nil?
271
-
272
- str = text.to_s
273
- return str if str.length <= max
274
-
275
- "#{str[0...max]}..."
276
- end
277
- end
278
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Shared utility methods for SwarmSDK
5
- module Utils
6
- class << self
7
- # Recursively convert all hash keys to symbols
8
- #
9
- # Handles nested hashes and arrays containing hashes.
10
- #
11
- # @param obj [Object] Object to symbolize (Hash, Array, or other)
12
- # @return [Object] Object with symbolized keys (if applicable)
13
- #
14
- # @example
15
- # Utils.symbolize_keys({ "name" => "test", "config" => { "key" => "value" } })
16
- # # => { name: "test", config: { key: "value" } }
17
- def symbolize_keys(obj)
18
- case obj
19
- when Hash
20
- obj.transform_keys(&:to_sym).transform_values { |v| symbolize_keys(v) }
21
- when Array
22
- obj.map { |item| symbolize_keys(item) }
23
- else
24
- obj
25
- end
26
- end
27
-
28
- # Recursively convert all hash keys to strings
29
- #
30
- # Handles nested hashes and arrays containing hashes.
31
- #
32
- # @param obj [Object] Object to stringify (Hash, Array, or other)
33
- # @return [Object] Object with stringified keys (if applicable)
34
- #
35
- # @example
36
- # Utils.stringify_keys({ name: "test", config: { key: "value" } })
37
- # # => { "name" => "test", "config" => { "key" => "value" } }
38
- def stringify_keys(obj)
39
- case obj
40
- when Hash
41
- obj.transform_keys(&:to_s).transform_values { |v| stringify_keys(v) }
42
- when Array
43
- obj.map { |item| stringify_keys(item) }
44
- else
45
- obj
46
- end
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
66
- end
67
- end
68
- end
@@ -1,33 +0,0 @@
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 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- VERSION = "2.7.13"
5
- end
@@ -1,95 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Workflow
5
- # AgentConfig provides fluent API for configuring agents within a node
6
- #
7
- # This class enables the chainable syntax:
8
- # agent(:backend).delegates_to(:tester, :database)
9
- # agent(:backend, reset_context: false) # Preserve context across nodes
10
- # agent(:backend).tools(:Read, :Edit) # Override tools for this node
11
- #
12
- # @example Basic delegation
13
- # agent(:backend).delegates_to(:tester)
14
- #
15
- # @example No delegation (solo agent)
16
- # agent(:planner)
17
- #
18
- # @example Preserve agent context
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)
26
- class AgentConfig
27
- attr_reader :agent_name
28
-
29
- def initialize(agent_name, node_builder, reset_context: true)
30
- @agent_name = agent_name
31
- @node_builder = node_builder
32
- @delegates_to = []
33
- @reset_context = reset_context
34
- @tools = nil # nil means use global agent definition tools
35
- @finalized = false
36
- end
37
-
38
- # Set delegation targets for this agent
39
- #
40
- # Supports multiple formats for flexibility:
41
- # - Array: delegates_to(:frontend, :backend)
42
- # - Hash: delegates_to(frontend: "AskFrontend", backend: "GetBackend")
43
- #
44
- # @param agent_names_and_options [Array<Symbol, Hash>] Names and/or hash with custom tool names
45
- # @return [self] For method chaining
46
- def delegates_to(*agent_names_and_options)
47
- # Parse delegation configs (same logic as Agent::Builder)
48
- @delegates_to = []
49
- agent_names_and_options.each do |item|
50
- case item
51
- when Symbol, String
52
- @delegates_to << { agent: item.to_sym, tool_name: nil }
53
- when Hash
54
- item.each do |agent, tool_name|
55
- @delegates_to << { agent: agent.to_sym, tool_name: tool_name }
56
- end
57
- end
58
- end
59
-
60
- update_registration
61
- self
62
- end
63
-
64
- # Override tools for this agent in this node
65
- #
66
- # @param tool_names [Array<Symbol>] Tool names to use (overrides global agent definition)
67
- # @return [self] For method chaining
68
- #
69
- # @example
70
- # agent(:backend).tools(:Read, :Edit)
71
- def tools(*tool_names)
72
- @tools = tool_names.map(&:to_sym)
73
- update_registration
74
- self
75
- end
76
-
77
- # Update agent registration (called after each fluent method)
78
- #
79
- # Always updates the registration with current state.
80
- # This allows chaining: .delegates_to(...).tools(...)
81
- #
82
- # @return [void]
83
- def update_registration
84
- @node_builder.register_agent(@agent_name, @delegates_to, @reset_context, @tools)
85
- end
86
-
87
- # Finalize agent configuration (backward compatibility)
88
- #
89
- # @return [void]
90
- def finalize
91
- update_registration
92
- end
93
- end
94
- end
95
- end