Class: Ask::AppServer::HerdrReporter

Inherits:
Object
  • Object
show all
Defined in:
lib/ask/app_server/herdr_reporter.rb

Overview

Pane integration: when the host runs inside a terminal workspace that injects HERDR_SOCKET_PATH and HERDR_PANE_ID into the pane's environment, this reporter connects to the workspace socket and keeps its agent-state sidebar accurate with first-party state — the host KNOWS when a turn is running or an approval is pending, which beats screen scraping:

pane.report_agent       — working | blocked | idle, on change
pane.report_agent_session — the ask session id, for future resume
pane.report_metadata    — model and session count as sidebar tokens

The pane state is the aggregate across the host's sessions (a host can serve many clients): blocked if any session awaits an approval, working if any turn is running, idle otherwise. Events that cannot change the aggregate (model.streaming, tool.*, todos) are ignored.

Attach once per session manager: HerdrReporter.attach(manager).

Constant Summary collapse

SOCKET_PATH_ENV =
"HERDR_SOCKET_PATH"
PANE_ID_ENV =
"HERDR_PANE_ID"
SOURCE =

Reports originate from the ask host; the workspace uses the pair to dedup and order per-source reports.

"ask:app-server"
AGENT =
"ask"
STATE_EVENTS =

Events that can change the aggregate pane state.

%w[
  turn.started turn.completed turn.failed turn.aborted
  approval.required approval.updated
  plan.proposed plan.approved plan.rejected
  session.created session.ended
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(session_manager:, socket_path:, pane_id:) ⇒ HerdrReporter

Returns a new instance of HerdrReporter.

Parameters:

  • session_manager (SessionManager)
  • socket_path (String)

    the workspace socket (HERDR_SOCKET_PATH)

  • pane_id (String)

    this pane (HERDR_PANE_ID)



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ask/app_server/herdr_reporter.rb', line 53

def initialize(session_manager:, socket_path:, pane_id:)
  @session_manager = session_manager
  @socket_path = socket_path
  @pane_id = pane_id
  @seq = 0
  @reported_state = nil
  @socket = nil
  @mutex = Mutex.new
  @enabled = true

  session_manager.on_session_event { |session_id, event| on_event(session_id, event) }
  report_state(compute_state)
end

Class Method Details

.attach(session_manager, socket_path: ENV[SOCKET_PATH_ENV], pane_id: ENV[PANE_ID_ENV]) ⇒ HerdrReporter?

Returns a live reporter, or nil when the workspace environment variables are absent.

Returns:

  • (HerdrReporter, nil)

    a live reporter, or nil when the workspace environment variables are absent



44
45
46
47
48
# File 'lib/ask/app_server/herdr_reporter.rb', line 44

def self.attach(session_manager, socket_path: ENV[SOCKET_PATH_ENV], pane_id: ENV[PANE_ID_ENV])
  return nil if socket_path.to_s.empty? || pane_id.to_s.empty?

  new(session_manager: session_manager, socket_path: socket_path, pane_id: pane_id)
end

Instance Method Details

#closeObject

Stop reporting and drop the workspace connection.



68
69
70
71
72
73
74
# File 'lib/ask/app_server/herdr_reporter.rb', line 68

def close
  @enabled = false
  @mutex.synchronize do
    @socket&.close rescue nil
    @socket = nil
  end
end