#15051: feat: Zulip channel plugin with concurrent message processing
commands
size: XL
Cluster:
Mattermost and Zulip Enhancements
## Summary
Adds a full-featured Zulip channel plugin with **concurrent message processing** that significantly improves conversation flow compared to existing Zulip PRs.
## Core Features
- ✅ Event queue polling with exponential backoff and auto-recovery
- ✅ Authenticated upload downloads from `/user_uploads/`
- ✅ Outbound file uploads via `/api/v1/user_uploads`
- ✅ Reaction indicators (eyes → check_mark/warning)
- ✅ Topic directive `[[zulip_topic: <topic>]]`
- ✅ HTTP retry with backoff (429/502/503/504)
- ✅ Full actions API (stream CRUD, user management, reactions)
- ✅ Channel docs and unit tests
## Key Improvement Over Existing PRs
### The Problem
Existing Zulip PRs (#9643, #14182) process messages **sequentially**, causing:
- Long delays when multiple messages arrive during the polling window
- "Message dumps" where all replies arrive at once after minutes of silence
- Poor conversation UX
### The Solution
This PR implements **concurrent message processing with staggered start times**:
```typescript
// Old way (sequential - causes dumps):
for (const event of events) {
if (event.type === "message" && event.message) {
await processMessage(event.message); // Blocks until complete
}
}
// New way (concurrent - natural flow):
for (const event of events) {
if (event.type === "message" && event.message) {
processMessage(event.message).catch(handleError); // Fire-and-forget
await delay(200); // Small stagger for natural pacing
}
}
```
### Verified Impact
- ✅ Tested live on production Zulip instance
- ✅ Messages start processing immediately (no blocking)
- ✅ Replies arrive independently as each finishes
- ✅ Natural conversation flow instead of reply dumps
## Technical Details
- Fire-and-forget message processing with per-message error handling
- Maintains event cursor and queue ID correctly during concurrent processing
- 200ms stagger between starting each message for natural pacing
- Error handling doesn't block subsequent message processing
## References
- Discussion: #5163
- Related PRs: #8365, #9643, #12183 (closed due to branch noise)
- This is a clean-branch recreation of #12183 with the concurrent processing improvement
## Testing
Deployed and tested live on Zulip - confirmed significant UX improvement when handling multiple rapid messages.
---
cc @openclaw/maintainers - This addresses the conversation flow issues present in other Zulip PRs while maintaining all functionality.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds a new `extensions/zulip` plugin implementing a Zulip channel provider: configuration schema + onboarding, long-polling event queue monitoring, message dispatch (including concurrent “fire-and-forget” processing with staggered starts), upload download support for `/user_uploads/`, outbound file uploads via `/api/v1/user_uploads`, and a broad actions surface (streams, users, reactions, message ops). It integrates with the existing OpenClaw channel runtime APIs (routing/session keys, typing callbacks, reply dispatcher, pairing/allowlist policies) similarly to other channel monitors in the repo.
Key merge blockers are around operational correctness/maintainability: a silent catch during inbound attachment downloads makes missing media hard to diagnose, and outbound remote-media upload code leaks temp directories created via `mkdtemp()`.
<h3>Confidence Score: 4/5</h3>
- Mostly safe to merge once the two concrete operational issues are fixed.
- The plugin appears structurally consistent with other channel integrations and includes tests, but there are two definite issues: inbound upload download errors are silently swallowed (debuggability) and outbound remote-media upload leaves behind mkdtemp directories (resource leak). Fixing these should reduce operational pain without changing overall design.
- extensions/zulip/src/zulip/monitor.ts, extensions/zulip/src/zulip/send.ts
<sub>Last reviewed commit: b31afda</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#22308: feat(zulip): add Zulip channel plugin
by emadomedher · 2026-02-21
87.2%
#14182: zulip: fix event queue registration for multiple monitored streams
by simpliq-marvin · 2026-02-11
81.9%
#9594: feat: add SimpleX messaging channel
by dangoldbj · 2026-02-05
78.9%
#22260: feat(extensions/deltachat): add Delta.Chat channel extension
by alanz · 2026-02-20
77.7%
#13881: fix: Address Greptile feedback - test isolation and channel resolution
by trevorgordon981 · 2026-02-11
76.9%
#11608: feat(slack): native streaming, Block Kit blocks, tool-aware status
by joshdavisind · 2026-02-08
76.6%
#17361: feat(channels): add Tuitui (推推) channel support
by haomehaode · 2026-02-15
76.5%
#4878: fix: string/type handling and API fixes (#4537, #4380, #4373, #4547...
by lailoo · 2026-01-30
76.4%
#7353: fix: prevent silent message drops after config.patch restart
by 18-RAJAT · 2026-02-02
76.2%
#15879: Support for forwarded messages and file_shared messages in slack
by olyashok · 2026-02-14
76.2%