Egress actor
User-visible output — egress decides what reaches the forum based on text content, not message type.
The egress actor is the only place that decides what the user sees on the forum. The processor and inference loop do not think about visibility — they persist monologue messages and emit conversation.message.posted events. Egress reads those events and forwards the ones that should reach the user.
Rule
If the LLM output includes text, send that text to the user. Everything else stays internal.
| Monologue message | Forward to forum? |
|---|---|
Agent-authored, has text parts | Yes — text parts only |
Agent-authored, tool_call only | No |
System-authored tool_result | No |
| Ingested user copy | No (already on forum) |
Agent text + tool_call in same message | Yes — text parts only |
This is not tied to type: reply. Monologue traffic from the processor is always type: message. Egress does not filter on message type — it filters on author (agent monologue participant) and content (non-empty text parts).
type: reply remains available for other conversation semantics (threading, explicit reply relations). It is not the signal for user-visible agent output.
Flow
flowchart LR
P[Processor / inference loop] -->|post type: message| M[Monologue]
M -->|conversation.message.posted| E[Egress]
E -->|agent text only| F[Forum]
B[Chat platform bridge] -->|agent text on forum| U[User]
F --> BThe processor posts tool calls, tool results, and agent text to the monologue without deciding what is user-facing. Egress copies agent text to the forum. A chat platform bridge (if configured) watches forum traffic from the agent participant and delivers it to Slack, North chat, etc.
Filter
Egress subscribes to:
agent.forum.joined— record routing for a new stintagent.monologue.compacted— repoint routing after compaction swapconversation.message.posted— all message posts (not just one message type)
On each conversation.message.posted:
- Is
conversationIda tracked monologue for this agent? - Is
authorParticipantIdthe agent's monologue participant? - Does the message body contain non-empty
textparts?
If all yes → post text parts to the forum. Routing uses join state keyed by monologue id, not body.meta.sourceConversationId.
Join state
joins[forumId] = {
forumParticipantId, // agent on the forum
monologueId, // active internal transcript
monologueParticipantId, // agent on the monologue — author filter
};Updated on agent.forum.joined and agent.monologue.compacted.
Contrast with processor
| Processor | Egress | |
|---|---|---|
| Job | LLM inference + tool execution | User-visible copy-out |
| Visibility | Does not decide | Decides from text content |
| Output type | Always type: message on monologue | type: message on forum |
| Triggers on | Monologue events (excludes forum + legacy reply) | All monologue message posts |
Related
- Processor — event-driven inference; does not handle visibility
- Mesh pattern — ingestion → processor → egress pipeline
- Message types — part types and body schema