swarm_sdk 2.7.14 → 3.0.0.alpha2

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +16 -0
  3. data/lib/swarm_sdk/ruby_llm_patches/init.rb +4 -1
  4. data/lib/swarm_sdk/v3/agent.rb +1165 -0
  5. data/lib/swarm_sdk/v3/agent_builder.rb +533 -0
  6. data/lib/swarm_sdk/v3/agent_definition.rb +330 -0
  7. data/lib/swarm_sdk/v3/configuration.rb +490 -0
  8. data/lib/swarm_sdk/v3/debug_log.rb +86 -0
  9. data/lib/swarm_sdk/v3/event_stream.rb +130 -0
  10. data/lib/swarm_sdk/v3/hooks/context.rb +112 -0
  11. data/lib/swarm_sdk/v3/hooks/result.rb +115 -0
  12. data/lib/swarm_sdk/v3/hooks/runner.rb +128 -0
  13. data/lib/swarm_sdk/v3/mcp/connector.rb +183 -0
  14. data/lib/swarm_sdk/v3/mcp/mcp_error.rb +15 -0
  15. data/lib/swarm_sdk/v3/mcp/server_definition.rb +125 -0
  16. data/lib/swarm_sdk/v3/mcp/ssl_http_transport.rb +103 -0
  17. data/lib/swarm_sdk/v3/mcp/stdio_transport.rb +135 -0
  18. data/lib/swarm_sdk/v3/mcp/tool_proxy.rb +53 -0
  19. data/lib/swarm_sdk/v3/memory/adapters/base.rb +297 -0
  20. data/lib/swarm_sdk/v3/memory/adapters/faiss_support.rb +194 -0
  21. data/lib/swarm_sdk/v3/memory/adapters/filesystem_adapter.rb +212 -0
  22. data/lib/swarm_sdk/v3/memory/adapters/sqlite_adapter.rb +507 -0
  23. data/lib/swarm_sdk/v3/memory/adapters/vector_utils.rb +88 -0
  24. data/lib/swarm_sdk/v3/memory/card.rb +206 -0
  25. data/lib/swarm_sdk/v3/memory/cluster.rb +146 -0
  26. data/lib/swarm_sdk/v3/memory/compressor.rb +496 -0
  27. data/lib/swarm_sdk/v3/memory/consolidator.rb +427 -0
  28. data/lib/swarm_sdk/v3/memory/context_builder.rb +339 -0
  29. data/lib/swarm_sdk/v3/memory/edge.rb +105 -0
  30. data/lib/swarm_sdk/v3/memory/embedder.rb +185 -0
  31. data/lib/swarm_sdk/v3/memory/exposure_tracker.rb +104 -0
  32. data/lib/swarm_sdk/v3/memory/ingestion_pipeline.rb +394 -0
  33. data/lib/swarm_sdk/v3/memory/retriever.rb +289 -0
  34. data/lib/swarm_sdk/v3/memory/store.rb +489 -0
  35. data/lib/swarm_sdk/v3/skills/loader.rb +147 -0
  36. data/lib/swarm_sdk/v3/skills/manifest.rb +45 -0
  37. data/lib/swarm_sdk/v3/sub_task_agent.rb +248 -0
  38. data/lib/swarm_sdk/v3/tools/base.rb +80 -0
  39. data/lib/swarm_sdk/v3/tools/bash.rb +174 -0
  40. data/lib/swarm_sdk/v3/tools/clock.rb +32 -0
  41. data/lib/swarm_sdk/v3/tools/document_converters/base.rb +84 -0
  42. data/lib/swarm_sdk/v3/tools/document_converters/docx_converter.rb +120 -0
  43. data/lib/swarm_sdk/v3/tools/document_converters/pdf_converter.rb +111 -0
  44. data/lib/swarm_sdk/v3/tools/document_converters/xlsx_converter.rb +128 -0
  45. data/lib/swarm_sdk/v3/tools/edit.rb +111 -0
  46. data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
  47. data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
  48. data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
  49. data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
  50. data/lib/swarm_sdk/v3/tools/read.rb +213 -0
  51. data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
  52. data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
  53. data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
  54. data/lib/swarm_sdk/v3/tools/think.rb +88 -0
  55. data/lib/swarm_sdk/v3/tools/write.rb +87 -0
  56. data/lib/swarm_sdk/v3.rb +145 -0
  57. metadata +88 -149
  58. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
  59. data/lib/swarm_sdk/agent/builder.rb +0 -705
  60. data/lib/swarm_sdk/agent/chat.rb +0 -1438
  61. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
  62. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  63. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  64. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -85
  65. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
  66. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  67. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  68. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -134
  69. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  70. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
  71. data/lib/swarm_sdk/agent/context.rb +0 -115
  72. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  73. data/lib/swarm_sdk/agent/definition.rb +0 -588
  74. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
  75. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -173
  76. data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
  77. data/lib/swarm_sdk/agent_registry.rb +0 -146
  78. data/lib/swarm_sdk/builders/base_builder.rb +0 -558
  79. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  80. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -42
  81. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  82. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  83. data/lib/swarm_sdk/config.rb +0 -368
  84. data/lib/swarm_sdk/configuration/parser.rb +0 -397
  85. data/lib/swarm_sdk/configuration/translator.rb +0 -285
  86. data/lib/swarm_sdk/configuration.rb +0 -165
  87. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  88. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
  89. data/lib/swarm_sdk/context_compactor.rb +0 -335
  90. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  91. data/lib/swarm_sdk/context_management/context.rb +0 -328
  92. data/lib/swarm_sdk/custom_tool_registry.rb +0 -226
  93. data/lib/swarm_sdk/defaults.rb +0 -251
  94. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  95. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  96. data/lib/swarm_sdk/hooks/context.rb +0 -197
  97. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  98. data/lib/swarm_sdk/hooks/error.rb +0 -29
  99. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  100. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  101. data/lib/swarm_sdk/hooks/result.rb +0 -150
  102. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -256
  103. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  104. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  105. data/lib/swarm_sdk/log_collector.rb +0 -227
  106. data/lib/swarm_sdk/log_stream.rb +0 -127
  107. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  108. data/lib/swarm_sdk/model_aliases.json +0 -8
  109. data/lib/swarm_sdk/models.json +0 -44002
  110. data/lib/swarm_sdk/models.rb +0 -161
  111. data/lib/swarm_sdk/node_context.rb +0 -245
  112. data/lib/swarm_sdk/observer/builder.rb +0 -81
  113. data/lib/swarm_sdk/observer/config.rb +0 -45
  114. data/lib/swarm_sdk/observer/manager.rb +0 -248
  115. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  116. data/lib/swarm_sdk/permissions/config.rb +0 -239
  117. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  118. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  119. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  120. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  121. data/lib/swarm_sdk/plugin.rb +0 -309
  122. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  123. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  124. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -119
  125. data/lib/swarm_sdk/restore_result.rb +0 -65
  126. data/lib/swarm_sdk/result.rb +0 -241
  127. data/lib/swarm_sdk/snapshot.rb +0 -156
  128. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  129. data/lib/swarm_sdk/state_restorer.rb +0 -476
  130. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  131. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -648
  132. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -204
  133. data/lib/swarm_sdk/swarm/builder.rb +0 -256
  134. data/lib/swarm_sdk/swarm/executor.rb +0 -446
  135. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -162
  136. data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -361
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -290
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
  141. data/lib/swarm_sdk/swarm.rb +0 -973
  142. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  143. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  144. data/lib/swarm_sdk/tools/base.rb +0 -63
  145. data/lib/swarm_sdk/tools/bash.rb +0 -280
  146. data/lib/swarm_sdk/tools/clock.rb +0 -46
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -389
  148. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  149. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  150. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  151. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  152. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  153. data/lib/swarm_sdk/tools/edit.rb +0 -145
  154. data/lib/swarm_sdk/tools/glob.rb +0 -166
  155. data/lib/swarm_sdk/tools/grep.rb +0 -235
  156. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  157. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -167
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
  160. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  161. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  162. data/lib/swarm_sdk/tools/read.rb +0 -261
  163. data/lib/swarm_sdk/tools/registry.rb +0 -205
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  166. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  167. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  168. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -273
  169. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  170. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  171. data/lib/swarm_sdk/tools/think.rb +0 -100
  172. data/lib/swarm_sdk/tools/todo_write.rb +0 -237
  173. data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
  174. data/lib/swarm_sdk/tools/write.rb +0 -112
  175. data/lib/swarm_sdk/transcript_builder.rb +0 -278
  176. data/lib/swarm_sdk/utils.rb +0 -68
  177. data/lib/swarm_sdk/validation_result.rb +0 -33
  178. data/lib/swarm_sdk/version.rb +0 -5
  179. data/lib/swarm_sdk/workflow/agent_config.rb +0 -95
  180. data/lib/swarm_sdk/workflow/builder.rb +0 -227
  181. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  182. data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
  183. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
  184. data/lib/swarm_sdk/workflow.rb +0 -589
  185. data/lib/swarm_sdk.rb +0 -721
@@ -1,161 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Models provides model validation and suggestion functionality
5
- #
6
- # Uses static JSON files:
7
- # - models.json: Curated model list from Parsera
8
- # - model_aliases.json: Shortcuts mapping to latest models
9
- #
10
- # This avoids network calls, API key requirements, and RubyLLM
11
- # registry manipulation.
12
- #
13
- # @example
14
- # model = SwarmSDK::Models.find("claude-sonnet-4-5-20250929")
15
- # model = SwarmSDK::Models.find("sonnet") # Uses alias
16
- # suggestions = SwarmSDK::Models.suggest_similar("anthropic:claude-sonnet-4-5")
17
- class Models
18
- MODELS_JSON_PATH = File.expand_path("models.json", __dir__)
19
- ALIASES_JSON_PATH = File.expand_path("model_aliases.json", __dir__)
20
-
21
- # Model information wrapper providing method access to model data
22
- #
23
- # Wraps the raw Hash from models.json to provide RubyLLM::Model::Info-like
24
- # interface for compatibility with code expecting method access.
25
- #
26
- # @example
27
- # model = SwarmSDK::Models.find("claude-sonnet-4-5-20250929")
28
- # model.context_window #=> 200000
29
- # model.id #=> "claude-sonnet-4-5-20250929"
30
- class ModelInfo
31
- attr_reader :id,
32
- :name,
33
- :provider,
34
- :family,
35
- :context_window,
36
- :max_output_tokens,
37
- :knowledge_cutoff,
38
- :modalities,
39
- :capabilities,
40
- :pricing,
41
- :metadata
42
-
43
- # Create a ModelInfo from a Hash
44
- #
45
- # @param data [Hash] Model data from models.json
46
- def initialize(data)
47
- @id = data["id"] || data[:id]
48
- @name = data["name"] || data[:name]
49
- @provider = data["provider"] || data[:provider]
50
- @family = data["family"] || data[:family]
51
- @context_window = data["context_window"] || data[:context_window]
52
- @max_output_tokens = data["max_output_tokens"] || data[:max_output_tokens]
53
- @knowledge_cutoff = data["knowledge_cutoff"] || data[:knowledge_cutoff]
54
- @modalities = data["modalities"] || data[:modalities]
55
- @capabilities = data["capabilities"] || data[:capabilities]
56
- @pricing = data["pricing"] || data[:pricing]
57
- @metadata = data["metadata"] || data[:metadata]
58
- end
59
- end
60
-
61
- class << self
62
- # Find a model by ID or alias
63
- #
64
- # @param model_id [String] Model ID or alias to find
65
- # @return [ModelInfo, nil] Model info or nil if not found
66
- def find(model_id)
67
- # Check if it's an alias first
68
- resolved_id = resolve_alias(model_id)
69
-
70
- model_hash = all.find { |m| m["id"] == resolved_id || m[:id] == resolved_id }
71
- model_hash ? ModelInfo.new(model_hash) : nil
72
- end
73
-
74
- # Resolve a model alias to full model ID
75
- #
76
- # @param model_id [String] Model ID or alias
77
- # @return [String] Resolved model ID (or original if not an alias)
78
- def resolve_alias(model_id)
79
- aliases[model_id.to_s] || model_id
80
- end
81
-
82
- # Suggest similar models for a given query
83
- #
84
- # Strips provider prefixes and normalizes for fuzzy matching.
85
- #
86
- # @param query [String] Model ID to match against
87
- # @param limit [Integer] Maximum number of suggestions
88
- # @return [Array<Hash>] Up to `limit` similar models
89
- def suggest_similar(query, limit: 3)
90
- # Strip provider prefix (e.g., "anthropic:claude-sonnet-4-5" → "claude-sonnet-4-5")
91
- query_without_prefix = query.to_s.sub(/^[^:]+:/, "")
92
- normalized_query = query_without_prefix.downcase.gsub(/[.\-_]/, "")
93
-
94
- matches = all.select do |model|
95
- model_id = (model["id"] || model[:id]).to_s
96
- model_name = (model["name"] || model[:name]).to_s
97
-
98
- normalized_id = model_id.downcase.gsub(/[.\-_]/, "")
99
- normalized_name = model_name.downcase.gsub(/[.\-_]/, "")
100
-
101
- normalized_id.include?(normalized_query) || normalized_name.include?(normalized_query)
102
- end.first(limit)
103
-
104
- matches.map do |m|
105
- {
106
- id: m["id"] || m[:id],
107
- name: m["name"] || m[:name],
108
- context_window: m["context_window"] || m[:context_window],
109
- }
110
- end
111
- end
112
-
113
- # Get all models
114
- #
115
- # @return [Array<Hash>] All models from models.json
116
- def all
117
- @models ||= load_models
118
- end
119
-
120
- # Get all aliases
121
- #
122
- # @return [Hash] Alias mappings
123
- def aliases
124
- @aliases ||= load_aliases
125
- end
126
-
127
- # Reload models and aliases from JSON files
128
- #
129
- # @return [Array<Hash>] Loaded models
130
- def reload!
131
- @models = load_models
132
- @aliases = load_aliases
133
- @models
134
- end
135
-
136
- private
137
-
138
- # Load models from JSON file
139
- #
140
- # @return [Array<Hash>] Models array
141
- def load_models
142
- JSON.parse(File.read(MODELS_JSON_PATH))
143
- rescue StandardError => e
144
- # Log error and return empty array
145
- RubyLLM.logger.error("Failed to load SwarmSDK models.json: #{e.class} - #{e.message}")
146
- []
147
- end
148
-
149
- # Load aliases from JSON file
150
- #
151
- # @return [Hash] Alias mappings
152
- def load_aliases
153
- JSON.parse(File.read(ALIASES_JSON_PATH))
154
- rescue StandardError => e
155
- # Log error and return empty hash
156
- RubyLLM.logger.debug("Failed to load SwarmSDK model_aliases.json: #{e.class} - #{e.message}")
157
- {}
158
- end
159
- end
160
- end
161
- end
@@ -1,245 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # NodeContext provides context information to node transformers
5
- #
6
- # This class is passed to input and output transformers, giving them access to:
7
- # - The original user prompt
8
- # - Results from all previous nodes
9
- # - Current node metadata
10
- # - Convenience accessors for common operations
11
- #
12
- # @example Input transformer
13
- # input do |ctx|
14
- # ctx.content # Previous node's content (convenience)
15
- # ctx.original_prompt # Original user prompt
16
- # ctx.all_results[:plan] # Access any previous node
17
- # ctx.node_name # Current node name
18
- # end
19
- #
20
- # @example Output transformer
21
- # output do |ctx|
22
- # ctx.content # Current result's content (convenience)
23
- # ctx.original_prompt # Original user prompt
24
- # ctx.all_results[:plan] # Access previous nodes
25
- # end
26
- class NodeContext
27
- attr_reader :original_prompt, :all_results, :node_name, :dependencies
28
-
29
- # For input transformers: result from previous node(s)
30
- attr_reader :previous_result
31
-
32
- # For output transformers: current node's result
33
- attr_reader :result
34
-
35
- class << self
36
- # Create a NodeContext for input transformers
37
- #
38
- # @param previous_result [Result, Hash, String] Previous node's result or hash of results
39
- # @param all_results [Hash<Symbol, Result>] Results from all completed nodes
40
- # @param original_prompt [String] The original user prompt
41
- # @param node_name [Symbol] Current node name
42
- # @param dependencies [Array<Symbol>] Node dependencies
43
- # @param transformed_content [String, nil] Already-transformed content from previous output transformer
44
- # @return [NodeContext]
45
- def for_input(previous_result:, all_results:, original_prompt:, node_name:, dependencies:, transformed_content: nil)
46
- new(
47
- previous_result: previous_result,
48
- all_results: all_results,
49
- original_prompt: original_prompt,
50
- node_name: node_name,
51
- dependencies: dependencies,
52
- result: nil,
53
- transformed_content: transformed_content,
54
- )
55
- end
56
-
57
- # Create a NodeContext for output transformers
58
- #
59
- # @param result [Result] Current node's execution result
60
- # @param all_results [Hash<Symbol, Result>] Results from all completed nodes (including current)
61
- # @param original_prompt [String] The original user prompt
62
- # @param node_name [Symbol] Current node name
63
- # @return [NodeContext]
64
- def for_output(result:, all_results:, original_prompt:, node_name:)
65
- new(
66
- result: result,
67
- all_results: all_results,
68
- original_prompt: original_prompt,
69
- node_name: node_name,
70
- dependencies: [],
71
- previous_result: nil,
72
- transformed_content: nil,
73
- )
74
- end
75
- end
76
-
77
- def initialize(previous_result:, all_results:, original_prompt:, node_name:, dependencies:, result:, transformed_content:)
78
- @previous_result = previous_result
79
- @result = result
80
- @all_results = all_results
81
- @original_prompt = original_prompt
82
- @node_name = node_name
83
- @dependencies = dependencies
84
- @transformed_content = transformed_content
85
- end
86
-
87
- # Convenience accessor: Get content from previous_result or result
88
- #
89
- # For input transformers:
90
- # - Returns transformed_content if available (from previous output transformer)
91
- # - Otherwise returns previous_result.content (original content)
92
- # - Returns nil for multiple dependencies (use all_results instead)
93
- # For output transformers: returns result.content
94
- #
95
- # @return [String, nil]
96
- def content
97
- if @result
98
- # Output transformer context: return current result's content
99
- @result.content
100
- elsif @transformed_content
101
- # Input transformer with transformed content from previous output
102
- @transformed_content
103
- elsif @previous_result.respond_to?(:content)
104
- # Input transformer context with Result object (original content)
105
- @previous_result.content
106
- elsif @previous_result.is_a?(Hash)
107
- # Input transformer with multiple dependencies (hash of results)
108
- nil # No single "content" - user must pick from all_results hash
109
- else
110
- # String or other type (initial prompt, no dependencies)
111
- @previous_result.to_s
112
- end
113
- end
114
-
115
- # Convenience accessor: Get agent from previous_result or result
116
- #
117
- # @return [String, nil]
118
- def agent
119
- if @result
120
- @result.agent
121
- elsif @previous_result.respond_to?(:agent)
122
- @previous_result.agent
123
- end
124
- end
125
-
126
- # Convenience accessor: Get logs from previous_result or result
127
- #
128
- # @return [Array, nil]
129
- def logs
130
- if @result
131
- @result.logs
132
- elsif @previous_result.respond_to?(:logs)
133
- @previous_result.logs
134
- end
135
- end
136
-
137
- # Convenience accessor: Get duration from previous_result or result
138
- #
139
- # @return [Float, nil]
140
- def duration
141
- if @result
142
- @result.duration
143
- elsif @previous_result.respond_to?(:duration)
144
- @previous_result.duration
145
- end
146
- end
147
-
148
- # Convenience accessor: Get error from previous_result or result
149
- #
150
- # @return [Exception, nil]
151
- def error
152
- if @result
153
- @result.error
154
- elsif @previous_result.respond_to?(:error)
155
- @previous_result.error
156
- end
157
- end
158
-
159
- # Convenience accessor: Check success status
160
- #
161
- # @return [Boolean, nil]
162
- def success?
163
- if @result
164
- @result.success?
165
- elsif @previous_result.respond_to?(:success?)
166
- @previous_result.success?
167
- end
168
- end
169
-
170
- # Control flow methods for transformers
171
- # These return special hashes that Workflow recognizes
172
-
173
- # Skip current node's LLM execution and return content immediately
174
- #
175
- # Only valid for input transformers.
176
- #
177
- # @param content [String] Content to return (skips LLM call)
178
- # @return [Hash] Control hash for skip_execution
179
- # @raise [ArgumentError] If content is nil
180
- #
181
- # @example
182
- # input do |ctx|
183
- # cached = check_cache(ctx.content)
184
- # return ctx.skip_execution(content: cached) if cached
185
- # ctx.content
186
- # end
187
- def skip_execution(content:)
188
- if content.nil?
189
- raise ArgumentError,
190
- "skip_execution requires content (got nil). " \
191
- "Check that ctx.content or your content source is not nil. " \
192
- "Node: #{@node_name}"
193
- end
194
- { skip_execution: true, content: content }
195
- end
196
-
197
- # Halt entire workflow and return content as final result
198
- #
199
- # Valid for both input and output transformers.
200
- #
201
- # @param content [String] Final content to return
202
- # @return [Hash] Control hash for halt_workflow
203
- # @raise [ArgumentError] If content is nil
204
- #
205
- # @example
206
- # output do |ctx|
207
- # return ctx.halt_workflow(content: ctx.content) if converged?(ctx.content)
208
- # ctx.content
209
- # end
210
- def halt_workflow(content:)
211
- if content.nil?
212
- raise ArgumentError,
213
- "halt_workflow requires content (got nil). " \
214
- "Check that ctx.content or your content source is not nil. " \
215
- "Node: #{@node_name}"
216
- end
217
- { halt_workflow: true, content: content }
218
- end
219
-
220
- # Jump to a different node with provided content as input
221
- #
222
- # Valid for both input and output transformers.
223
- #
224
- # @param node [Symbol] Node name to jump to
225
- # @param content [String] Content to pass to target node
226
- # @return [Hash] Control hash for goto_node
227
- # @raise [ArgumentError] If content is nil
228
- #
229
- # @example
230
- # input do |ctx|
231
- # return ctx.goto_node(:review, content: ctx.content) if needs_review?(ctx.content)
232
- # ctx.content
233
- # end
234
- def goto_node(node, content:)
235
- if content.nil?
236
- raise ArgumentError,
237
- "goto_node requires content (got nil). " \
238
- "Check that ctx.content or your content source is not nil. " \
239
- "This often happens when the previous node failed with an error. " \
240
- "Node: #{@node_name}, Target: #{node}"
241
- end
242
- { goto_node: node.to_sym, content: content }
243
- end
244
- end
245
- end
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Observer
5
- # DSL for configuring observer agents
6
- #
7
- # Used by Swarm::Builder#observer to provide a clean DSL for defining
8
- # event handlers and observer configuration options.
9
- #
10
- # @example Basic usage
11
- # observer :profiler do
12
- # on :swarm_start do |event|
13
- # "Analyze this prompt: #{event[:prompt]}"
14
- # end
15
- #
16
- # timeout 120
17
- # max_concurrent 2
18
- # end
19
- class Builder
20
- # Initialize builder with agent name and config
21
- #
22
- # @param agent_name [Symbol] Name of the observer agent
23
- # @param config [Observer::Config] Configuration object to populate
24
- def initialize(agent_name, config)
25
- @agent_name = agent_name
26
- @config = config
27
- end
28
-
29
- # Register an event handler
30
- #
31
- # The block receives the event hash and should return:
32
- # - A prompt string to trigger the observer agent
33
- # - nil to skip execution for this event
34
- #
35
- # @param event_type [Symbol] Type of event to handle (e.g., :swarm_start, :tool_call)
36
- # @yield [Hash] Event hash
37
- # @yieldreturn [String, nil] Prompt or nil to skip
38
- # @return [void]
39
- #
40
- # @example
41
- # on :tool_call do |event|
42
- # next unless event[:tool_name] == "Bash"
43
- # "Check this command: #{event[:arguments][:command]}"
44
- # end
45
- def on(event_type, &block)
46
- @config.add_handler(event_type, &block)
47
- end
48
-
49
- # Set maximum concurrent executions for this observer
50
- #
51
- # Limits how many instances of this observer agent can run simultaneously.
52
- # Useful for resource-intensive observers.
53
- #
54
- # @param n [Integer] Maximum concurrent executions
55
- # @return [void]
56
- def max_concurrent(n)
57
- @config.options[:max_concurrent] = n
58
- end
59
-
60
- # Set timeout for observer execution
61
- #
62
- # Observer tasks will be cancelled after this duration.
63
- #
64
- # @param seconds [Integer] Timeout in seconds (default: 60)
65
- # @return [void]
66
- def timeout(seconds)
67
- @config.options[:timeout] = seconds
68
- end
69
-
70
- # Wait for observer to complete before swarm execution ends
71
- #
72
- # By default, observers are fire-and-forget. This option causes
73
- # the main execution to wait for this observer to complete.
74
- #
75
- # @return [void]
76
- def wait_for_completion!
77
- @config.options[:fire_and_forget] = false
78
- end
79
- end
80
- end
81
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Observer
5
- # Configuration for an observer agent
6
- #
7
- # Holds the agent name, event handlers (blocks that return prompts or nil),
8
- # and execution options.
9
- #
10
- # @example
11
- # config = Observer::Config.new(:profiler)
12
- # config.add_handler(:swarm_start) { |event| "Analyze: #{event[:prompt]}" }
13
- # config.options[:timeout] = 120
14
- class Config
15
- attr_reader :agent_name, :event_handlers, :options
16
-
17
- # Initialize a new observer configuration
18
- #
19
- # @param agent_name [Symbol] Name of the agent to use as observer
20
- def initialize(agent_name)
21
- @agent_name = agent_name
22
- @event_handlers = {} # { event_type => block }
23
- @options = {
24
- max_concurrent: nil,
25
- timeout: 60,
26
- fire_and_forget: true,
27
- }
28
- end
29
-
30
- # Add an event handler for a specific event type
31
- #
32
- # The block receives the event hash and should return:
33
- # - A prompt string to trigger the observer agent
34
- # - nil to skip execution for this event
35
- #
36
- # @param event_type [Symbol] Type of event to handle (e.g., :swarm_start, :tool_call)
37
- # @yield [Hash] Event hash with type, agent, and other data
38
- # @yieldreturn [String, nil] Prompt to execute or nil to skip
39
- # @return [void]
40
- def add_handler(event_type, &block)
41
- @event_handlers[event_type] = block
42
- end
43
- end
44
- end
45
- end