CI / validate (pull_request) Failing after 1s
Architecture change: DM-First (v2) replaces @mention-in-stream (v1) as primary agent interaction channel. See ADR-001-dm-topology and ADR-002-dm-routing. Key changes: - New DM-first Zulip adapter (adapter_dm.py) deployed on CT 112 - Registers empty narrow to receive ALL events - Demuxes DMs (type: 'private') vs stream events - Replies to DMs back in private thread, stream replies to #agent-hub - Uses blocking long-poll (dont_block=False) to eliminate rate limiting - Rewritten ARCHITECTURE.md, CONTEXT.md, PRD.md for v2 DM-First - New ADRs: ADR-001 (DM Topology), ADR-002 (DM Routing) - Archived old ADRs: 001, 002, 005 (topic-topology, mention-routing, mention-detection) - Updated ADRs: 003 (agent-naming), 004 (per-agent-bots), 006 (all-bots-model) - Updated PI extension (index.ts) with DM-aware patterns - Tanko agent confirmed responding in both DM and @all-bots in #agent-hub
52 lines
2.5 KiB
Markdown
52 lines
2.5 KiB
Markdown
# ADR 2: DM-First Routing
|
|
|
|
**Date**: 2026-06-21 (supersedes 2026-04-28 @mention-based routing)
|
|
|
|
### Decision
|
|
|
|
Agents are triggered primarily by **Zulip Direct Messages (DMs)**. Users send a DM to any agent's bot user (e.g., `@tanko-bot`) to communicate with that agent. Stream-based `@mention` routing is **deprecated** for agent-owner communication but retained for `@all-bots` broadcasts and multi-agent coordination in `#agent-hub`.
|
|
|
|
### Context
|
|
|
|
The original design required users to `@mention` an agent in `#agent-hub` stream topics. This proved unreliable because:
|
|
|
|
1. Zulip 12.0 SDK may not populate `mentioned_users` on stream message events
|
|
2. Every bot subscribed to `#agent-hub` receives every message — wasteful
|
|
3. Topic routing (capturing origin stream + topic for reply) adds parsing complexity
|
|
4. Distinguishing `type: 'stream'` vs `type: 'private'` required extra event filtering
|
|
|
|
DMs eliminate all of these concerns:
|
|
- Only the recipient bot receives the DM — no broadcast noise
|
|
- No @mention parsing needed — the DM itself is the signal
|
|
- No topic/stream capture needed — reply in the same DM thread
|
|
- `message.type: 'private'` is trivially detectable in the event queue
|
|
|
|
### DM Event Flow
|
|
|
|
```
|
|
User sends DM to @tanko-bot
|
|
→ Zulip pushes event to tanko-bot's event queue
|
|
→ Event has: {type: 'message', message: {type: 'private', ...}}
|
|
→ Bot checks: message.type === 'private' (trivial)
|
|
→ Bot reads message.content, processes, responds
|
|
→ Bot sends reply to same DM via /api/v1/messages with
|
|
{type: 'private', to: [user_id], content: 'response'}
|
|
```
|
|
|
|
### @all-bots Exception
|
|
|
|
The stream-based approach is retained **only** for `@all-bots` broadcasts:
|
|
- `@all-bots` in `#agent-hub` → all bots detect the mention and respond
|
|
- This remains necessary for cross-platform broadcasts
|
|
- Detection can use Zulip SDK `mentioned_users` or content-based `@**All Bots**` matching
|
|
|
|
### Consequences
|
|
|
|
- **Positive:** Dramatically simpler routing logic — no @mention parsing, no topic/stream tracking
|
|
- **Positive:** Each bot only processes its own DMs — no wasted event processing
|
|
- **Positive:** Zulip's native DM threading handles all reply threading automatically
|
|
- **Positive:** No dependency on `mentioned_users` field behavior in Zulip 12.0
|
|
- **Negative:** Owners must DM their agent directly instead of using stream topics
|
|
- **Negative:** Cross-agent visibility in stream topics is reduced (mitigated by `@all-bots`)
|
|
- **Neutral:** `@all-bots` in `#agent-hub` still uses the original @mention detection pattern
|