Class: Silas::LogSubscriber

Inherits:
ActiveSupport::LogSubscriber
  • Object
show all
Defined in:
lib/silas/log_subscriber.rb

Overview

Turns the loop's notifications into log lines, at levels that match what an operator actually wants paged about: parks and rescues are INFO (a human is now in the loop, or a crash was recovered), budget breaches and nondeterminism are WARN, failed turns are ERROR, and the per-step/per-token chatter stays DEBUG.

Attach is automatic (see Silas::Engine). To silence just Silas:

Silas.logger = Logger.new(IO::NULL)

Instance Method Summary collapse

Instance Method Details

#approval(event) ⇒ Object



41
42
43
44
# File 'lib/silas/log_subscriber.rb', line 41

def approval(event)
  info formatted_event(event, action: "Approval #{event.payload[:action]}",
                       **event.payload.slice(:tool, :by, :turn_id).compact)
end

#budget(event) ⇒ Object



46
47
48
49
# File 'lib/silas/log_subscriber.rb', line 46

def budget(event)
  warn formatted_event(event, action: "Budget reached (#{event.payload[:reason]})",
                       **event.payload.slice(:turn_id).compact)
end

#compact(event) ⇒ Object



51
52
53
54
# File 'lib/silas/log_subscriber.rb', line 51

def compact(event)
  info formatted_event(event, action: "Compacted through turn #{event.payload[:up_to_turn_index]}",
                       **event.payload.slice(:session_id, :turn_id, :tokens_before, :output_tokens).compact)
end

#nondeterminism(event) ⇒ Object



56
57
58
59
# File 'lib/silas/log_subscriber.rb', line 56

def nondeterminism(event)
  error formatted_event(event, action: "Definitions changed mid-turn",
                        **event.payload.slice(:turn_id, :was, :now).compact)
end

#park(event) ⇒ Object



30
31
32
33
# File 'lib/silas/log_subscriber.rb', line 30

def park(event)
  info formatted_event(event, action: "Turn parked (#{event.payload[:reason]})",
                       **event.payload.slice(:turn_id, :detail).compact)
end

#rescue(event) ⇒ Object



61
62
63
64
65
66
# File 'lib/silas/log_subscriber.rb', line 61

def rescue(event)
  payload = event.payload
  return if payload[:rescued].to_i.zero? && payload[:stranded].to_i.zero?

  info formatted_event(event, action: "Rescuer", **payload.slice(:rescued, :stranded))
end

#resume(event) ⇒ Object



35
36
37
38
39
# File 'lib/silas/log_subscriber.rb', line 35

def resume(event)
  parked_for = event.payload[:parked_for]
  info formatted_event(event, action: "Turn resumed after #{parked_for&.round(1)}s parked",
                       **event.payload.slice(:turn_id).compact)
end

#step(event) ⇒ Object



19
20
21
22
# File 'lib/silas/log_subscriber.rb', line 19

def step(event)
  debug formatted_event(event, action: "Model call",
                        **event.payload.slice(:turn_id, :index, :model).compact)
end

#tool(event) ⇒ Object



24
25
26
27
28
# File 'lib/silas/log_subscriber.rb', line 24

def tool(event)
  line = formatted_event(event, action: "Tool #{event.payload[:tool]}",
                         **event.payload.slice(:effect_mode, :status, :approval_state, :turn_id).compact)
  event.payload[:status].to_s == "failed" ? warn(line) : info(line)
end

#turn(event) ⇒ Object



12
13
14
15
16
17
# File 'lib/silas/log_subscriber.rb', line 12

def turn(event)
  status = event.payload[:status]
  line = formatted_event(event, action: "Turn #{status}",
                         **event.payload.slice(:turn_id, :session_id, :agent, :steps, :reason).compact)
  status.to_s == "failed" ? error(line) : info(line)
end