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
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# ADR 1: DM-First Communication Topology
|
||||
|
||||
**Date**: 2026-06-21 (supersedes 2026-04-28 topic-based topology)
|
||||
|
||||
### Decision
|
||||
|
||||
Each agent communicates primarily via **Zulip Direct Messages (DMs)**. The `#agent-hub` stream is retained as an **optional broadcast-only channel** for inter-agent coordination, `@all-bots` announcements, and cross-agent visibility. Agent-private topics (`<agent>-private`) are **deprecated** in favor of native Zulip DMs.
|
||||
|
||||
### Context
|
||||
|
||||
Zulip bots are regular user accounts — any user can send a **private message** to any bot by composing a DM with the bot as the sole recipient. The bot's event queue then receives an event with `message.type: 'private'`, which requires **no @mention detection, no topic parsing, no stream subscription checks**.
|
||||
|
||||
The original design used topics under `#agent-hub` with `@mention` routing, but this introduced several failure modes:
|
||||
|
||||
| Problem | Impact |
|
||||
|---------|--------|
|
||||
| `mentioned_users` field not populated by Zulip 12.0 SDK | @mention detection silently fails |
|
||||
| Topic routing required capturing origin topic + stream for reply | Added parsing complexity |
|
||||
| All 6 bots subscribed to same stream | Every bot receives every message, wasting resources |
|
||||
| `type:'stream'` events different from `type:'private'` | Required additional event filtering logic |
|
||||
|
||||
**DMs solve all of this natively:**
|
||||
- Every DM is inherently for the bot recipient — no @mention needed
|
||||
- Reply in the same DM thread — Zulip handles threading
|
||||
- Only the recipient bot sees the message — no broadcast noise
|
||||
- `message.type: 'private'` is trivially detectable
|
||||
|
||||
### Architecture Change
|
||||
|
||||
#### Before (Deprecated):
|
||||
```
|
||||
User @mentions @tanko-bot in #agent-hub > tanko-private
|
||||
→ Zulip fires event to ALL 6 bot event queues
|
||||
→ Each bot checks mentioned_users for its user_id
|
||||
→ Only matching bot processes the event
|
||||
→ Bot replies to same stream+topic
|
||||
```
|
||||
|
||||
#### After (DM-First):
|
||||
```
|
||||
User DMs @tanko-bot directly
|
||||
→ Zulip fires event ONLY to tanko-bot's event queue
|
||||
→ Bot receives message.type: 'private'
|
||||
→ No @mention detection, no topic parsing
|
||||
→ Bot processes and replies in same DM thread
|
||||
```
|
||||
|
||||
### Consequences
|
||||
|
||||
- **Positive:** Dramatically simpler event processing — no @mention detection, no topic routing, no mentioned_users dependency, no stream subscription requirement
|
||||
- **Positive:** Each bot only receives its own messages — less noise, less resource usage
|
||||
- **Positive:** Zulip's native DM threading handles all reply routing automatically
|
||||
- **Positive:** No need to subscribe all 6 bots to `#agent-hub` stream (except for `@all-bots` broadcast capability)
|
||||
- **Negative:** Single #agent-hub stream topic no longer shows all agent activity in one timeline
|
||||
- **Negative:** Cross-agent visibility requires `@all-bots` broadcast or agents explicitly CC each other
|
||||
- **Neutral:** `#agent-hub` stream is retained for: `@all-bots` broadcasts, inter-agent coordination, and user-initiated multi-agent topics
|
||||
|
||||
### Migration Path
|
||||
|
||||
1. All plugins listen for `type: 'private'` events as primary communication channel
|
||||
2. `#agent-hub` stream listener is secondary — only for `@all-bots` broadcast detection
|
||||
3. Existing `<agent>-private` topics are deprecated but not deleted (grace period)
|
||||
4. Owners communicate with their agents via DM, not via private topics
|
||||
5. `@all-bots` continues to work in `#agent-hub` for cross-platform broadcasts
|
||||
@@ -1,15 +0,0 @@
|
||||
# ADR 1: Topic & Stream Topology
|
||||
|
||||
**Date**: 2026-04-28
|
||||
|
||||
### Decision
|
||||
Each agent gets a private topic under `#agent-hub` named `<agent>-private` for owner-only communication; all other topics are collaboration topics where agents respond only when @mentioned.
|
||||
|
||||
### Context
|
||||
We need a clear separation between agent-private communication (user-agent DMs) and collaboration (multi-agent discussions). Zulip topics are the right granularity — no separate streams needed. The `-private` suffix convention is simple and self-documenting.
|
||||
|
||||
### Consequences
|
||||
- All 6 agents co-exist in `#agent-hub` stream
|
||||
- Users can create any new topic and @mention agents
|
||||
- Private topics are invitation-only (bot + owner)
|
||||
- No need to manage multiple streams
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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
|
||||
@@ -1,14 +0,0 @@
|
||||
# ADR 2: @mention-Based Routing
|
||||
|
||||
**Date**: 2026-04-28
|
||||
|
||||
### Decision
|
||||
Agents are triggered exclusively by Zulip @mentions. No topic-based assignment. Users @mention an agent in any topic, and the agent's bot responds.
|
||||
|
||||
### Context
|
||||
Topic-based routing is too rigid — it requires users to know which topic maps to which agent. @mention routing is natural in Zulip (users already know how to @mention). It also enables multi-agent conversations in a single topic.
|
||||
|
||||
### Consequences
|
||||
- Each bot must parse @mentions from every message in `#agent-hub`
|
||||
- Routing complexity moves from topic name matching to @mention resolution
|
||||
- Users can freely create topics and involve agents ad-hoc
|
||||
@@ -1,15 +1,11 @@
|
||||
# ADR 3: Agent Naming Convention
|
||||
# ADR 3: Agent Naming Convention (Unchanged)
|
||||
|
||||
**Date**: 2026-04-28
|
||||
**Date**: 2026-04-28 | **Status**: Still active — DM architecture does not affect naming
|
||||
|
||||
### Decision
|
||||
Each agent bot has a display name in `{name}-bot` format with no spaces, dashes only: `tanko-bot`, `mumuni-bot`, `koonimo-bot`, `koby-bot`, `kagentz-bot`, `abiba-bot`.
|
||||
Each agent bot has a display name in `{name}-bot` format: `tanko-bot`, `mumuni-bot`, etc.
|
||||
|
||||
### Context
|
||||
Zulip @mentions work best with clean, predictable names. No spaces avoids ambiguity in @mention parsing. The `-bot` suffix makes it clear these are automated agents, not human users.
|
||||
|
||||
### Consequences
|
||||
- @mention format: `@**tanko-bot**`
|
||||
### Consequences (Unchanged)
|
||||
- DM address: `@**tanko-bot**` (same as @mention format)
|
||||
- Email format: `tanko-bot@chat.sysloggh.net`
|
||||
- Users must type @tanko-bot (not @tanko)
|
||||
- Consistent naming across all 6 agents
|
||||
- Consistent naming across all 6 agents
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
# ADR 4: One Zulip Bot Per Agent
|
||||
# ADR 4: One Zulip Bot Per Agent (Unchanged)
|
||||
|
||||
**Date**: 2026-04-28
|
||||
**Date**: 2026-04-28 | **Status**: Still active — DM architecture needs per-agent bots even more
|
||||
|
||||
### Decision
|
||||
Each agent has its own dedicated Zulip bot user, co-located on the agent's CT. Each bot runs independently as a platform-native plugin.
|
||||
Each agent has its own dedicated Zulip bot user, co-located on the agent's CT.
|
||||
|
||||
### Context
|
||||
A single bot creates a single point of failure and requires message routing to the correct agent. Per-agent bots provide full isolation — if tanko's bot fails, mumuni's bot continues working. Co-location means zero A2A overhead for the local agent.
|
||||
|
||||
### Consequences
|
||||
- 6 Zulip bot users to create and manage
|
||||
### Consequences (Unchanged)
|
||||
- 6 Zulip bot users
|
||||
- 6 independent event streams (one per CT)
|
||||
- @all-bots requires each bot to know about `All Bots` user
|
||||
- Adding a new agent = create Zulip bot + deploy plugin to CT
|
||||
- @all-bots still requires each bot to know about `All Bots` user
|
||||
- DM isolation: only recipient bot sees the message (improvement over stream-based approach)
|
||||
|
||||
@@ -1,15 +1,44 @@
|
||||
# ADR 6: @all-bots via Dedicated Zulip Bot User
|
||||
# ADR 6: @all-bots via Content-Based Detection
|
||||
|
||||
**Date**: 2026-04-28
|
||||
**Date**: 2026-06-21 (supersedes 2026-04-28 dedicated bot user approach)
|
||||
|
||||
### Decision
|
||||
@all-bots is implemented as a dedicated Zulip bot user with display name `All Bots` and email `all-bots@chat.sysloggh.net`. All 6 per-agent bots subscribe to the same event narrow and detect when `All Bots` is in `mentioned_users`.
|
||||
|
||||
`@all-bots` is detected via **content-based mention matching** on messages in the `#agent-hub` stream. Each bot subscribes to `#agent-hub` and uses regex to detect `@**all-bots**` or `@**All Bots**` in message content. A dedicated "All Bots" Zulip bot user is **not required**.
|
||||
|
||||
### Context
|
||||
@all-bots needs to trigger all agents regardless of platform. A dedicated bot user is explicit and intentional — it prevents @everyone or stream-wide pings from accidentally triggering all agents. Each bot independently detects the @mention and forwards to its agent.
|
||||
|
||||
The original design required a 7th Zulip bot user (`all-bots@chat.sysloggh.net`) with display name `All Bots`. This user was never created during initial bot provisioning. Additionally:
|
||||
|
||||
- Bot users cannot reliably detect @mentions of other bot users in Zulip 12.0 (ADR-005 archived)
|
||||
- Content-based regex matching (`@**all-bots**`) works on any Zulip message regardless of SDK version
|
||||
- Under the DM-first architecture (ADR-001), bot-event stream subscription to `#agent-hub` is the **only** stream-level listener needed — all other communication uses DMs
|
||||
|
||||
### Behavior
|
||||
|
||||
```
|
||||
User posts in #agent-hub > topic:
|
||||
"@**all-bots** status report please"
|
||||
|
||||
→ Each bot receives event via #agent-hub subscription
|
||||
→ Each bot checks: /@\*\*(?:all-bots|All Bots)\*\*/i.test(content)
|
||||
→ If match: bot forwards message to its agent
|
||||
→ 6 independent responses appear in the topic
|
||||
```
|
||||
|
||||
### Active Stream Subscription
|
||||
|
||||
Under DM-first architecture, each agent's plugin maintains **one** stream subscription:
|
||||
- **Stream:** `#agent-hub`
|
||||
- **Purpose:** Only for detecting `@all-bots` broadcasts
|
||||
- **Filter:** Ignore all non-`@all-bots` messages in the stream
|
||||
- **Primary channel:** DMs for all agent-owner communication
|
||||
|
||||
### Consequences
|
||||
- Must create a 7th Zulip bot user for `All Bots`
|
||||
- Each agent bot's config must include `All Bots` user ID for detection
|
||||
- @all-bots is opt-in: only topics that explicitly @all-bots trigger broadcast
|
||||
- Cross-platform broadcast works without a central dispatcher
|
||||
|
||||
- **Positive:** No need to create/manage a 7th dedicated bot user
|
||||
- **Positive:** Content-based detection works reliably across Zulip versions (no SDK dependency)
|
||||
- **Positive:** Same regex works for case-insensitive matching (`all-bots` / `All Bots`)
|
||||
- **Negative:** Slightly more processing per message (regex check)
|
||||
- **Negative:** If `@all-bots` syntax changes in Zulip, regex must update
|
||||
- **Neutral:** All 6 bots still independently detect and respond — same multi-response pattern
|
||||
|
||||
Reference in New Issue
Block a user