Light Dark

Functions

AgentRuntime alias

Alias of ::rt/AgentRuntime

forget-notification

fn (rt: ::ai::agent::runtime/AgentRuntime, recipient-id: Str, id: Str): Bool

Permanently delete a notification by id. Returns true when removed.

hydrate

fn (raw: Map): Notification

Lift a serialized notification map back into a Notification value.

list-notifications

fn (rt: ::ai::agent::runtime/AgentRuntime, recipient-id: Str, opts: Map?): Vec

List notifications for a recipient, oldest first.

opts:

  • unread-only (Bool, default false): drop records with read-at.
  • kind (Str?): if set, only matching kind records.
  • limit (Int?): cap the result length (after filtering).

mark-all-read

fn (rt: ::ai::agent::runtime/AgentRuntime, recipient-id: Str): Int

Mark every unread notification for a recipient as read. Returns the count touched.

mark-read

fn (rt: ::ai::agent::runtime/AgentRuntime, recipient-id: Str, id: Str): Notification?

Mark a single notification (looked up by id) read for the given recipient. Returns the updated Notification, or null when the id is unknown for that recipient.

now-secs

fn (): Int

ns alias

Alias of ::ai::agent::notify/

Notification ledger for scheduled (and ad-hoc) agent output.

Scheduled handlers (daily recaps, stale-task nudges, standups, …) run without a client subscribed to their reply stream, so they need a durable place to land their output. notify is that place: a runtime-scoped store of Notification records the active UI can surface via an /inbox command or a "new since you were here" badge.

Design notes

  • Storage: rt.notify-store (a ::hot::store/Map). One key per notification, value is a serialized Notification map. Keys are ${recipient-id}:${created-at}:${id} so they sort newest-last when listed.
  • Recipient: a free-form string. PersonalAgents typically pass the user id (u1); TeamAgents pass channel:<session-id> so a channel-wide inbox is keyed independently from any one user.
  • Kind: short tag for the emitter (e.g. daily-recap, stale-task-nudge, daily-standup). Lets UIs filter or group.
  • Read state: a single read-at epoch-seconds field. null = unread.

This is intentionally a small primitive. Production agents will likely add external delivery (Slack post, email) by tailing this store from a separate channel — see record-notification for the write path you'd reuse.

record-notification

fn (rt: ::ai::agent::runtime/AgentRuntime, opts: Map): Notification

Append a new notification to rt.notify-store and return the typed record. opts shape:

  • recipient-id (Str, required): user id for personal agents, channel:<session-id> for team agents.
  • kind (Str, required): emitter tag, e.g. daily-recap.
  • body (Str, required): the message body. Markdown is fine.
  • session-id (Str?): the originating session if any.
  • source (Str?): a free-form provenance string (cron job name).
  • meta (Map?): extra structured metadata.

render-inbox

fn (notifications: Vec): Str

Format a list of notifications as a single markdown block suitable for an /inbox reply. Empty input yields a friendly "no notifications" line.

storage-key

fn (recipient-id: Str, created-at: Int, id: Str): Str

Compose the store key for a notification. Sortable by recipient, then time, then id — so ::store/list returns chronologically grouped entries per recipient.

unread-count

fn (rt: ::ai::agent::runtime/AgentRuntime, recipient-id: Str): Int

Number of unread notifications for a recipient.

Types

Notification

Notification type {
    id: Str,
    recipient-id: Str,
    session-id: Str?,
    kind: Str,
    body: Str,
    source: Str?,
    created-at: Int,
    read-at: Int?,
    meta: Map?
}

One notification record. recipient-id is opaque (user id for personal, channel:<sid> for team). kind identifies the cron handler that wrote it; UIs can group/badge by kind.