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.
- checksums.yaml +4 -4
- data/lib/swarm_memory/version.rb +1 -1
- metadata +5 -184
- data/lib/claude_swarm/base_executor.rb +0 -133
- data/lib/claude_swarm/claude_code_executor.rb +0 -349
- data/lib/claude_swarm/claude_mcp_server.rb +0 -78
- data/lib/claude_swarm/cli.rb +0 -697
- data/lib/claude_swarm/commands/ps.rb +0 -215
- data/lib/claude_swarm/commands/show.rb +0 -139
- data/lib/claude_swarm/configuration.rb +0 -373
- data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
- data/lib/claude_swarm/json_handler.rb +0 -91
- data/lib/claude_swarm/mcp_generator.rb +0 -230
- data/lib/claude_swarm/openai/chat_completion.rb +0 -256
- data/lib/claude_swarm/openai/executor.rb +0 -256
- data/lib/claude_swarm/openai/responses.rb +0 -319
- data/lib/claude_swarm/orchestrator.rb +0 -878
- data/lib/claude_swarm/process_tracker.rb +0 -78
- data/lib/claude_swarm/session_cost_calculator.rb +0 -209
- data/lib/claude_swarm/session_path.rb +0 -42
- data/lib/claude_swarm/settings_generator.rb +0 -77
- data/lib/claude_swarm/system_utils.rb +0 -46
- data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
- data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
- data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
- data/lib/claude_swarm/tools/task_tool.rb +0 -63
- data/lib/claude_swarm/version.rb +0 -5
- data/lib/claude_swarm/worktree_manager.rb +0 -475
- data/lib/claude_swarm/yaml_loader.rb +0 -22
- data/lib/claude_swarm.rb +0 -67
- data/lib/swarm_cli/cli.rb +0 -201
- data/lib/swarm_cli/command_registry.rb +0 -61
- data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
- data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
- data/lib/swarm_cli/commands/migrate.rb +0 -55
- data/lib/swarm_cli/commands/run.rb +0 -173
- data/lib/swarm_cli/config_loader.rb +0 -98
- data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
- data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
- data/lib/swarm_cli/interactive_repl.rb +0 -924
- data/lib/swarm_cli/mcp_serve_options.rb +0 -44
- data/lib/swarm_cli/mcp_tools_options.rb +0 -59
- data/lib/swarm_cli/migrate_options.rb +0 -54
- data/lib/swarm_cli/migrator.rb +0 -132
- data/lib/swarm_cli/options.rb +0 -151
- data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
- data/lib/swarm_cli/ui/components/content_block.rb +0 -120
- data/lib/swarm_cli/ui/components/divider.rb +0 -57
- data/lib/swarm_cli/ui/components/panel.rb +0 -62
- data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
- data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
- data/lib/swarm_cli/ui/formatters/number.rb +0 -58
- data/lib/swarm_cli/ui/formatters/text.rb +0 -77
- data/lib/swarm_cli/ui/formatters/time.rb +0 -73
- data/lib/swarm_cli/ui/icons.rb +0 -36
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
- data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
- data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
- data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
- data/lib/swarm_cli/version.rb +0 -5
- data/lib/swarm_cli.rb +0 -46
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
- data/lib/swarm_sdk/agent/builder.rb +0 -552
- data/lib/swarm_sdk/agent/chat.rb +0 -774
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
- data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
- data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
- data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
- data/lib/swarm_sdk/agent/context.rb +0 -116
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -477
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/builders/base_builder.rb +0 -409
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
- data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
- data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
- data/lib/swarm_sdk/concerns/validatable.rb +0 -55
- data/lib/swarm_sdk/configuration/parser.rb +0 -353
- data/lib/swarm_sdk/configuration/translator.rb +0 -255
- data/lib/swarm_sdk/configuration.rb +0 -135
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
- data/lib/swarm_sdk/context_compactor.rb +0 -335
- data/lib/swarm_sdk/context_management/builder.rb +0 -128
- data/lib/swarm_sdk/context_management/context.rb +0 -328
- data/lib/swarm_sdk/defaults.rb +0 -196
- data/lib/swarm_sdk/events_to_messages.rb +0 -199
- data/lib/swarm_sdk/hooks/adapter.rb +0 -359
- data/lib/swarm_sdk/hooks/context.rb +0 -197
- data/lib/swarm_sdk/hooks/definition.rb +0 -80
- data/lib/swarm_sdk/hooks/error.rb +0 -29
- data/lib/swarm_sdk/hooks/executor.rb +0 -146
- data/lib/swarm_sdk/hooks/registry.rb +0 -147
- data/lib/swarm_sdk/hooks/result.rb +0 -150
- data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
- data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
- data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
- data/lib/swarm_sdk/log_collector.rb +0 -227
- data/lib/swarm_sdk/log_stream.rb +0 -127
- data/lib/swarm_sdk/markdown_parser.rb +0 -75
- data/lib/swarm_sdk/model_aliases.json +0 -8
- data/lib/swarm_sdk/models.json +0 -1
- data/lib/swarm_sdk/models.rb +0 -120
- data/lib/swarm_sdk/node_context.rb +0 -245
- data/lib/swarm_sdk/observer/builder.rb +0 -81
- data/lib/swarm_sdk/observer/config.rb +0 -45
- data/lib/swarm_sdk/observer/manager.rb +0 -236
- data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
- data/lib/swarm_sdk/permissions/config.rb +0 -239
- data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
- data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
- data/lib/swarm_sdk/permissions/validator.rb +0 -173
- data/lib/swarm_sdk/permissions_builder.rb +0 -122
- data/lib/swarm_sdk/plugin.rb +0 -309
- data/lib/swarm_sdk/plugin_registry.rb +0 -101
- data/lib/swarm_sdk/proc_helpers.rb +0 -53
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
- data/lib/swarm_sdk/restore_result.rb +0 -65
- data/lib/swarm_sdk/result.rb +0 -123
- data/lib/swarm_sdk/snapshot.rb +0 -156
- data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
- data/lib/swarm_sdk/state_restorer.rb +0 -476
- data/lib/swarm_sdk/state_snapshot.rb +0 -334
- data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
- data/lib/swarm_sdk/swarm/builder.rb +0 -249
- data/lib/swarm_sdk/swarm/executor.rb +0 -213
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
- data/lib/swarm_sdk/swarm.rb +0 -717
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/bash.rb +0 -282
- data/lib/swarm_sdk/tools/clock.rb +0 -44
- data/lib/swarm_sdk/tools/delegate.rb +0 -267
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
- data/lib/swarm_sdk/tools/edit.rb +0 -145
- data/lib/swarm_sdk/tools/glob.rb +0 -166
- data/lib/swarm_sdk/tools/grep.rb +0 -235
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
- data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
- data/lib/swarm_sdk/tools/read.rb +0 -261
- data/lib/swarm_sdk/tools/registry.rb +0 -205
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
- data/lib/swarm_sdk/tools/think.rb +0 -98
- data/lib/swarm_sdk/tools/todo_write.rb +0 -235
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/utils.rb +0 -68
- data/lib/swarm_sdk/validation_result.rb +0 -33
- data/lib/swarm_sdk/version.rb +0 -5
- data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
- data/lib/swarm_sdk/workflow/builder.rb +0 -143
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
- data/lib/swarm_sdk/workflow.rb +0 -554
- 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
|