Tab: Room (Proactive Mode)
The Room turns an instance from a reactive chatbot into a proactive worker. With the room enabled, the assistant runs cycles on its own clock, reacting to events delivered via inbound webhooks rather than waiting for a human to type a message.
What the Room does
Every 30 seconds (TICK_INTERVAL_MS), the Room scheduler wakes up and asks: “For each room with enabled = true, are there any pending events?” If yes, it spawns one supervisor cycle per room. Inside the cycle, the assistant sees:
- The room’s prompt (separate from the instance’s identity prompt).
- The pending events as the user-message side of the conversation.
- Three harness tools:
send_message_to_human,mark_events_completed,compact_room_history.
Each cycle creates a new conversation — the conversation id format is room:<instanceId>:<timestamp>, never persistent. Rolling state lives in the activity log instead (see below).
A human reply on the outbound channel triggers an immediate cycle (skipping the 30 s wait) so that the assistant is responsive when a human steps in mid-flow.
Configuration
The Room tab has three sub-sections: Configuration, Backlog, and Activity Log. Event sources are not a Room sub-section any more — they moved to the new top-level Triggers tab (see Tab: Triggers below).
Configuration
- Enabled — master switch.
- Prompt — the room-specific system prompt. This replaces the instance’s identity prompt during a room cycle, but the other seven sections (Soul, Tooling, Safety, Skills, Memory, User Identity, Datetime) still apply.
- Outbound channel —
slack,telegram,whatsapp, ornone. - Outbound target — channel id or user id where
send_message_to_humanwill deliver.
The 30-second tick is a global scheduler interval (TICK_INTERVAL_MS), not a per-room field — it is not configurable from the Room tab.
Event Sources (moved to Triggers → Webhooks)
Event sources now live under the instance’s Triggers tab → Webhooks subtab. The model has not changed; the configuration UI simply relocated. An event source is a connection between an external system and the Room. Each event source has:
-
Webhook URL — auto-generated, formatted as
/webhooks/<webhookToken>. The token IS the secret — anyone who knows the URL can post events. Treat it as a credential; rotate it from the UI when leaked. -
Payload size cap — 64 KB. Oversize payloads receive a
200 OKwith body{ ok: false, error: "payload too large" }(the receiver is always fire-and-forget). -
Backlog cap — 100 pending events per source. Beyond that, oldest events are dropped.
-
Event Definitions — the heart of routing. Matching is evaluated by an LLM (tier
fast) against natural-language prompts you define per event definition — there are no rules, regex, or JSONPath predicates. Each definition has:- Name and priority (lower priority fires first).
matchingPrompt— a natural-language description of when this definition applies (e.g. “The payload indicates a Stripe invoice has just been paid by a customer”). Evaluated sequentially in priority order; first match wins.interpretationPrompt— a natural-language instruction on how to summarize the matched payload into the user-message side of the room cycle (e.g. “Extract the customer email, amount, and invoice id, and phrase it as a single sentence”).- A target room behavior.
When a webhook fires, the engine sends the payload + each definition’s
matchingPromptto the matcher until one matches, then uses the winning definition’sinterpretationPromptto render the event for the room cycle.
Backlog and Activity Log
- Backlog — pending events waiting to be processed. Status filter:
pending,processing,completed. Each row shows event source, definition matched, payload (collapsed), and timestamps. - Activity log — a chronological log of every room cycle. Old entries are compacted automatically:
- Daily entries older than 7 days collapse into a weekly summary.
- Weekly entries older than 28 days collapse into a monthly summary.
- Monthly entries are kept for 12 months, then dropped.
Compaction keeps the log readable and the database lean.
Storage retention
The room activity log is auto-compacted on a fixed schedule: daily rows for the last 7 days, then weekly rows after 7d, then monthly rows after 4 weeks. The compaction logic lives in packages/engine/src/room/activity-log.store.ts:49-70 and runs as part of the scheduler’s housekeeping pass — no manual maintenance is required.
Worked example: Stripe invoice paid
Suppose you want the assistant to send a Slack DM whenever a customer pays an invoice.
- Create an instance with the right identity for the use case.
- On the Room tab → Configuration, set:
- Enabled: yes
- Prompt: “You watch Stripe invoice events. When an invoice is paid, send a short congratulatory DM to the account owner on Slack.”
- Outbound channel:
slack - Outbound target: the Slack channel id
C012345678
- On the Channels tab, configure Slack and start the channel.
- On the Room tab → Event Sources, click New event source:
- Name:
Stripe - Optional secret: any string; mirror it on Stripe’s webhook config.
- Add an event definition:
- Name:
Invoice paid - Priority: 1
- Description: “A Stripe invoice has been paid. The payload includes
event.type = 'invoice.paid'.”
- Name:
- Name:
- In Stripe, point a webhook at
https://<your-host>/webhooks/<webhookToken>. Pick theinvoice.paidevent type only (or all if you do not mind extra traffic). - Pay a test invoice. Within ~30 seconds you should see a Slack DM from the bot, and a new entry in the activity log.
For the inbound HTTP contract (size limits, signatures, response codes) see Webhooks (Inbound).
Tab: Triggers
Triggers is a separate top-level instance tab — a sibling of Room, not a subtab inside it. It groups three subtabs:
- Webhooks — the event sources from above (full CRUD: create / edit / delete / event definitions).
- Scheduled — recurring or one-shot tasks created by
scheduleTask. Each row: cron expression, next run, status. - Runs — execution history of all triggers (webhook + scheduled + room ticks).
Use the Triggers tab to configure trigger sources and to debug why an event did or did not fire.