Documents lessons from building pi Zulip extension and Hermes Zulip plugin: 1. Queue registration content-type 2. Missing bot_user_id for @mentions 3. Zero stream subscriptions 4. Stale errors never cleared 5. Stuck detection too aggressive 6. Env var name mismatch 7. Poll interval too aggressive 8. A2A port conflict Also: fixed Hermes adapter to clear stale errors on successful poll
3.7 KiB
3.7 KiB
kind, name, description
| kind | name | description |
|---|---|---|
| pattern | zulip-adapter-lessons | Lessons learned from building and debugging the pi Zulip extension and Hermes Zulip plugin. Documents failure modes, fixes, and patterns that apply across all Zulip adapters. |
Known Failure Modes & Fixes
1. Queue Registration Content-Type
- Symptom: Event queue registered but delivers no stream events
- Root cause:
multipart/form-data(fromisomorphic-form-data/form-datanpm pkgs) vsapplication/x-www-form-urlencoded - Fix: Always use URLSearchParams / form-urlencoded for
/api/v1/register - Applies to: pi extension (fixed), Hermes adapter (httpx sends form-urlencoded by default ✅)
2. Missing bot_user_id for @mention Detection
- Symptom: Bot receives stream messages but doesn't respond to @mentions
- Root cause:
/api/v1/registerdoesn't returnuser_id;mentioned_userscheck fails when bot ID is null - Fix: Call
GET /api/v1/users/meafter registration to getuser_id - Applies to: pi extension (fixed), Hermes adapter (fixed via
_resolve_bot_user_id()✅)
3. Zero Stream Subscriptions
- Symptom: Bot can send to streams but never receives stream events
- Root cause: Bot user created with 0 stream subscriptions — only DMs arrive
- Fix:
POST /api/v1/users/me/subscriptionswith required stream names - Applies to: pi extension (fixed), Hermes adapter (⚠️ needs check)
4. Stale Errors Never Cleared
- Symptom: Health monitor shows persistent error long after recovery
- Root cause:
last_errorset on failure but never cleared on successful poll - Fix: Clear
lastErroron every successful poll (not just on reconnect) - Applies to: pi extension (fixed), Hermes adapter (⚠️ needs check)
5. Stuck Detection Too Aggressive
- Symptom: Monitor restarts bot during quiet periods (nights/weekends)
- Root cause: 30-min stuck threshold doesn't account for low traffic
- Fix: Raise threshold to 4 hours — or remove stuck detection entirely
- Applies to: pi extension (fixed to 4h), Hermes gateway (uses own idle detection)
6. Env Var Name Mismatch (ZULIP_URL vs ZULIP_SITE)
- Symptom: Plugin not loading because check_fn returns False
- Root cause: Some deploy configs use
ZULIP_URL, adapter code expectsZULIP_SITE - Fix: Support both names in check_fn, validate_config, and env_enablement_fn
- Applies to: Hermes adapter (fixed ✅)
7. Poll Interval Too Aggressive
- Symptom: Queue expires faster than expected, reconnection cycling
- Root cause: 3s poll interval with
dont_block=truecreates many requests - Fix: Use long-poll (no
dont_block) with 30s+ server timeout - Applies to: pi extension (uses long-poll ✅), Hermes adapter (uses long-poll ✅)
8. A2A Server Address Already In Use
- Symptom: A2A server fails to start with "[Errno 98] address already in use"
- Root cause: Previous process holds port after container restart
- Fix: Kill old process before starting, or use docker restart to clear state
- Applies to: kagentz Agent Zero deployment
Deployment Checklist
When deploying a new Zulip adapter, verify:
- Queue registered with form-urlencoded content type
- Bot user_id fetched from
/api/v1/users/me - Subscribed to all expected streams (check with
/api/v1/users/me/subscriptions) last_errorcleared on successful poll- Env vars support both
ZULIP_URLandZULIP_SITE - Stream @mentions detected via
mentioned_usersarray @all-botsdetected via configurable user_id- Poll uses long-poll (not
dont_block=truepolling) - Stuck/idle detection accounts for quiet periods