← Back to PRs

#15051: feat: Zulip channel plugin with concurrent message processing

by FtlC-ian open 2026-02-12 22:42 View on GitHub →
commands size: XL
## 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