swarm_memory 2.1.5 → 2.1.6

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. metadata +5 -184
  4. data/lib/claude_swarm/base_executor.rb +0 -133
  5. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  6. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  7. data/lib/claude_swarm/cli.rb +0 -697
  8. data/lib/claude_swarm/commands/ps.rb +0 -215
  9. data/lib/claude_swarm/commands/show.rb +0 -139
  10. data/lib/claude_swarm/configuration.rb +0 -373
  11. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  12. data/lib/claude_swarm/json_handler.rb +0 -91
  13. data/lib/claude_swarm/mcp_generator.rb +0 -230
  14. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  15. data/lib/claude_swarm/openai/executor.rb +0 -256
  16. data/lib/claude_swarm/openai/responses.rb +0 -319
  17. data/lib/claude_swarm/orchestrator.rb +0 -878
  18. data/lib/claude_swarm/process_tracker.rb +0 -78
  19. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  20. data/lib/claude_swarm/session_path.rb +0 -42
  21. data/lib/claude_swarm/settings_generator.rb +0 -77
  22. data/lib/claude_swarm/system_utils.rb +0 -46
  23. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  24. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  25. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  27. data/lib/claude_swarm/version.rb +0 -5
  28. data/lib/claude_swarm/worktree_manager.rb +0 -475
  29. data/lib/claude_swarm/yaml_loader.rb +0 -22
  30. data/lib/claude_swarm.rb +0 -67
  31. data/lib/swarm_cli/cli.rb +0 -201
  32. data/lib/swarm_cli/command_registry.rb +0 -61
  33. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  34. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  35. data/lib/swarm_cli/commands/migrate.rb +0 -55
  36. data/lib/swarm_cli/commands/run.rb +0 -173
  37. data/lib/swarm_cli/config_loader.rb +0 -98
  38. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  39. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  40. data/lib/swarm_cli/interactive_repl.rb +0 -924
  41. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  42. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  43. data/lib/swarm_cli/migrate_options.rb +0 -54
  44. data/lib/swarm_cli/migrator.rb +0 -132
  45. data/lib/swarm_cli/options.rb +0 -151
  46. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  47. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  48. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  49. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  50. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  51. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  52. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  53. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  54. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  55. data/lib/swarm_cli/ui/icons.rb +0 -36
  56. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  57. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  58. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  59. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  60. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  61. data/lib/swarm_cli/version.rb +0 -5
  62. data/lib/swarm_cli.rb +0 -46
  63. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  64. data/lib/swarm_sdk/agent/builder.rb +0 -552
  65. data/lib/swarm_sdk/agent/chat.rb +0 -774
  66. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  67. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  68. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  69. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  70. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  71. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  72. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  73. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  75. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  76. data/lib/swarm_sdk/agent/context.rb +0 -116
  77. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  78. data/lib/swarm_sdk/agent/definition.rb +0 -477
  79. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  80. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  81. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  82. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  83. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  84. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  85. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  86. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  87. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  88. data/lib/swarm_sdk/configuration.rb +0 -135
  89. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  90. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  91. data/lib/swarm_sdk/context_compactor.rb +0 -335
  92. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  93. data/lib/swarm_sdk/context_management/context.rb +0 -328
  94. data/lib/swarm_sdk/defaults.rb +0 -196
  95. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  96. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  97. data/lib/swarm_sdk/hooks/context.rb +0 -197
  98. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  99. data/lib/swarm_sdk/hooks/error.rb +0 -29
  100. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  101. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  102. data/lib/swarm_sdk/hooks/result.rb +0 -150
  103. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  104. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  105. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  106. data/lib/swarm_sdk/log_collector.rb +0 -227
  107. data/lib/swarm_sdk/log_stream.rb +0 -127
  108. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  109. data/lib/swarm_sdk/model_aliases.json +0 -8
  110. data/lib/swarm_sdk/models.json +0 -1
  111. data/lib/swarm_sdk/models.rb +0 -120
  112. data/lib/swarm_sdk/node_context.rb +0 -245
  113. data/lib/swarm_sdk/observer/builder.rb +0 -81
  114. data/lib/swarm_sdk/observer/config.rb +0 -45
  115. data/lib/swarm_sdk/observer/manager.rb +0 -236
  116. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  117. data/lib/swarm_sdk/permissions/config.rb +0 -239
  118. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  119. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  120. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  121. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  122. data/lib/swarm_sdk/plugin.rb +0 -309
  123. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  124. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  125. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  126. data/lib/swarm_sdk/restore_result.rb +0 -65
  127. data/lib/swarm_sdk/result.rb +0 -123
  128. data/lib/swarm_sdk/snapshot.rb +0 -156
  129. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  130. data/lib/swarm_sdk/state_restorer.rb +0 -476
  131. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  132. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  133. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  134. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  135. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  136. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  141. data/lib/swarm_sdk/swarm.rb +0 -717
  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/bash.rb +0 -282
  145. data/lib/swarm_sdk/tools/clock.rb +0 -44
  146. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  147. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  148. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  149. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  150. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  151. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  152. data/lib/swarm_sdk/tools/edit.rb +0 -145
  153. data/lib/swarm_sdk/tools/glob.rb +0 -166
  154. data/lib/swarm_sdk/tools/grep.rb +0 -235
  155. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  156. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  157. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  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 -272
  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 -98
  170. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  171. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  172. data/lib/swarm_sdk/tools/write.rb +0 -112
  173. data/lib/swarm_sdk/utils.rb +0 -68
  174. data/lib/swarm_sdk/validation_result.rb +0 -33
  175. data/lib/swarm_sdk/version.rb +0 -5
  176. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  177. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  178. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  179. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  180. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  181. data/lib/swarm_sdk/workflow.rb +0 -554
  182. data/lib/swarm_sdk.rb +0 -524
@@ -1,197 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Hooks
5
- # Rich context object passed to hook callbacks
6
- #
7
- # Provides hooks with comprehensive access to:
8
- # - Agent information (name, definition)
9
- # - Tool call details (for tool-related events)
10
- # - Delegation details (for delegation events)
11
- # - Swarm context (access to other agents, configuration)
12
- # - Metadata (arbitrary additional data)
13
- #
14
- # The context is read-write, allowing hooks to modify data
15
- # (e.g., add metadata, modify tool parameters).
16
- #
17
- # @example Access tool call information
18
- # context.tool_call.name # => "Write"
19
- # context.tool_call.parameters # => { file_path: "...", content: "..." }
20
- #
21
- # @example Modify metadata
22
- # context.metadata[:validated] = true
23
- # context.metadata[:validation_time] = Time.now
24
- #
25
- # @example Check event type
26
- # if context.tool_event?
27
- # validate_tool_call(context.tool_call)
28
- # end
29
- class Context
30
- attr_reader :event, :agent_name, :agent_definition, :swarm, :metadata
31
- attr_accessor :tool_call, :tool_result, :delegation_target, :delegation_result
32
-
33
- # @param event [Symbol] The event type triggering this hook
34
- # @param agent_name [String, Symbol] Name of the agent
35
- # @param agent_definition [SwarmSDK::AgentDefinition, nil] Agent's configuration
36
- # @param swarm [SwarmSDK::Swarm, nil] Reference to the swarm (if available)
37
- # @param tool_call [ToolCall, nil] Tool call object (for tool events)
38
- # @param tool_result [ToolResult, nil] Tool result (for post_tool_use)
39
- # @param delegation_target [String, Symbol, nil] Target agent name (for delegation events)
40
- # @param delegation_result [Object, nil] Result from delegation (for post_delegation)
41
- # @param metadata [Hash] Additional metadata
42
- def initialize(
43
- event:,
44
- agent_name:,
45
- agent_definition: nil,
46
- swarm: nil,
47
- tool_call: nil,
48
- tool_result: nil,
49
- delegation_target: nil,
50
- delegation_result: nil,
51
- metadata: {}
52
- )
53
- @event = event
54
- @agent_name = agent_name
55
- @agent_definition = agent_definition
56
- @swarm = swarm
57
- @tool_call = tool_call
58
- @tool_result = tool_result
59
- @delegation_target = delegation_target
60
- @delegation_result = delegation_result
61
- @metadata = metadata
62
- end
63
-
64
- # Check if this is a tool-related event
65
- #
66
- # @return [Boolean] true if event is pre_tool_use or post_tool_use
67
- def tool_event?
68
- [:pre_tool_use, :post_tool_use].include?(@event)
69
- end
70
-
71
- # Check if this is a delegation-related event
72
- #
73
- # @return [Boolean] true if event is pre_delegation or post_delegation
74
- def delegation_event?
75
- [:pre_delegation, :post_delegation].include?(@event)
76
- end
77
-
78
- # Get tool name (convenience method)
79
- #
80
- # @return [String, nil] Tool name or nil if not a tool event
81
- def tool_name
82
- tool_call&.name
83
- end
84
-
85
- # Create a copy of this context with modified attributes
86
- #
87
- # Useful for chaining hooks that need to pass modified context
88
- # to subsequent hooks.
89
- #
90
- # @param attributes [Hash] Attributes to override
91
- # @return [Context] New context with modified attributes
92
- def with(**attributes)
93
- Context.new(
94
- event: attributes[:event] || @event,
95
- agent_name: attributes[:agent_name] || @agent_name,
96
- agent_definition: attributes[:agent_definition] || @agent_definition,
97
- swarm: attributes[:swarm] || @swarm,
98
- tool_call: attributes[:tool_call] || @tool_call,
99
- tool_result: attributes[:tool_result] || @tool_result,
100
- delegation_target: attributes[:delegation_target] || @delegation_target,
101
- delegation_result: attributes[:delegation_result] || @delegation_result,
102
- metadata: attributes[:metadata] || @metadata.dup,
103
- )
104
- end
105
-
106
- # Convert to hash for logging and debugging
107
- #
108
- # @return [Hash] Simplified hash representation of context
109
- def to_h
110
- {
111
- event: @event,
112
- agent_name: @agent_name,
113
- tool_name: tool_name,
114
- delegation_target: @delegation_target,
115
- metadata: @metadata,
116
- }
117
- end
118
-
119
- # Convenience methods for creating Results
120
- # These allow hooks to use `halt("message")` instead of `SwarmSDK::Hooks::Result.halt("message")`
121
-
122
- # Halt the current operation and return a message
123
- #
124
- # @param message [String] Message to return
125
- # @return [Result] Halt result
126
- def halt(message)
127
- Result.halt(message)
128
- end
129
-
130
- # Replace the current result with a custom value
131
- #
132
- # @param value [Object] Replacement value
133
- # @return [Result] Replace result
134
- def replace(value)
135
- Result.replace(value)
136
- end
137
-
138
- # Reprompt the agent with a new prompt
139
- #
140
- # @param prompt [String] New prompt
141
- # @return [Result] Reprompt result
142
- def reprompt(prompt)
143
- Result.reprompt(prompt)
144
- end
145
-
146
- # Finish the current agent's execution with a final message
147
- #
148
- # @param message [String] Final message from the agent
149
- # @return [Result] Finish agent result
150
- def finish_agent(message)
151
- Result.finish_agent(message)
152
- end
153
-
154
- # Finish the entire swarm execution with a final message
155
- #
156
- # @param message [String] Final message from the swarm
157
- # @return [Result] Finish swarm result
158
- def finish_swarm(message)
159
- Result.finish_swarm(message)
160
- end
161
-
162
- # Enter an interactive debugging breakpoint
163
- #
164
- # This method:
165
- # 1. Emits a breakpoint_enter event (formatters can pause spinners)
166
- # 2. Opens binding.irb for interactive debugging
167
- # 3. Emits a breakpoint_exit event (formatters can resume spinners)
168
- #
169
- # @example Use in a hook
170
- # hook(:pre_delegation) do |ctx|
171
- # ctx.breakpoint # Pause execution and inspect context
172
- # end
173
- #
174
- # @return [void]
175
- def breakpoint
176
- # Emit breakpoint_enter event
177
- LogStream.emit(
178
- type: "breakpoint_enter",
179
- agent: @agent_name,
180
- event: @event,
181
- timestamp: Time.now.utc.iso8601,
182
- )
183
-
184
- # Enter interactive debugging
185
- binding.irb # rubocop:disable Lint/Debugger
186
-
187
- # Emit breakpoint_exit event
188
- LogStream.emit(
189
- type: "breakpoint_exit",
190
- agent: @agent_name,
191
- event: @event,
192
- timestamp: Time.now.utc.iso8601,
193
- )
194
- end
195
- end
196
- end
197
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Hooks
5
- # Represents a single hook configuration
6
- #
7
- # A hook definition includes:
8
- # - Event type (when to trigger)
9
- # - Optional matcher (regex for tool names)
10
- # - Priority (execution order)
11
- # - Proc to execute
12
- #
13
- # @example Create a hook definition
14
- # definition = SwarmSDK::Hooks::Definition.new(
15
- # event: :pre_tool_use,
16
- # matcher: "Write|Edit",
17
- # priority: 10,
18
- # proc: ->(ctx) { validate_code(ctx.tool_call) }
19
- # )
20
- class Definition
21
- attr_reader :event, :matcher, :priority, :proc
22
-
23
- # @param event [Symbol] Event type (e.g., :pre_tool_use)
24
- # @param matcher [String, Regexp, nil] Optional regex pattern for tool names
25
- # @param priority [Integer] Execution priority (higher = earlier)
26
- # @param proc [Proc, Symbol] Hook proc or named hook symbol
27
- def initialize(event:, matcher: nil, priority: 0, proc:)
28
- @event = event
29
- @matcher = compile_matcher(matcher)
30
- @priority = priority
31
- @proc = proc
32
- end
33
-
34
- # Check if this hook should execute for a given tool name
35
- #
36
- # @param tool_name [String] Name of the tool being called
37
- # @return [Boolean] true if hook should execute
38
- def matches?(tool_name)
39
- return true if @matcher.nil? # No matcher = matches everything
40
-
41
- @matcher.match?(tool_name)
42
- end
43
-
44
- # Check if this hook uses a named reference
45
- #
46
- # @return [Boolean] true if proc is a symbol (named hook)
47
- def named_hook?
48
- @proc.is_a?(Symbol)
49
- end
50
-
51
- # Resolve the actual proc, looking up named hooks if needed
52
- #
53
- # @param registry [Registry] Registry to lookup named hooks
54
- # @return [Proc] The actual proc to execute
55
- # @raise [ArgumentError] if named hook not found
56
- def resolve_proc(registry)
57
- return @proc unless named_hook?
58
-
59
- resolved = registry.get(@proc)
60
- raise ArgumentError, "Named hook :#{@proc} not found in registry" unless resolved
61
-
62
- resolved
63
- end
64
-
65
- private
66
-
67
- # Compile matcher string/regexp into regexp
68
- #
69
- # @param matcher [String, Regexp, nil] Matcher pattern
70
- # @return [Regexp, nil] Compiled regex or nil
71
- def compile_matcher(matcher)
72
- return if matcher.nil?
73
- return matcher if matcher.is_a?(Regexp)
74
-
75
- # Convert string to regex, treating it as a pattern with | for OR
76
- Regexp.new(matcher)
77
- end
78
- end
79
- end
80
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Hooks
5
- # Error raised by callbacks to block execution
6
- #
7
- # This error provides context about which hook failed and includes
8
- # the execution context for debugging and error handling.
9
- #
10
- # @example Raise a hook error to block execution
11
- # raise SwarmSDK::Hooks::Error.new(
12
- # "Validation failed: invalid syntax",
13
- # hook_name: :validate_code,
14
- # context: context
15
- # )
16
- class Error < StandardError
17
- attr_reader :hook_name, :context
18
-
19
- # @param message [String] Error message
20
- # @param hook_name [Symbol, String, nil] Name of the hook that failed
21
- # @param context [Context, nil] Execution context when error occurred
22
- def initialize(message, hook_name: nil, context: nil)
23
- super(message)
24
- @hook_name = hook_name
25
- @context = context
26
- end
27
- end
28
- end
29
- end
@@ -1,146 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Hooks
5
- # Executes hooks with proper chaining, error handling, and logging
6
- #
7
- # The executor:
8
- # - Chains multiple hooks for the same event
9
- # - Handles errors and blocking (via Error or Result.halt)
10
- # - Respects matcher patterns (only runs matching hooks)
11
- # - Logs execution for debugging
12
- # - Returns Result indicating action to take
13
- #
14
- # @example Execute hooks
15
- # executor = SwarmSDK::Hooks::Executor.new(registry, logger)
16
- # context = SwarmSDK::Hooks::Context.new(...)
17
- # result = executor.execute(event: :pre_tool_use, context: context, hooks: agent_hooks)
18
- # if result.halt?
19
- # # Handle halt
20
- # elsif result.replace?
21
- # # Use replacement value
22
- # end
23
- class Executor
24
- # @param registry [Registry] Hook registry for resolving named hooks
25
- # @param logger [Logger, nil] Logger for debugging (optional)
26
- def initialize(registry, logger: nil)
27
- @registry = registry
28
- @logger = logger || Logger.new(nil) # Null logger if not provided
29
- end
30
-
31
- # Execute all hooks for an event
32
- #
33
- # Execution order:
34
- # 1. Swarm-level defaults (from registry)
35
- # 2. Agent-specific hooks
36
- # 3. Within each group, by priority (highest first)
37
- #
38
- # Hooks must return:
39
- # - Result - to control execution flow (halt, replace, reprompt, continue)
40
- # - nil - treated as continue with unmodified context
41
- #
42
- # @param event [Symbol] Event type
43
- # @param context [Context] Context to pass to hooks
44
- # @param callbacks [Array<Definition>] Agent-specific hooks
45
- # @return [Result] Result indicating action and value
46
- # @raise [Error] If a hook raises an error
47
- def execute(event:, context:, callbacks: [])
48
- # Combine swarm defaults and agent hooks
49
- all_hooks = @registry.get_defaults(event) + callbacks
50
-
51
- # Filter by matcher (for tool events)
52
- if context.tool_event? && context.tool_name
53
- all_hooks = all_hooks.select { |hook| hook.matches?(context.tool_name) }
54
- end
55
-
56
- # Execute hooks in order
57
- all_hooks.each do |hook_def|
58
- result = execute_single(hook_def, context)
59
-
60
- # Only Result controls flow - nil means continue
61
- next unless result.is_a?(Result)
62
-
63
- # Early return for control flow actions
64
- return result if result.halt? || result.replace? || result.reprompt? || result.finish_agent? || result.finish_swarm?
65
-
66
- # Update context if continue with modified context
67
- context = result.value if result.continue? && result.value.is_a?(Context)
68
- end
69
-
70
- # All hooks executed successfully - continue with final context
71
- Result.continue(context)
72
- rescue Error => e
73
- # Re-raise with context for better error messages
74
- @logger.error("Hook blocked execution: #{e.message}")
75
- raise
76
- rescue StandardError => e
77
- # Wrap unexpected errors
78
- @logger.error("Hook failed unexpectedly: #{e.class} - #{e.message}")
79
- @logger.error(e.backtrace.join("\n"))
80
- raise Error.new(
81
- "Hook failed: #{e.message}",
82
- context: context,
83
- )
84
- end
85
-
86
- # Execute a single hook
87
- #
88
- # @param hook_def [Definition] Hook to execute
89
- # @param context [Context] Current context
90
- # @return [Result, nil] Result from hook (Result or nil)
91
- # @raise [Error] If hook execution fails
92
- def execute_single(hook_def, context)
93
- proc = hook_def.resolve_proc(@registry)
94
-
95
- @logger.debug("Executing hook for #{context.event} (agent: #{context.agent_name})")
96
-
97
- # Execute hook with context as parameter
98
- # Users can access convenience methods via context parameter:
99
- # hook(:event) { |ctx| ctx.halt("msg") }
100
- # This preserves lexical scope and access to surrounding instance variables
101
- proc.call(context)
102
- rescue Error
103
- # Pass through blocking errors
104
- raise
105
- rescue StandardError => e
106
- # Wrap other errors with context and detailed debugging
107
- hook_name = hook_def.named_hook? ? hook_def.proc : "anonymous"
108
-
109
- # Log detailed error info for debugging
110
- @logger.error("=" * 80)
111
- @logger.error("HOOK EXECUTION ERROR")
112
- @logger.error(" Hook: #{hook_name}")
113
- @logger.error(" Event: #{context.event}")
114
- @logger.error(" Agent: #{context.agent_name}")
115
- @logger.error(" Proc class: #{proc.class}")
116
- @logger.error(" Proc arity: #{proc.arity} (expected: 1 for |context|)")
117
- @logger.error(" Error: #{e.class.name}: #{e.message}")
118
- @logger.error(" Backtrace:")
119
- e.backtrace.first(15).each { |line| @logger.error(" #{line}") }
120
- @logger.error("=" * 80)
121
-
122
- raise Error.new(
123
- "Hook #{hook_name} failed: #{e.message}",
124
- hook_name: hook_name,
125
- context: context,
126
- )
127
- end
128
-
129
- # Execute hooks and return result safely (without raising)
130
- #
131
- # This is a convenience method that catches Error and converts it
132
- # to a halt result, making it easier to use in control flow.
133
- #
134
- # @param event [Symbol] Event type
135
- # @param context [Context] Context to pass to hooks
136
- # @param callbacks [Array<Definition>] Agent-specific hooks
137
- # @return [Result] Result from hooks
138
- def execute_safe(event:, context:, callbacks: [])
139
- execute(event: event, context: context, callbacks: callbacks)
140
- rescue Error => e
141
- @logger.warn("Execution blocked by hook: #{e.message}")
142
- Result.halt(e.message)
143
- end
144
- end
145
- end
146
- end
@@ -1,147 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Hooks
5
- # Central registry for managing named hooks and swarm-level defaults
6
- #
7
- # The Registry stores:
8
- # - Named hooks that can be referenced by symbol in YAML or code
9
- # - Swarm-level default hooks that apply to all agents
10
- #
11
- # @example Register a named hook
12
- # registry = SwarmSDK::Hooks::Registry.new
13
- # registry.register(:validate_code) do |context|
14
- # raise SwarmSDK::Hooks::Error, "Invalid code" unless valid?(context.tool_call)
15
- # end
16
- #
17
- # @example Add swarm-level default
18
- # registry.add_default(:pre_tool_use, matcher: "Write|Edit") do |context|
19
- # puts "Tool #{context.tool_call.name} called by #{context.agent_name}"
20
- # end
21
- class Registry
22
- # Available hook event types
23
- VALID_EVENTS = [
24
- # Swarm lifecycle events
25
- :swarm_start, # When Swarm.execute is called (before first user message)
26
- :swarm_stop, # When Swarm.execute completes (after execution)
27
- :first_message, # When first user message is sent to swarm (Swarm.execute)
28
-
29
- # Agent/LLM events
30
- :user_prompt, # Before sending user message to LLM
31
- :agent_step, # After agent makes intermediate response with tool calls
32
- :agent_stop, # After agent completes with final response (no more tool calls)
33
-
34
- # Tool events
35
- :pre_tool_use, # Before tool execution (can block/modify)
36
- :post_tool_use, # After tool execution
37
-
38
- # Delegation events
39
- :pre_delegation, # Before delegating to another agent
40
- :post_delegation, # After delegation completes
41
-
42
- # Context events
43
- :context_warning, # When context usage crosses threshold
44
-
45
- # Debug events
46
- :breakpoint_enter, # When entering interactive debugging (binding.irb)
47
- :breakpoint_exit, # When exiting interactive debugging
48
- ].freeze
49
-
50
- def initialize
51
- @named_hooks = {} # { hook_name: proc }
52
- @defaults = Hash.new { |h, k| h[k] = [] } # { event_type: [Definition, ...] }
53
- end
54
-
55
- # Register a named hook that can be referenced elsewhere
56
- #
57
- # @param name [Symbol] Unique name for this hook
58
- # @param block [Proc] Hook implementation
59
- # @raise [ArgumentError] if name already registered or invalid
60
- #
61
- # @example
62
- # registry.register(:log_tool_use) { |ctx| puts "Tool: #{ctx.tool_call.name}" }
63
- def register(name, &block)
64
- raise ArgumentError, "Hook name must be a symbol" unless name.is_a?(Symbol)
65
- raise ArgumentError, "Hook #{name} already registered" if @named_hooks.key?(name)
66
- raise ArgumentError, "Block required" unless block
67
-
68
- @named_hooks[name] = block
69
- end
70
-
71
- # Get a named hook by symbol
72
- #
73
- # @param name [Symbol] Hook name
74
- # @return [Proc, nil] The hook proc or nil if not found
75
- def get(name)
76
- @named_hooks[name]
77
- end
78
-
79
- # Add a swarm-level default hook
80
- #
81
- # These hooks apply to all agents unless overridden at agent level.
82
- #
83
- # @param event [Symbol] Event type (must be in VALID_EVENTS)
84
- # @param matcher [String, Regexp, nil] Optional regex pattern to match tool names
85
- # @param priority [Integer] Execution priority (higher runs first)
86
- # @param block [Proc] Hook implementation
87
- # @raise [ArgumentError] if event invalid or block missing
88
- #
89
- # @example Add default logging
90
- # registry.add_default(:pre_tool_use) { |ctx| log(ctx) }
91
- #
92
- # @example Add validation for specific tools
93
- # registry.add_default(:pre_tool_use, matcher: "Write|Edit") do |ctx|
94
- # validate_tool_call(ctx.tool_call)
95
- # end
96
- def add_default(event, matcher: nil, priority: 0, &block)
97
- validate_event!(event)
98
- raise ArgumentError, "Block required" unless block
99
-
100
- definition = Definition.new(
101
- event: event,
102
- matcher: matcher,
103
- priority: priority,
104
- proc: block,
105
- )
106
-
107
- @defaults[event] << definition
108
- @defaults[event].sort_by! { |d| -d.priority } # Higher priority first
109
- end
110
-
111
- # Get all default hooks for an event type
112
- #
113
- # @param event [Symbol] Event type
114
- # @return [Array<Definition>] List of hook definitions
115
- def get_defaults(event)
116
- @defaults[event]
117
- end
118
-
119
- # Get all registered named hook names
120
- #
121
- # @return [Array<Symbol>] List of hook names
122
- def named_hooks
123
- @named_hooks.keys
124
- end
125
-
126
- # Check if a hook name is registered
127
- #
128
- # @param name [Symbol] Hook name
129
- # @return [Boolean] true if registered
130
- def registered?(name)
131
- @named_hooks.key?(name)
132
- end
133
-
134
- private
135
-
136
- # Validate event type
137
- #
138
- # @param event [Symbol] Event to validate
139
- # @raise [ArgumentError] if event invalid
140
- def validate_event!(event)
141
- return if VALID_EVENTS.include?(event)
142
-
143
- raise ArgumentError, "Invalid event type: #{event}. Valid types: #{VALID_EVENTS.join(", ")}"
144
- end
145
- end
146
- end
147
- end