Forum & Monologue
Two conversation roles — public forum for participants and private monologue per agent join stint.
Forum and monologue are product roles, not separate database tables. Both use the same conversations, participants, and messages schema — they differ in who participates and how agents route between them.
Forum (public chat)
A forum is a conversation with multiple participants — humans and agent personas:
FORUM F
human_alice
human_bob
agent_support (stint p3)
messages visible to all active participantsCreate via Chat SDK:
const room = await chat.createRoom({ title: "support" });
await chat.addMember(room.id, humanActorId);Monologue (agent internal)
When an agent joins a forum, bootstrap creates a separate conversation — the monologue — with typically system + the agent actor:
MONOLOGUE M (agent support's stint)
system
agent_support (stint p4)
messages visible only to monologue participants
(ingestion copies, tool calls, reasoning, replies)Humans in the forum do not see monologue traffic unless egress publishes a type: "reply" back to the forum.
Pairing
FORUM F MONOLOGUE M
│ ▲
│ ingestion (per join) │
└────────────────────────────────────┘
│
processor + egress| Layer | Storage | Scope |
|---|---|---|
| Canonical | participants.metadata.monologueId on forum stint | One monologue per forum join stint |
| Optional registry | Coordinator actor ctx.state | JoinHandle per forum id |
| Runtime routing | Egress ctx.state.joins | forumId → { monologueId, forumParticipantId } |
createAgent does not create a monologue. Each joinConversation creates a fresh monologue and writes monologueId onto the forum participant stint.
Per-join instances
Each joinConversation call spins up:
| Instance | Role |
|---|---|
| ingestion | Copy forum messages into monologue (external shadow actors per author) |
| processor | LLM + tools on monologue traffic |
| egress (one per agent) | Route type: "reply" from any monologue stint to correct forum |
Ingestion without mirror relations
Ingested copies carry routing metadata in body.meta:
{
"meta": {
"sourceConversationId": "forum-id",
"sourceMessageId": "original-message-id",
"sourceActorId": "forum-author-actor-id"
}
}No message_relations mirror table — egress uses sourceConversationId to pick the forum.
Compaction swap
When compaction changes the transcript, the forum participant's metadata.monologueId is updated to point at a new monologue. Ingestion resolves the active monologue from participant metadata on each event.
Event agent.monologue.compacted notifies egress to update its joins map.
1:1 is just a small forum
A direct message between system and agent is a forum with two participants — same bootstrap path as multi-party support rooms.