Class: Clacky::IdleCompressionTimer

Inherits:
Object
  • Object
show all
Defined in:
lib/clacky/idle_compression_timer.rb

Overview

IdleCompressionTimer triggers memory compression after a period of inactivity.

Both CLI and WebUI use the same agent-level compression logic; this class abstracts the “wait N seconds, then compress” pattern so it can be shared.

Usage:

timer = IdleCompressionTimer.new(agent: agent, session_manager: sm) do |success|
  # called on the compression thread after compression finishes
  broadcast_update if success
end
timer.start   # call after each agent run completes
timer.cancel  # call when new user input arrives

Constant Summary collapse

IDLE_DELAY =

Seconds of inactivity before idle compression is triggered

180

Instance Method Summary collapse

Constructor Details

#initialize(agent:, session_manager: nil, logger: nil, &on_compress) ⇒ IdleCompressionTimer

Returns a new instance of IdleCompressionTimer.

Parameters:

  • agent (Clacky::Agent)

    the agent whose messages will be compressed

  • session_manager (Clacky::SessionManager, nil) (defaults to: nil)

    used to persist session after compression

  • logger (#call, nil) (defaults to: nil)

    optional logger lambda: ->(msg, level:) { … }

  • on_compress (Proc, nil)

    block called after compression attempt with success (bool)



24
25
26
27
28
29
30
31
32
33
# File 'lib/clacky/idle_compression_timer.rb', line 24

def initialize(agent:, session_manager: nil, logger: nil, &on_compress)
  @agent           = agent
  @session_manager = session_manager
  @logger          = logger
  @on_compress     = on_compress

  @timer_thread    = nil
  @compress_thread = nil
  @mutex           = Mutex.new
end

Instance Method Details

#active?Boolean

True if the timer or compression is currently active.

Returns:

  • (Boolean)


83
84
85
# File 'lib/clacky/idle_compression_timer.rb', line 83

def active?
  @mutex.synchronize { @timer_thread&.alive? || @compress_thread&.alive? }
end

#cancelObject

Cancel the timer and any in-progress compression. Raises AgentInterrupted on the compress thread and waits for it to fully exit, ensuring history rollback completes before the caller starts a new agent.run.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/clacky/idle_compression_timer.rb', line 63

def cancel
  compress_thread_to_join = nil

  @mutex.synchronize do
    @timer_thread&.kill
    if @compress_thread&.alive?
      @compress_thread.raise(Clacky::AgentInterrupted, "Idle timer cancelled")
      compress_thread_to_join = @compress_thread
    end
    @timer_thread    = nil
    @compress_thread = nil
  end

  # Join outside the mutex to avoid deadlock.
  # This blocks until the compress thread has finished rolling back history,
  # so the subsequent agent.run sees a clean, consistent history.
  compress_thread_to_join&.join(5)
end

#startObject

Start (or restart) the idle timer. Cancels any existing timer first, then waits IDLE_DELAY seconds before compressing.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/clacky/idle_compression_timer.rb', line 37

def start
  cancel # reset any existing timer

  @timer_thread = Thread.new do
    Thread.current.name = "idle-compression-timer"
    sleep IDLE_DELAY

    # Register @compress_thread inside the mutex BEFORE the thread starts running,
    # so cancel() can always find and interrupt it even if it fires immediately.
    compress_thread = nil
    @mutex.synchronize do
      compress_thread = Thread.new do
        Thread.current.name = "idle-compression-work"
        run_compression
      end
      @compress_thread = compress_thread
    end

    compress_thread.join
    @mutex.synchronize { @compress_thread = nil; @timer_thread = nil }
  end
end