Class: Rubino::Context::Compressor

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/context/compressor.rb

Overview

Orchestrates context compaction: flush memory, split messages into head/middle/tail, generate summary, create child session.

Instance Method Summary collapse

Constructor Details

#initialize(session_id:, config: nil, db: nil) ⇒ Compressor

Returns a new instance of Compressor.



10
11
12
13
14
15
16
17
# File 'lib/rubino/context/compressor.rb', line 10

def initialize(session_id:, config: nil, db: nil)
  @session_id = session_id
  @config = config || Rubino.configuration
  @db = db || Rubino.database.db
  @message_store = Session::Store.new(db: @db)
  @session_repo = Session::Repository.new(db: @db)
  @summary_store = Session::SummaryStore.new(db: @db)
end

Instance Method Details

#compact!Object

Performs full compaction and returns metadata

Raises:



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rubino/context/compressor.rb', line 20

def compact!
  session = @session_repo.find(@session_id)
  raise CompactionError, "Session not found: #{@session_id}" unless session

  messages = @message_store.for_session(@session_id)
  return no_op_result if messages.size < minimum_messages

  # 1. Flush memory before compaction
  flush_memory!

  # 2. Split messages into head / middle / tail
  boundary = MessageBoundary.new(messages: messages, config: @config)
  head = boundary.head
  middle = boundary.middle
  tail = boundary.tail

  return no_op_result if middle.empty?

  # 3. Sanitize tool pairs in middle
  if @config.compression_preserve_tool_pairs?
    sanitizer = ToolPairSanitizer.new
    middle = sanitizer.sanitize(middle)
  end

  # 4. Load previous summary (capture id now, before the insert below
  #    overwrites "latest" — the lineage link must point at the prior row)
  previous = @summary_store.latest(@session_id)
  previous_summary = previous&.dig(:content)
  previous_summary_id = previous&.dig(:id)

  # 5. Generate new summary
  summary_builder = SummaryBuilder.new(session_id: @session_id)
  new_summary = summary_builder.build(
    messages: middle,
    previous_summary: previous_summary
  )

  # 6. Save summary (chains parent_summary_id to the previous row)
  summary_id = @summary_store.insert(session_id: @session_id, content: new_summary)

  # 7. Create child session with compacted context
  child_session = create_child_session(session, head, new_summary, tail)

  # 8. Record compaction lineage
  record_compaction(
    source_id: @session_id,
    target_id: child_session[:id],
    previous_summary_id: previous_summary_id,
    new_summary_id: summary_id,
    original_tokens: estimate_tokens(messages),
    compacted_tokens: estimate_tokens(head + tail)
  )

  {
    source_session_id: @session_id,
    target_session_id: child_session[:id],
    original_messages: messages.size,
    compacted_messages: head.size + tail.size + 1, # +1 for summary
    saved_tokens: estimate_tokens(middle),
    summary_id: summary_id
  }
end