Documentation
¶
Overview ¶
Package monitor hosts the deferred Monitor tool — a background process watcher that streams stdout lines as agent-loop notifications.
The tool spawns the configured shell command in its own process group bound to the host's RootCtx (so monitor goroutines survive the LLM call that spawned them). For each stdout line the goroutine writes a MonitorEvent to the host's queue and fires a signal so an idle agent wakes up to react; events arriving while the loop is busy are folded into the next iteration via drainMonitorEvents.
Index ¶
- Constants
- func GenerateID() string
- func Names() []tools.ToolName
- type MonitorEvent
- type MonitorEventQueue
- type MonitorHost
- type MonitorStatus
- type MonitorTask
- type MonitorTaskSnapshot
- type MonitorTaskStore
- func (s *MonitorTaskStore) Add(snap MonitorTaskSnapshot, cancel context.CancelFunc)
- func (s *MonitorTaskStore) Complete(id string, status MonitorStatus)
- func (s *MonitorTaskStore) Domain() string
- func (s *MonitorTaskStore) Get(id string) (MonitorTaskSnapshot, bool)
- func (s *MonitorTaskStore) IncEventCount(id string)
- func (s *MonitorTaskStore) Snapshot() []MonitorTaskSnapshot
- func (s *MonitorTaskStore) Stop(id string) (MonitorTaskSnapshot, bool)
- type MonitorTool
Constants ¶
const MonitorDomain = "monitors"
MonitorDomain is the observable.Change.Domain for monitor task changes.
Variables ¶
This section is empty.
Functions ¶
func GenerateID ¶
func GenerateID() string
GenerateID returns "m" + 8 random base-36 chars. Distinct prefix from shell.GenerateID's "b" so a transcript can disambiguate at a glance.
Types ¶
type MonitorEvent ¶
MonitorEvent is one stdout line streamed by a running monitor. Closing is true on the final event when the underlying process exits (or task_stop is called) — drain folds the closing event into the system-reminder and the TUI strip flips the chip to Stopped.
type MonitorEventQueue ¶
type MonitorEventQueue struct {
// contains filtered or unexported fields
}
MonitorEventQueue is the FIFO queue of streamed lines from every running monitor. The agent's drainMonitorEvents helper pulls events at iter start and folds them into a single <system-reminder> RoleUser message; events are never persisted beyond the drain.
func NewMonitorEventQueue ¶
func NewMonitorEventQueue() *MonitorEventQueue
NewMonitorEventQueue returns an empty queue.
func (*MonitorEventQueue) Drain ¶
func (q *MonitorEventQueue) Drain() []MonitorEvent
Drain returns every queued event in arrival order and clears the queue. Returns nil when empty so the drain helper can short-circuit.
func (*MonitorEventQueue) Enqueue ¶
func (q *MonitorEventQueue) Enqueue(ev MonitorEvent)
Enqueue pushes one event. Callers (monitor goroutines) call this before signalling the agent so the drain at iter start sees the event regardless of how the pump's CAS races.
func (*MonitorEventQueue) HasPending ¶
func (q *MonitorEventQueue) HasPending() bool
HasPending reports whether the queue carries any undrained events. Cheap mu-read used by the agent loop's end-of-turn re-check.
type MonitorHost ¶
type MonitorHost interface {
// MonitorTaskStore returns the agent's monitor catalog.
MonitorTaskStore() *MonitorTaskStore
// MonitorEventQueue returns the per-agent queue every monitor
// streams events into.
MonitorEventQueue() *MonitorEventQueue
// RootCtx returns the agent-lifetime context; monitor goroutines
// bind here, not the per-call ctx.
RootCtx() context.Context
// AgentID is the spawning agent's id.
AgentID() string
// NotifyMonitorEvent fires the agent's signal pump for one streamed
// event. Non-blocking; the queue is the durable backstop.
NotifyMonitorEvent(ev MonitorEvent)
}
MonitorHost is the narrow surface a MonitorTool reads from its host (*toolset.ToolState in production). Mirrors shell.BgTaskHost so the two implementations stay parallel.
type MonitorStatus ¶
type MonitorStatus string
MonitorStatus is the lifecycle state of one Monitor task. Distinct from shell.BgTaskStatus because monitor tasks can be long-lived (persistent loops) and don't carry a single exit code — they accumulate events.
Transitions:
Monitoring → Stopped (process exited cleanly OR task_stop called) Monitoring → Failed (process spawn failed)
const ( Monitoring MonitorStatus = "monitoring" Stopped MonitorStatus = "stopped" Failed MonitorStatus = "failed" )
type MonitorTask ¶
type MonitorTask struct {
MonitorTaskSnapshot
Cancel context.CancelFunc
}
MonitorTask is the live record the store mutates. Cancel terminates the underlying process — task_stop calls it; the goroutine then transitions the snapshot to Stopped.
type MonitorTaskSnapshot ¶
type MonitorTaskSnapshot struct {
ID string
Command string
Description string
Status MonitorStatus
EventCount int
StartedAt time.Time
StoppedAt time.Time
AgentID string
}
MonitorTaskSnapshot is the public shape of one monitor entry. The event count is read at snapshot time; events themselves live in the per-agent MonitorEventQueue, not on the snapshot.
type MonitorTaskStore ¶
type MonitorTaskStore struct {
*observable.Observable
// contains filtered or unexported fields
}
MonitorTaskStore is the agent-owned catalog of monitor tasks. Same shape as shell.BgTaskStore: embedded Observable for TUI fanout, internal mutex, lifecycle methods (Add / Complete / Stop) + query methods (Get / Snapshot).
Unlike BgTaskStore there is no DrainCompleted — monitors don't fold their snapshot into the conversation when they stop. The per-monitor closing event (Closing:true) carries that signal; the snapshot just transitions to Stopped/Failed and stays in the store until the session ends.
func NewMonitorTaskStore ¶
func NewMonitorTaskStore() *MonitorTaskStore
NewMonitorTaskStore returns an empty store.
func (*MonitorTaskStore) Add ¶
func (s *MonitorTaskStore) Add(snap MonitorTaskSnapshot, cancel context.CancelFunc)
Add registers a freshly-spawned monitor. cancel kills the underlying process on task_stop or root-ctx cancel. Emits a "started" Change so the strip renders the chip immediately.
func (*MonitorTaskStore) Complete ¶
func (s *MonitorTaskStore) Complete(id string, status MonitorStatus)
Complete transitions the monitor to a terminal state (Stopped / Failed). Clears Cancel so task_stop on a finished monitor is a clean no-op. Emits a Change matching the terminal Op for renderers.
func (*MonitorTaskStore) Domain ¶
func (s *MonitorTaskStore) Domain() string
Domain returns the observable store domain. Implements observable.Store.
func (*MonitorTaskStore) Get ¶
func (s *MonitorTaskStore) Get(id string) (MonitorTaskSnapshot, bool)
Get returns one task snapshot. ok=false when unknown.
func (*MonitorTaskStore) IncEventCount ¶
func (s *MonitorTaskStore) IncEventCount(id string)
IncEventCount bumps the event counter for a running monitor. Called by the monitor goroutine each time it streams a line. Emits an "event" Change for the strip to flicker.
func (*MonitorTaskStore) Snapshot ¶
func (s *MonitorTaskStore) Snapshot() []MonitorTaskSnapshot
Snapshot returns every monitor in started-at order. Used by the TUI strip.
func (*MonitorTaskStore) Stop ¶
func (s *MonitorTaskStore) Stop(id string) (MonitorTaskSnapshot, bool)
Stop signals the named monitor to terminate. ok=false when unknown or already terminal.
type MonitorTool ¶
type MonitorTool struct {
// contains filtered or unexported fields
}
MonitorTool spawns a long-running shell command and streams its stdout lines back to the agent as MonitorEvents. host supplies the MonitorTaskStore + event queue + signal sender; without it the tool reports a clean error rather than panicking.
func NewMonitor ¶
func NewMonitor(host MonitorHost) *MonitorTool
NewMonitor constructs the production MonitorTool. The toolset factory passes the agent's *ToolState as host so per-event delivery routes through the agent's signal pump.
func (*MonitorTool) Description ¶
func (t *MonitorTool) Description() string
func (*MonitorTool) Execute ¶
func (t *MonitorTool) Execute(_ context.Context, logger *slog.Logger, raw json.RawMessage) (tools.Result, error)
func (*MonitorTool) Name ¶
func (t *MonitorTool) Name() string
func (*MonitorTool) Schema ¶
func (t *MonitorTool) Schema() json.RawMessage