notifier

package
v0.2.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package notifier is the host's outbound-notification delivery pipeline. It owns queuing, send timeouts, and Provider lifecycle — nothing else. Deciding what is push-worthy and composing the copy is entirely the caller's job (internal/host classifies backend events and enriches them with session metadata before handing over a finished Notification); this package never inspects events and has no policy of its own.

The Loop owns an internal buffered channel + worker goroutine: the caller enqueues via Notify (non-blocking), and the worker drains it serially into Provider.Send. Send is allowed to be slow — the worker isolates it from the caller so a misbehaving provider can't backpressure the host's event fan-out.

Index

Constants

View Source
const (
	// DefaultBuffer is the worker's input queue size. Notifications are
	// rare (a permission ask or an idle flip per agent turn), so this
	// mostly absorbs a provider that stalls across a burst of sessions.
	// Overflow drops notifications (and logs) rather than blocking the
	// caller.
	DefaultBuffer = 64

	// DefaultSendTimeout caps a single Provider.Send. Picked to be
	// short enough that a hung provider doesn't drain the buffer to
	// drops while still leaving room for normal HTTP round-trips.
	DefaultSendTimeout = 5 * time.Second
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Provider    Provider
	Log         *log.Logger
	Buffer      int
	SendTimeout time.Duration
}

Config configures a Loop at construction time. Provider is required.

type Kind

type Kind string

Kind classifies a Notification. Providers may use Kind to choose transport (e.g. high-priority push for KindPermission) or copy.

const (
	KindIdle       Kind = "idle"       // Agent transitioned to idle (finished a turn)
	KindPermission Kind = "permission" // Agent is waiting for tool permission
	KindError      Kind = "error"      // Agent encountered an error
)

type Loop

type Loop struct {
	// contains filtered or unexported fields
}

Loop is the delivery worker. Construct with New, enqueue via Notify, run the worker with Run, stop with Stop.

func New

func New(cfg Config) *Loop

New constructs a Loop. Panics on missing Provider — fast failure beats a later nil deref.

func (*Loop) Notify

func (l *Loop) Notify(n Notification)

Notify enqueues n for asynchronous delivery. Non-blocking: if the worker's input queue is full, n is dropped and logged. Safe from any goroutine.

We drop rather than block because the caller sits on the host's event fan-out path — blocking it would back up event consumption. We'd rather lose a notification than starve the rest of the system.

func (*Loop) Run

func (l *Loop) Run(ctx context.Context)

Run drives the worker until ctx is canceled or Stop is called. Drains the input queue into Provider.Send. Logs (and continues) on Send error — retries and DLQs are the Provider's responsibility.

On Stop the worker drains whatever's already queued before exiting so the last permission/idle/error notifications aren't lost during graceful shutdown. On ctx cancellation we exit immediately — that path is for hard teardown (the parent gave up waiting).

func (*Loop) Stop

func (l *Loop) Stop(ctx context.Context) error

Stop halts Run and calls Provider.Close. Safe to call multiple times concurrently: close(l.stop) and Provider.Close each fire exactly once; subsequent calls return the cached error from the first Close. If ctx fires before Run exits, Stop returns ctx.Err() without invoking Provider.Close — a subsequent Stop with a live ctx will still close.

type Notification

type Notification struct {
	SessionID  string         `json:"session_id"`
	Kind       Kind           `json:"kind"`
	Title      string         `json:"title"`
	Body       string         `json:"body"`
	Data       map[string]any `json:"data,omitempty"`
	OccurredAt time.Time      `json:"occurred_at"`
}

Notification is the canonical, provider-agnostic shape. Providers translate this into their delivery format (Expo Push payload, webhook body, …). SessionID is opaque metadata — the receiver uses it to deep-link, not to authenticate.

type Provider

type Provider interface {
	Send(ctx context.Context, n Notification) error
	Close(ctx context.Context) error
}

Provider delivers Notifications to the outside world. Implementations live under internal/notifier/<name>/. Send is called serially from the Loop's worker goroutine — no internal locking required, but it should respect ctx for cancellation.

Directories

Path Synopsis
Package noop implements notifier.Provider as a logger-only sink.
Package noop implements notifier.Provider as a logger-only sink.
Package webhook implements notifier.Provider as an HTTP POST to a configured URL.
Package webhook implements notifier.Provider as an HTTP POST to a configured URL.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL