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,199 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Reconstructs RubyLLM::Message objects from SwarmSDK event streams
5
- #
6
- # This class enables conversation replay and analysis from event logs.
7
- # It uses timestamps to maintain chronological ordering of messages.
8
- #
9
- # ## Limitations
10
- #
11
- # This reconstructs ONLY conversation messages. It does NOT restore:
12
- # - Context state (warning thresholds, compression, todowrite index)
13
- # - Scratchpad contents
14
- # - Read tracking information
15
- # - Full swarm state
16
- #
17
- # For full state restoration, use StateSnapshot/StateRestorer or SnapshotFromEvents.
18
- #
19
- # ## Usage
20
- #
21
- # # Collect events during execution
22
- # events = []
23
- # swarm.execute("Build feature") do |event|
24
- # events << event
25
- # end
26
- #
27
- # # Reconstruct conversation for an agent
28
- # messages = SwarmSDK::EventsToMessages.reconstruct(events, agent: :backend)
29
- #
30
- # # View conversation
31
- # messages.each do |msg|
32
- # puts "[#{msg.role}] #{msg.content}"
33
- # end
34
- #
35
- # ## Event Requirements
36
- #
37
- # Events must have:
38
- # - `:timestamp` field (ISO 8601 format) for ordering
39
- # - `:agent` field to filter by agent
40
- # - `:type` field to identify event type
41
- #
42
- # Supported event types:
43
- # - `user_prompt`: Reconstructs user message (prompt in metadata or top-level)
44
- # - `agent_step`: Reconstructs assistant message with tool calls
45
- # - `agent_stop`: Reconstructs final assistant message
46
- # - `tool_result`: Reconstructs tool result message
47
- # - `delegation_result`: Reconstructs tool result message from delegation
48
- class EventsToMessages
49
- class << self
50
- # Reconstruct messages for an agent from event stream
51
- #
52
- # @param events [Array<Hash>] Event stream with timestamps
53
- # @param agent [Symbol, String] Agent name to reconstruct messages for
54
- # @return [Array<RubyLLM::Message>] Reconstructed messages in chronological order
55
- #
56
- # @example
57
- # messages = EventsToMessages.reconstruct(events, agent: :backend)
58
- # messages.each { |msg| puts msg.content }
59
- def reconstruct(events, agent:)
60
- new(events, agent).reconstruct
61
- end
62
- end
63
-
64
- # Initialize reconstructor
65
- #
66
- # @param events [Array<Hash>] Event stream
67
- # @param agent [Symbol, String] Agent name
68
- def initialize(events, agent)
69
- @events = events
70
- @agent = agent.to_sym
71
- end
72
-
73
- # Reconstruct messages from events
74
- #
75
- # Filters events by agent, sorts by timestamp, and converts to RubyLLM::Message objects.
76
- #
77
- # @return [Array<RubyLLM::Message>] Reconstructed messages
78
- def reconstruct
79
- messages = []
80
-
81
- # Filter events for this agent and sort by timestamp
82
- agent_events = @events
83
- .select { |e| normalize_agent(e[:agent]) == @agent }
84
- .sort_by { |e| parse_timestamp(e[:timestamp]) }
85
-
86
- agent_events.each do |event|
87
- message = case event[:type]&.to_s
88
- when "user_prompt"
89
- reconstruct_user_message(event)
90
- when "agent_step", "agent_stop"
91
- reconstruct_assistant_message(event)
92
- when "tool_result"
93
- reconstruct_tool_result_message(event)
94
- when "delegation_result"
95
- reconstruct_delegation_result_message(event)
96
- end
97
-
98
- messages << message if message
99
- end
100
-
101
- messages
102
- end
103
-
104
- private
105
-
106
- # Reconstruct user message from user_prompt event
107
- #
108
- # Extracts prompt from metadata or top-level field.
109
- #
110
- # @param event [Hash] user_prompt event
111
- # @return [RubyLLM::Message, nil] User message or nil if prompt not found
112
- def reconstruct_user_message(event)
113
- # Try to extract prompt from metadata (current location) or top-level (potential future location)
114
- prompt = event.dig(:metadata, :prompt) || event[:prompt]
115
- return unless prompt && !prompt.to_s.empty?
116
-
117
- RubyLLM::Message.new(
118
- role: :user,
119
- content: prompt,
120
- )
121
- end
122
-
123
- # Reconstruct assistant message from agent_step or agent_stop event
124
- #
125
- # Converts tool_calls array to hash format expected by RubyLLM.
126
- #
127
- # @param event [Hash] agent_step or agent_stop event
128
- # @return [RubyLLM::Message] Assistant message
129
- def reconstruct_assistant_message(event)
130
- # Convert tool_calls array to hash (RubyLLM format)
131
- # Events emit tool_calls as Array, but RubyLLM expects Hash<String, ToolCall>
132
- tool_calls_hash = if event[:tool_calls] && !event[:tool_calls].empty?
133
- event[:tool_calls].each_with_object({}) do |tc, hash|
134
- hash[tc[:id].to_s] = RubyLLM::ToolCall.new(
135
- id: tc[:id],
136
- name: tc[:name],
137
- arguments: tc[:arguments] || {},
138
- )
139
- end
140
- end
141
-
142
- RubyLLM::Message.new(
143
- role: :assistant,
144
- content: event[:content] || "",
145
- tool_calls: tool_calls_hash,
146
- input_tokens: event.dig(:usage, :input_tokens),
147
- output_tokens: event.dig(:usage, :output_tokens),
148
- model_id: event[:model],
149
- )
150
- end
151
-
152
- # Reconstruct tool result message from tool_result event
153
- #
154
- # @param event [Hash] tool_result event
155
- # @return [RubyLLM::Message] Tool result message
156
- def reconstruct_tool_result_message(event)
157
- RubyLLM::Message.new(
158
- role: :tool,
159
- content: event[:result].to_s,
160
- tool_call_id: event[:tool_call_id],
161
- )
162
- end
163
-
164
- # Reconstruct tool result message from delegation_result event
165
- #
166
- # delegation_result events are emitted when a delegation completes,
167
- # and they should be converted to tool result messages in the conversation.
168
- #
169
- # @param event [Hash] delegation_result event
170
- # @return [RubyLLM::Message] Tool result message
171
- def reconstruct_delegation_result_message(event)
172
- RubyLLM::Message.new(
173
- role: :tool,
174
- content: event[:result].to_s,
175
- tool_call_id: event[:tool_call_id],
176
- )
177
- end
178
-
179
- # Parse timestamp string to Time object
180
- #
181
- # @param timestamp [String, nil] ISO 8601 timestamp
182
- # @return [Time] Parsed time or epoch if nil/invalid
183
- def parse_timestamp(timestamp)
184
- return Time.at(0) unless timestamp
185
-
186
- Time.parse(timestamp)
187
- rescue ArgumentError
188
- Time.at(0)
189
- end
190
-
191
- # Normalize agent name to symbol
192
- #
193
- # @param agent [Symbol, String, nil] Agent name
194
- # @return [Symbol] Normalized agent name
195
- def normalize_agent(agent)
196
- agent.to_s.to_sym
197
- end
198
- end
199
- end
@@ -1,359 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Hooks
5
- # Translates YAML hooks configuration to Ruby hooks
6
- #
7
- # Adapter bridges the gap between declarative YAML hooks (shell commands)
8
- # and SwarmSDK's internal hook system. It creates hooks that execute
9
- # shell commands and translate exit codes to Result objects.
10
- #
11
- # ## YAML Hooks are YAML-Only
12
- #
13
- # Hooks are a **YAML-only feature** designed for users who want Claude Code-style
14
- # shell command hooks. Users of the Ruby API should use hooks directly.
15
- #
16
- # ## Swarm-Level vs Agent-Level
17
- #
18
- # - **Swarm-level**: Only `swarm_start` and `swarm_stop` (lifecycle hooks)
19
- # - **Agent-level**: All other events (per-agent or all_agents)
20
- # - **all_agents**: Hooks applied as swarm defaults to all agents
21
- #
22
- # ## Event Naming
23
- #
24
- # Uses snake_case to match internal hook events directly (no translation):
25
- # - `pre_tool_use` → :pre_tool_use
26
- # - `swarm_start` → :swarm_start
27
- # - etc.
28
- #
29
- # @example YAML configuration
30
- # swarm:
31
- # hooks:
32
- # swarm_start:
33
- # - hooks:
34
- # - type: command
35
- # command: "echo 'Starting swarm'"
36
- #
37
- # all_agents:
38
- # hooks:
39
- # pre_tool_use:
40
- # - matcher: "Write|Edit"
41
- # hooks:
42
- # - type: command
43
- # command: "rubocop --stdin"
44
- #
45
- # agents:
46
- # backend:
47
- # hooks:
48
- # pre_tool_use:
49
- # - matcher: "Bash"
50
- # hooks:
51
- # - type: command
52
- # command: "python validate_bash.py"
53
- class Adapter
54
- # Swarm-level events (only these allowed at swarm.hooks level)
55
- SWARM_LEVEL_EVENTS = [:swarm_start, :swarm_stop].freeze
56
-
57
- # Agent-level events (allowed in all_agents.hooks and agent.hooks)
58
- AGENT_LEVEL_EVENTS = [
59
- :pre_tool_use,
60
- :post_tool_use,
61
- :user_prompt,
62
- :agent_step,
63
- :agent_stop,
64
- :first_message,
65
- :pre_delegation,
66
- :post_delegation,
67
- :context_warning,
68
- ].freeze
69
-
70
- class << self
71
- # Apply hooks from YAML configuration to swarm
72
- #
73
- # This is called automatically by Swarm.load after creating the swarm instance.
74
- # It translates YAML hooks into hooks that execute shell commands.
75
- #
76
- # @param swarm [Swarm] Swarm instance to configure
77
- # @param config [Configuration] Parsed YAML configuration
78
- # @return [void]
79
- def apply_hooks(swarm, config)
80
- # 1. Apply swarm-level hooks (from swarm.hooks)
81
- apply_swarm_hooks(swarm, config.swarm_hooks) if config.swarm_hooks&.any?
82
-
83
- # 2. Apply all_agents hooks (as swarm defaults)
84
- apply_all_agents_hooks(swarm, config.all_agents_hooks) if config.all_agents_hooks&.any?
85
-
86
- # 3. Store agent hooks for later application (after agents are initialized)
87
- store_agent_hooks(config)
88
- end
89
-
90
- # Apply agent-specific hooks to an already-initialized agent
91
- #
92
- # This is called during agent initialization for each agent that has hooks configured.
93
- #
94
- # @param agent [AgentChat] Agent instance
95
- # @param agent_name [Symbol] Agent name
96
- # @param hooks_config [Hash] Hooks configuration from YAML
97
- # @param swarm_name [String] Swarm name for environment variables
98
- # @return [void]
99
- def apply_agent_hooks(agent, agent_name, hooks_config, swarm_name)
100
- return unless hooks_config&.any?
101
-
102
- hooks_config.each do |event_name, hook_defs|
103
- event_symbol = event_name.to_sym
104
- validate_agent_event!(event_symbol)
105
-
106
- # Each hook def can have optional matcher
107
- Array(hook_defs).each do |hook_def|
108
- matcher = hook_def[:matcher] || hook_def["matcher"]
109
- hook = create_hook_callback(hook_def, event_symbol, agent_name, swarm_name)
110
- agent.add_hook(event_symbol, matcher: matcher, &hook)
111
- end
112
- end
113
- end
114
-
115
- private
116
-
117
- # Apply swarm-level hooks (swarm_start, swarm_stop)
118
- #
119
- # @param swarm [Swarm] Swarm instance
120
- # @param hooks_config [Hash] Hooks configuration
121
- def apply_swarm_hooks(swarm, hooks_config)
122
- hooks_config.each do |event_name, hook_defs|
123
- event_symbol = event_name.to_sym
124
- validate_swarm_event!(event_symbol)
125
-
126
- # Each hook def is a direct hash with type, command, timeout
127
- Array(hook_defs).each do |hook_def|
128
- hook = create_swarm_hook_callback(hook_def, event_symbol, swarm.name)
129
- swarm.add_default_callback(event_symbol, &hook)
130
- end
131
- end
132
- end
133
-
134
- # Apply all_agents hooks as swarm defaults
135
- #
136
- # @param swarm [Swarm] Swarm instance
137
- # @param hooks_config [Hash] Hooks configuration
138
- def apply_all_agents_hooks(swarm, hooks_config)
139
- hooks_config.each do |event_name, hook_defs|
140
- event_symbol = event_name.to_sym
141
- validate_agent_event!(event_symbol)
142
-
143
- # Each hook def can have optional matcher
144
- Array(hook_defs).each do |hook_def|
145
- matcher = hook_def[:matcher] || hook_def["matcher"]
146
- hook = create_all_agents_hook_callback(hook_def, event_symbol, swarm.name)
147
- swarm.add_default_callback(event_symbol, matcher: matcher, &hook)
148
- end
149
- end
150
- end
151
-
152
- # Store agent hooks in Configuration for later application
153
- #
154
- # @param config [Configuration] Configuration instance
155
- def store_agent_hooks(config)
156
- # Agent hooks are already stored in AgentDefinition
157
- # They'll be applied during agent initialization
158
- end
159
-
160
- # Create a hook for agent-level hooks
161
- #
162
- # @param hook_def [Hash] Hook definition from YAML
163
- # @param event_symbol [Symbol] Event type
164
- # @param agent_name [Symbol, String] Agent name
165
- # @param swarm_name [String] Swarm name
166
- # @return [Proc] Hook callback
167
- def create_hook_callback(hook_def, event_symbol, agent_name, swarm_name)
168
- # Support both string and symbol keys (YAML may be symbolized)
169
- command = hook_def[:command] || hook_def["command"]
170
- timeout = hook_def[:timeout] || hook_def["timeout"] || ShellExecutor::DEFAULT_TIMEOUT
171
-
172
- lambda do |context|
173
- input_json = build_input_json(context, event_symbol, agent_name)
174
- ShellExecutor.execute(
175
- command: command,
176
- input_json: input_json,
177
- timeout: timeout,
178
- agent_name: agent_name,
179
- swarm_name: swarm_name,
180
- event: event_symbol,
181
- )
182
- end
183
- end
184
-
185
- # Create a hook for all_agents hooks
186
- #
187
- # @param hook_def [Hash] Hook definition from YAML
188
- # @param event_symbol [Symbol] Event type
189
- # @param swarm_name [String] Swarm name
190
- # @return [Proc] Hook callback
191
- def create_all_agents_hook_callback(hook_def, event_symbol, swarm_name)
192
- # Support both string and symbol keys (YAML may be symbolized)
193
- command = hook_def[:command] || hook_def["command"]
194
- timeout = hook_def[:timeout] || hook_def["timeout"] || ShellExecutor::DEFAULT_TIMEOUT
195
-
196
- lambda do |context|
197
- # Agent name comes from context
198
- agent_name = context.agent_name
199
- input_json = build_input_json(context, event_symbol, agent_name)
200
- ShellExecutor.execute(
201
- command: command,
202
- input_json: input_json,
203
- timeout: timeout,
204
- agent_name: agent_name,
205
- swarm_name: swarm_name,
206
- event: event_symbol,
207
- )
208
- end
209
- end
210
-
211
- # Create a hook for swarm-level hooks
212
- #
213
- # @param hook_def [Hash] Hook definition from YAML
214
- # @param event_symbol [Symbol] Event type
215
- # @param swarm_name [String] Swarm name
216
- # @return [Proc] Hook callback
217
- def create_swarm_hook_callback(hook_def, event_symbol, swarm_name)
218
- # Support both string and symbol keys (YAML may be symbolized)
219
- command = hook_def[:command] || hook_def["command"]
220
- timeout = hook_def[:timeout] || hook_def["timeout"] || ShellExecutor::DEFAULT_TIMEOUT
221
-
222
- lambda do |context|
223
- input_json = build_swarm_input_json(context, event_symbol, swarm_name)
224
- ShellExecutor.execute(
225
- command: command,
226
- input_json: input_json,
227
- timeout: timeout,
228
- agent_name: nil,
229
- swarm_name: swarm_name,
230
- event: event_symbol,
231
- )
232
- end
233
- end
234
-
235
- # Build JSON input for agent-level hook scripts
236
- #
237
- # @param context [Context] Hook context
238
- # @param event_symbol [Symbol] Event type
239
- # @param agent_name [Symbol, String] Agent name
240
- # @return [Hash] JSON input for hook script
241
- def build_input_json(context, event_symbol, agent_name)
242
- base = {
243
- event: event_symbol.to_s,
244
- agent: agent_name.to_s,
245
- }
246
-
247
- # Add event-specific data
248
- case event_symbol
249
- when :pre_tool_use
250
- base.merge(
251
- tool: context.tool_call.name,
252
- parameters: context.tool_call.parameters,
253
- )
254
- when :post_tool_use
255
- # In post_tool_use, we only have tool_result, not tool_call
256
- # Need to extract tool info from metadata or tool_result
257
- base.merge(
258
- result: context.tool_result.content,
259
- success: context.tool_result.success?,
260
- tool_call_id: context.tool_result.tool_call_id,
261
- )
262
- when :pre_delegation
263
- base.merge(
264
- delegation_target: context.delegation_target,
265
- task: context.metadata[:task],
266
- )
267
- when :post_delegation
268
- base.merge(
269
- delegation_target: context.delegation_target,
270
- task: context.metadata[:task],
271
- result: context.delegation_result,
272
- )
273
- when :user_prompt
274
- base.merge(
275
- prompt: context.metadata[:prompt],
276
- message_count: context.metadata[:message_count],
277
- )
278
- when :agent_step
279
- base.merge(
280
- content: context.metadata[:content],
281
- tool_calls: context.metadata[:tool_calls],
282
- finish_reason: context.metadata[:finish_reason],
283
- usage: context.metadata[:usage],
284
- )
285
- when :agent_stop
286
- base.merge(
287
- content: context.metadata[:content],
288
- finish_reason: context.metadata[:finish_reason],
289
- usage: context.metadata[:usage],
290
- )
291
- when :first_message
292
- base.merge(prompt: context.metadata[:prompt])
293
- when :context_warning
294
- base.merge(
295
- threshold: context.metadata[:threshold],
296
- percentage: context.metadata[:percentage],
297
- tokens_used: context.metadata[:tokens_used],
298
- tokens_remaining: context.metadata[:tokens_remaining],
299
- )
300
- else
301
- base
302
- end
303
- end
304
-
305
- # Build JSON input for swarm-level hook scripts
306
- #
307
- # @param context [Context] Hook context
308
- # @param event_symbol [Symbol] Event type
309
- # @param swarm_name [String] Swarm name
310
- # @return [Hash] JSON input for hook script
311
- def build_swarm_input_json(context, event_symbol, swarm_name)
312
- base = {
313
- event: event_symbol.to_s,
314
- swarm: swarm_name,
315
- }
316
-
317
- case event_symbol
318
- when :swarm_start, :first_message
319
- base.merge(prompt: context.metadata[:prompt])
320
- when :swarm_stop
321
- base.merge(
322
- success: context.metadata[:success],
323
- duration: context.metadata[:duration],
324
- total_cost: context.metadata[:total_cost],
325
- total_tokens: context.metadata[:total_tokens],
326
- )
327
- else
328
- base
329
- end
330
- end
331
-
332
- # Validate swarm-level event
333
- #
334
- # @param event [Symbol] Event to validate
335
- # @raise [ConfigurationError] if event invalid for swarm level
336
- def validate_swarm_event!(event)
337
- return if SWARM_LEVEL_EVENTS.include?(event)
338
-
339
- raise ConfigurationError,
340
- "Invalid swarm-level hook event: #{event}. " \
341
- "Only #{SWARM_LEVEL_EVENTS.join(", ")} are allowed at swarm.hooks level. " \
342
- "Use all_agents.hooks or agent.hooks for other events."
343
- end
344
-
345
- # Validate agent-level event
346
- #
347
- # @param event [Symbol] Event to validate
348
- # @raise [ConfigurationError] if event invalid for agent level
349
- def validate_agent_event!(event)
350
- return if AGENT_LEVEL_EVENTS.include?(event)
351
-
352
- raise ConfigurationError,
353
- "Invalid agent-level hook event: #{event}. " \
354
- "Valid events: #{AGENT_LEVEL_EVENTS.join(", ")}"
355
- end
356
- end
357
- end
358
- end
359
- end