Module: SwarmSDK::Agent::ChatHelpers::HookIntegration
- Included in:
- SwarmSDK::Agent::Chat
- Defined in:
- lib/swarm_sdk/agent/chat_helpers/hook_integration.rb
Overview
Integrates SwarmSDK's hook system with Agent::Chat
Responsibilities:
- Setup hook system (registry, executor, agent hooks)
- Provide trigger methods for all hook events
- Wrap ask() to inject user_prompt hooks
- Handle hook results (halt, replace, continue, reprompt)
This module is included in Agent::Chat and provides methods for triggering hooks. It overrides ask() to inject user_prompt hooks, but does NOT override handle_tool_calls (that's handled in Agent::Chat with explicit hook calls).
Instance Attribute Summary collapse
-
#hook_agent_hooks ⇒ Object
readonly
Expose hook system components for ContextTracker.
-
#hook_executor ⇒ Object
readonly
Expose hook system components for ContextTracker.
-
#hook_swarm ⇒ Object
readonly
Expose hook system components for ContextTracker.
Instance Method Summary collapse
-
#add_hook(event, matcher: nil, priority: 0, &block) ⇒ Object
Add a hook programmatically at runtime.
-
#check_context_warnings ⇒ Object
Override check_context_warnings to trigger our hook system.
-
#setup_hooks(registry:, agent_definition:, swarm: nil) ⇒ void
Setup the hook system for this agent chat.
-
#trigger_post_tool_use(result, tool_call:) ⇒ Object, Hash
Trigger post_tool_use hooks.
-
#trigger_pre_tool_use(tool_call) ⇒ Hash
Trigger pre_tool_use hooks.
Instance Attribute Details
#hook_agent_hooks ⇒ Object (readonly)
Expose hook system components for ContextTracker
19 20 21 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 19 def hook_agent_hooks @hook_agent_hooks end |
#hook_executor ⇒ Object (readonly)
Expose hook system components for ContextTracker
19 20 21 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 19 def hook_executor @hook_executor end |
#hook_swarm ⇒ Object (readonly)
Expose hook system components for ContextTracker
19 20 21 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 19 def hook_swarm @hook_swarm end |
Instance Method Details
#add_hook(event, matcher: nil, priority: 0, &block) ⇒ Object
Add a hook programmatically at runtime
This allows agents to add hooks dynamically, which is useful for implementing adaptive behavior or runtime monitoring.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 59 def add_hook(event, matcher: nil, priority: 0, &block) raise ArgumentError, "Hooks not set up. Call setup_hooks first." unless @hook_executor definition = Hooks::Definition.new( event: event, matcher: matcher, priority: priority, proc: block, ) @hook_agent_hooks[event] ||= [] @hook_agent_hooks[event] << definition @hook_agent_hooks[event].sort_by! { |cb| -cb.priority } end |
#check_context_warnings ⇒ Object
Override check_context_warnings to trigger our hook system
This wraps the default context warning behavior to also trigger hooks. Unified implementation that:
- Emits context_threshold_hit events (for snapshot reconstruction)
- Optionally triggers automatic compression at 60% (if no custom handler)
- Emits context_limit_warning events (backward compatibility)
- Triggers user-defined context_warning hooks
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 93 def check_context_warnings return unless respond_to?(:context_usage_percentage) current_percentage = context_usage_percentage Context::CONTEXT_WARNING_THRESHOLDS.each do |threshold| # Only warn once per threshold next if @agent_context.warning_threshold_hit?(threshold) next if current_percentage < threshold # Mark threshold as hit @agent_context.hit_warning_threshold?(threshold) # Emit context_threshold_hit event (for snapshot reconstruction) - CRITICAL LogStream.emit( type: "context_threshold_hit", agent: @agent_context.name, threshold: threshold, current_usage_percentage: current_percentage.round(2), ) # Check if user has defined custom handler for context_warning # Custom handlers take responsibility for managing context at this threshold has_custom_handler = (@hook_agent_hooks[:context_warning] || []).any? # Trigger automatic compression at 60% ONLY if no custom handler compression_triggered = false if threshold == SwarmSDK.config.context_compression_threshold && !has_custom_handler compressed_count = apply_automatic_compression compression_triggered = compressed_count > 0 end # Emit legacy context_limit_warning for backwards compatibility LogStream.emit( type: "context_limit_warning", agent: @agent_context.name, model: model_id, threshold: "#{threshold}%", current_usage: "#{current_percentage}%", tokens_used: cumulative_total_tokens, tokens_remaining: tokens_remaining, context_limit: context_limit, metadata: @agent_context., compression_triggered: compression_triggered, ) # Trigger hook system (user-defined handlers) trigger_context_warning(threshold, current_percentage) if @hook_executor end end |
#setup_hooks(registry:, agent_definition:, swarm: nil) ⇒ void
This method returns an undefined value.
Setup the hook system for this agent chat
This must be called after setup_context and before the first ask/complete. It wires up the hook system to trigger at the right times.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 30 def setup_hooks(registry:, agent_definition:, swarm: nil) @hook_registry = registry @hook_swarm = swarm @hook_executor = Hooks::Executor.new(registry, logger: RubyLLM.logger) # Extract agent hooks based on format hooks = agent_definition.hooks || {} # Check if hooks are pre-parsed HookDefinition objects (from DSL) # or raw YAML hash (to be processed by Hooks::Adapter in pass_5) @hook_agent_hooks = if hooks.is_a?(Hash) && hooks.values.all? { |v| v.is_a?(Array) && v.all? { |item| item.is_a?(Hooks::Definition) } } # DSL hooks - already parsed, use them hooks else # YAML hooks - raw hash, will be processed in pass_5 by Hooks::Adapter # For now, use empty hash (pass_5 will add them later) {} end end |
#trigger_post_tool_use(result, tool_call:) ⇒ Object, Hash
Trigger post_tool_use hooks
Should be called by Agent::Chat after tool execution. Returns modified result if hook replaces it, or a special marker for finish actions.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 191 def trigger_post_tool_use(result, tool_call:) return result unless @hook_executor # Extract tracking digest for Read/MemoryRead tools = extract_tool_tracking_digest(tool_call, result) context = build_hook_context( event: :post_tool_use, tool_result: wrap_tool_result(tool_call.id, tool_call.name, result), metadata: , ) agent_hooks = @hook_agent_hooks[:post_tool_use] || [] hook_result = @hook_executor.execute_safe( event: :post_tool_use, context: context, callbacks: agent_hooks, ) # Return modified result or finish markers if hook_result.replace? hook_result.value elsif hook_result.finish_agent? { __finish_agent__: true, message: hook_result.value } elsif hook_result.finish_swarm? { __finish_swarm__: true, message: hook_result.value } else result end end |
#trigger_pre_tool_use(tool_call) ⇒ Hash
Trigger pre_tool_use hooks
Should be called by Agent::Chat before tool execution. Returns a hash indicating whether to proceed and any custom result.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/swarm_sdk/agent/chat_helpers/hook_integration.rb', line 151 def trigger_pre_tool_use(tool_call) return { proceed: true } unless @hook_executor context = build_hook_context( event: :pre_tool_use, tool_call: wrap_tool_call_to_hooks(tool_call), ) agent_hooks = @hook_agent_hooks[:pre_tool_use] || [] result = @hook_executor.execute_safe( event: :pre_tool_use, context: context, callbacks: agent_hooks, ) # Return custom result if hook provides one if result.replace? { proceed: false, custom_result: result.value } elsif result.halt? { proceed: false, custom_result: result.value || "Tool execution blocked by hook" } elsif result.finish_agent? # Finish agent execution immediately with this message { proceed: false, finish_agent: true, custom_result: result.value } elsif result.finish_swarm? # Finish entire swarm execution immediately with this message { proceed: false, finish_swarm: true, custom_result: result.value } else { proceed: true } end end |