Class: SwarmSDK::ContextManagement::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/swarm_sdk/context_management/context.rb

Overview

Rich context wrapper for context management handlers

Provides a clean, developer-friendly API for manipulating the conversation context when warning thresholds are triggered. Wraps the lower-level Hooks::Context with message manipulation helpers.

Examples:

Basic usage in handler

on :warning_60 do |ctx|
  ctx.compress_tool_results(keep_recent: 10)
end

Advanced usage with metrics

on :warning_80 do |ctx|
  if ctx.usage_percentage > 85
    ctx.prune_old_messages(keep_recent: 10)
    ctx.log_action("aggressive_pruning", remaining: ctx.tokens_remaining)
  else
    ctx.compress_tool_results(keep_recent: 5, truncate_to: 100)
  end
end

Instance Method Summary collapse

Constructor Details

#initialize(hooks_context) ⇒ Context

Create a new context wrapper

Parameters:

  • hooks_context (Hooks::Context)

    Lower-level hook context with metadata



29
30
31
32
# File 'lib/swarm_sdk/context_management/context.rb', line 29

def initialize(hooks_context)
  @hooks_context = hooks_context
  @chat = hooks_context.[:chat]
end

Instance Method Details

#agent_nameSymbol

Agent name

Examples:

ctx.log_action("agent_context", agent: ctx.agent_name)

Returns:

  • (Symbol)

    Agent identifier



96
97
98
# File 'lib/swarm_sdk/context_management/context.rb', line 96

def agent_name
  @hooks_context.agent_name
end

#compress_tool_results(keep_recent: 10, truncate_to: 200) ⇒ Integer

Compress tool result messages to save context space

Creates NEW message objects with truncated content (follows RubyLLM patterns). Truncates old tool results while keeping recent ones intact. Automatically marks compression as applied to prevent double compression.

Examples:

Light compression at 60%

ctx.compress_tool_results(keep_recent: 15, truncate_to: 500)

Aggressive compression at 80%

ctx.compress_tool_results(keep_recent: 5, truncate_to: 100)

Parameters:

  • keep_recent (Integer) (defaults to: 10)

    Number of recent tool results to preserve (default: 10)

  • truncate_to (Integer) (defaults to: 200)

    Max characters for truncated results (default: 200)

Returns:

  • (Integer)

    Number of messages compressed



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
182
183
184
185
186
187
188
189
190
191
# File 'lib/swarm_sdk/context_management/context.rb', line 155

def compress_tool_results(keep_recent: 10, truncate_to: 200)
  msgs = messages.dup
  compressed_count = 0

  # Find tool result messages (skip recent ones)
  tool_indices = []
  msgs.each_with_index do |msg, idx|
    tool_indices << idx if msg.role == :tool
  end

  # Keep recent tool results, compress older ones
  indices_to_compress = tool_indices[0...-keep_recent] || []

  indices_to_compress.each do |idx|
    msg = msgs[idx]
    content = msg.content.to_s
    next if content.length <= truncate_to

    # Create NEW message with truncated content (NO instance_variable_set!)
    truncated_content = "#{content[0...truncate_to]}... [truncated for context management]"

    # Create new message object following RubyLLM patterns
    msgs[idx] = RubyLLM::Message.new(
      role: :tool,
      content: truncated_content,
      tool_call_id: msg.tool_call_id,
    )
    compressed_count += 1
  end

  replace_messages(msgs)

  # Mark compression as applied to coordinate with ContextManager
  mark_compression_applied

  compressed_count
end

#compression_applied?Boolean

Check if compression has already been applied

Examples:

Conditional compression

unless ctx.compression_applied?
  ctx.compress_tool_results(keep_recent: 10)
end

Returns:

  • (Boolean)

    True if compression was already applied



218
219
220
221
222
# File 'lib/swarm_sdk/context_management/context.rb', line 218

def compression_applied?
  return false unless @chat.respond_to?(:context_manager)

  !!@chat.context_manager.compression_applied
end

#context_limitInteger

Total context window size

Examples:

buffer = ctx.context_limit * 0.1  # 10% buffer

Returns:

  • (Integer)

    Token count



86
87
88
# File 'lib/swarm_sdk/context_management/context.rb', line 86

def context_limit
  @hooks_context.[:context_limit]
end

#log_action(action, details = {}) ⇒ void

This method returns an undefined value.

Log a context management action

Emits a log event for tracking what actions were taken. Useful for debugging and monitoring context management strategies.

Examples:

Log compression action

ctx.log_action("compressed_tool_results", count: 5)

Log emergency action

ctx.log_action("emergency_pruning", remaining: ctx.tokens_remaining)

Parameters:

  • action (String)

    Description of action taken

  • details (Hash) (defaults to: {})

    Additional details



316
317
318
319
320
321
322
323
324
325
# File 'lib/swarm_sdk/context_management/context.rb', line 316

def log_action(action, details = {})
  LogStream.emit(
    type: "context_management_action",
    agent: agent_name,
    threshold: threshold,
    action: action,
    usage_percentage: usage_percentage,
    **details,
  )
end

#mark_compression_appliedvoid

This method returns an undefined value.

Mark compression as applied in ContextManager

Call this when your handler performs compression to prevent double compression from auto-compression logic.

Examples:

Custom compression

msgs = ctx.messages.map { |m| ... } # custom logic
ctx.replace_messages(msgs)
ctx.mark_compression_applied


204
205
206
207
208
# File 'lib/swarm_sdk/context_management/context.rb', line 204

def mark_compression_applied
  return unless @chat.respond_to?(:context_manager)

  @chat.context_manager.compression_applied = true
end

#message_countInteger

Number of messages

Examples:

if ctx.message_count > 100
  ctx.prune_old_messages(keep_recent: 50)
end

Returns:

  • (Integer)

    Message count



122
123
124
# File 'lib/swarm_sdk/context_management/context.rb', line 122

def message_count
  @chat.message_count
end

#messagesArray<RubyLLM::Message>

Get all messages (copy for manipulation)

Examples:

ctx.messages.each do |msg|
  puts "#{msg.role}: #{msg.content.length} chars"
end

Returns:

  • (Array<RubyLLM::Message>)

    Message array



110
111
112
# File 'lib/swarm_sdk/context_management/context.rb', line 110

def messages
  @chat.messages
end

#prune_old_messages(keep_recent: 20) ⇒ Integer

Remove old messages from history

Keeps system message (if any) and recent exchanges. This is more aggressive than compression and loses context.

Examples:

Prune at 80% threshold

ctx.prune_old_messages(keep_recent: 30)

Emergency pruning at 90%

ctx.prune_old_messages(keep_recent: 10)

Parameters:

  • keep_recent (Integer) (defaults to: 20)

    Number of recent messages to keep (default: 20)

Returns:

  • (Integer)

    Number of messages removed



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/swarm_sdk/context_management/context.rb', line 237

def prune_old_messages(keep_recent: 20)
  msgs = messages.dup
  original_count = msgs.size

  # Always keep system message if present
  system_msg = msgs.first if msgs.first&.role == :system
  non_system = system_msg ? msgs[1..] : msgs

  # Keep only recent messages
  if non_system.size > keep_recent
    kept = non_system.last(keep_recent)
    new_msgs = system_msg ? [system_msg] + kept : kept
    replace_messages(new_msgs)
    original_count - new_msgs.size
  else
    0
  end
end

#replace_messages(new_messages) ⇒ void

This method returns an undefined value.

Replace all messages with new array

Examples:

new_msgs = ctx.messages.reject { |m| m.role == :tool }
ctx.replace_messages(new_msgs)

Parameters:

  • new_messages (Array<RubyLLM::Message>)

    New message array



136
137
138
# File 'lib/swarm_sdk/context_management/context.rb', line 136

def replace_messages(new_messages)
  @chat.replace_messages(new_messages)
end

#summarize_old_exchanges(older_than: 10) ⇒ Integer

Summarize old message exchanges

Groups old user/assistant pairs and replaces with summary. This is a placeholder - actual implementation would use LLM.

Examples:

ctx.summarize_old_exchanges(older_than: 10)

Parameters:

  • older_than (Integer) (defaults to: 10)

    Messages older than this index get summarized

Returns:

  • (Integer)

    Number of exchanges summarized



266
267
268
269
270
271
# File 'lib/swarm_sdk/context_management/context.rb', line 266

def summarize_old_exchanges(older_than: 10)
  # For now, this is a marker - full implementation would call LLM
  # to summarize exchanges. We provide the API for developers to
  # implement their own summarization logic.
  0
end

#thresholdInteger

Threshold that triggered this handler

Examples:

ctx.log_action("threshold_hit", threshold: ctx.threshold)

Returns:

  • (Integer)

    Threshold (60, 80, or 90)



54
55
56
# File 'lib/swarm_sdk/context_management/context.rb', line 54

def threshold
  @hooks_context.[:threshold]
end

#tokens_remainingInteger

Tokens remaining in context window

Examples:

if ctx.tokens_remaining < 10000
  ctx.prune_old_messages(keep_recent: 5)
end

Returns:

  • (Integer)

    Token count



76
77
78
# File 'lib/swarm_sdk/context_management/context.rb', line 76

def tokens_remaining
  @hooks_context.[:tokens_remaining]
end

#tokens_usedInteger

Total tokens used so far

Examples:

ctx.log_action("usage", tokens: ctx.tokens_used)

Returns:

  • (Integer)

    Token count



64
65
66
# File 'lib/swarm_sdk/context_management/context.rb', line 64

def tokens_used
  @hooks_context.[:tokens_used]
end

#transform_messages {|Array<RubyLLM::Message>| ... } ⇒ void

This method returns an undefined value.

Custom message transformation

Apply a block to transform messages. This gives full control over message manipulation for custom strategies.

Examples:

Remove specific tool results

ctx.transform_messages do |msgs|
  msgs.reject { |m| m.role == :tool && m.content.include?("verbose output") }
end

Custom compression logic

ctx.transform_messages do |msgs|
  msgs.map do |m|
    if m.role == :tool && m.content.length > 1000
      RubyLLM::Message.new(role: :tool, content: m.content[0..500], tool_call_id: m.tool_call_id)
    else
      m
    end
  end
end

Yields:

  • (Array<RubyLLM::Message>)

    Current messages

Yield Returns:

  • (Array<RubyLLM::Message>)

    Transformed messages



297
298
299
300
# File 'lib/swarm_sdk/context_management/context.rb', line 297

def transform_messages
  new_msgs = yield(messages.dup)
  replace_messages(new_msgs)
end

#usage_percentageFloat

Current context usage percentage

Examples:

if ctx.usage_percentage > 85
  ctx.prune_old_messages(keep_recent: 10)
end

Returns:

  • (Float)

    Usage percentage (0.0 to 100.0)



44
45
46
# File 'lib/swarm_sdk/context_management/context.rb', line 44

def usage_percentage
  @hooks_context.[:percentage]
end