Conversation
Adds a full Zulip channel plugin with: - Event queue polling with exponential backoff - 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 Refs: #5163, openclaw#8365, openclaw#9643
| } | ||
| return null; | ||
| }, |
There was a problem hiding this comment.
Wrong config key
applyAccountConfig writes the base URL to channels.zulip.url, but the rest of the plugin reads account.baseUrl (resolved from the url field in config). This leaves the default account unconfigured at runtime even though setup succeeded.
| } | |
| return null; | |
| }, | |
| ...(baseUrl ? { url: baseUrl } : {}), |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/zulip/src/channel.ts
Line: 281:283
Comment:
**Wrong config key**
`applyAccountConfig` writes the base URL to `channels.zulip.url`, but the rest of the plugin reads `account.baseUrl` (resolved from the `url` field in config). This leaves the default account unconfigured at runtime even though setup succeeded.
```suggestion
...(baseUrl ? { url: baseUrl } : {}),
```
How can I resolve this? If you propose a fix, please make it concise.| ...next, | ||
| channels: { | ||
| ...next.channels, |
There was a problem hiding this comment.
Wrong config key
Same issue as the default-account path above: the account-scoped config writes channels.zulip.accounts[accountId].url but uses the url field name inconsistently elsewhere (resolved as baseUrl). This makes non-default accounts appear configured but fail at runtime when account.baseUrl is read.
| ...next, | |
| channels: { | |
| ...next.channels, | |
| ...(baseUrl ? { url: baseUrl } : {}), |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/zulip/src/channel.ts
Line: 306:308
Comment:
**Wrong config key**
Same issue as the default-account path above: the account-scoped config writes `channels.zulip.accounts[accountId].url` but uses the `url` field name inconsistently elsewhere (resolved as `baseUrl`). This makes non-default accounts appear configured but fail at runtime when `account.baseUrl` is read.
```suggestion
...(baseUrl ? { url: baseUrl } : {}),
```
How can I resolve this? If you propose a fix, please make it concise.| onModelSelected, | ||
| }, | ||
| }); | ||
| } catch (err) { |
There was a problem hiding this comment.
Event ID type mismatch
lastEventId is assigned from events[events.length - 1].id without normalization; Zulip's event IDs are numbers, and passing a number where the client expects a string can break subsequent polling (e.g., if request building/URLSearchParams assumes string). Consider coercing to String(...) at assignment to keep the type stable across re-register + retry paths.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/zulip/src/zulip/monitor.ts
Line: 719:722
Comment:
**Event ID type mismatch**
`lastEventId` is assigned from `events[events.length - 1].id` without normalization; Zulip's event IDs are numbers, and passing a number where the client expects a string can break subsequent polling (e.g., if request building/URLSearchParams assumes string). Consider coercing to `String(...)` at assignment to keep the type stable across re-register + retry paths.
How can I resolve this? If you propose a fix, please make it concise.Addresses Greptile review feedback: ensure lastEventId stays as a number type when assigned from event response data.
FtlC-ian
left a comment
There was a problem hiding this comment.
Thanks for the review! Addressing the feedback:
Config key (lines 283, 308): This is actually correct as-is. The config schema field is url (see config-schema.ts), and accounts.ts reads merged.url to resolve baseUrl. Writing { url: baseUrl } maps the user input to the correct config key.
Event ID type (line 722): Good catch — added Number() coercion in 4e52c40 to keep the type stable.
|
Note for Zulip plugin users: Zulip natively renders markdown tables, but OpenClaw's default table mode converts them to code blocks. To get proper table rendering in Zulip, add this to your config: \\json Without this, tables appear as monospace code instead of formatted tables. Might be worth setting \off\ as the default for the Zulip channel since Zulip supports GFM tables natively. |
|
Good catch! Added |
Adds a full Zulip channel plugin with: - Event queue polling with exponential backoff - 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 Refs: #5163, openclaw#8365, openclaw#9643
Addresses Greptile review feedback: ensure lastEventId stays as a number type when assigned from event response data.
c77c9c5 to
a63e9fe
Compare
Renamed 4 duplicate function names to avoid code-analysis failures: - normalizeEmojiName → normalizeZulipEmojiName (uploads.ts) - readStringArrayParam → parseStringArrayParam (actions.ts) - resolveLocalPath → resolveZulipLocalPath (send.ts) - sleep → delay (monitor.ts, client.ts) Formatted accounts.ts and monitor.ts with oxfmt.
|
Closing this PR because it has more than 20 labels, which usually means the branch is too noisy. Please recreate the PR from a clean branch. |
|
Closing this PR because it has more than 20 labels, which usually means the branch is too noisy. Please recreate the PR from a clean branch. |
Adds a full-featured Zulip channel plugin with: 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: - Implements CONCURRENT message processing with staggered start times - Other PRs (openclaw#9643, openclaw#14182) process messages sequentially, causing reply delays and "message dumps" when multiple messages arrive - This implementation starts processing each message immediately with a 200ms stagger for natural conversation flow - Replies arrive as each finishes instead of all at once Technical Details: - Fire-and-forget message processing with per-message error handling - Maintains event cursor and queue ID correctly during concurrent processing - Tested live and confirmed significant UX improvement Refs: openclaw#5163, openclaw#8365, openclaw#9643, openclaw#12183
Adds a full-featured Zulip channel plugin with: 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: - Implements CONCURRENT message processing with staggered start times - Other PRs (openclaw#9643, openclaw#14182) process messages sequentially, causing reply delays and "message dumps" when multiple messages arrive - This implementation starts processing each message immediately with a 200ms stagger for natural conversation flow - Replies arrive as each finishes instead of all at once Technical Details: - Fire-and-forget message processing with per-message error handling - Maintains event cursor and queue ID correctly during concurrent processing - Tested live and confirmed significant UX improvement Refs: openclaw#5163, openclaw#8365, openclaw#9643, openclaw#12183
Adds a full-featured Zulip channel plugin with: 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: - Implements CONCURRENT message processing with staggered start times - Other PRs (openclaw#9643, openclaw#14182) process messages sequentially, causing reply delays and "message dumps" when multiple messages arrive - This implementation starts processing each message immediately with a 200ms stagger for natural conversation flow - Replies arrive as each finishes instead of all at once Technical Details: - Fire-and-forget message processing with per-message error handling - Maintains event cursor and queue ID correctly during concurrent processing - Tested live and confirmed significant UX improvement Refs: openclaw#5163, openclaw#8365, openclaw#9643, openclaw#12183
Zulip Channel Plugin
Adds a full-featured Zulip channel plugin for OpenClaw.
Features
/user_uploads/paths/api/v1/user_uploads[[zulip_topic: <topic>]]:eyes:andeyesformatsConfig
Context
This was developed to address the Zulip integration request in #5163. We reviewed both existing PRs (#8365 by @rafaelreis-r and #9643 by @jamie-dit) and incorporated the best ideas from each:
checkemoji naming, DELETE reactions via query params, topic directive, emoji normalization, docs structureWhat this PR adds beyond both:
Testing
Refs: #5163, #8365, #9643
Greptile Overview
Greptile Summary
This PR adds a new
@openclaw/zulipchannel plugin underextensions/zulip, including config schema, onboarding hooks, outbound send support (including uploads), and an event-queue long-polling monitor that routes stream/topic messages into per-topic sessions. It also updates the channel docs index and marks Zulip as markdown-capable insrc/utils/message-channel.ts.Key integration points:
extensions/zulip/index.ts+openclaw.plugin.json+ per-extensionpackage.json.extensions/zulip/src/zulip/monitor.ts(event queue registration + long-poll loop, routing/session mapping, optional reactions/typing indicators, media download from/user_uploads/).extensions/zulip/src/zulip/send.ts(target parsing, optional upload to Zulip, markdown table conversion).Primary merge blockers are config write/read mismatches in the channel setup path (URL written to a different key than the rest of the plugin reads), which will prevent successful configuration from actually working at runtime.
Confidence Score: 3/5
(2/5) Greptile learns from your feedback when you react with thumbs up/down!