#23709: fix(synology-chat): resolve Chat API user_id for reply delivery
size: M
Cluster:
Slack Thread Management Fixes
## Summary
Synology Chat outgoing webhooks use a **per-integration sequential user_id** (e.g. `1`) that differs from the **global Chat API user_id** (e.g. `4`) required by `method=chatbot`. This caused reply messages to fail silently when the IDs diverged.
- Add `fetchChatUsers()` and `resolveChatUserId()` to resolve the correct Chat API user_id via the `user_list` endpoint (nickname-first matching, cached 5min)
- Use resolved user_id for all `sendMessage()` calls in webhook handler and channel dispatcher
- Add `Provider` field to MsgContext so the agent runner correctly identifies the message channel (was `"unknown"`, now `"synology-chat"`)
- Log warnings when `user_list` API fails or when falling back to unresolved webhook user_id
## Background
The Synology Chat API has two separate user_id spaces:
| Context | user_id | Example |
|---------|---------|---------|
| Outgoing webhook (`user_id` field) | Per-integration sequential | `1` |
| Chat API (`method=chatbot`, `user_ids[]`) | Global internal | `4` |
The outgoing webhook's `username` field corresponds to the Chat user's `nickname`. Resolution is done by calling `method=user_list` with the bot's token and matching by nickname (primary) then username (fallback), case-insensitive.
## Test plan
- [x] 68/68 unit tests pass (5 new tests for user_id resolution)
- [x] 0 TypeScript errors, 0 lint warnings
- [x] Tested in production: DM and group channel delivery confirmed working
- [x] Verified `messageChannel=synology-chat` in agent runner logs (was `unknown`)
- [x] Verified fallback behavior when user_list API is unavailable
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Added user_id resolution to fix reply delivery failures in Synology Chat integration. The PR correctly addresses the mismatch between webhook user_id (per-integration sequential) and Chat API user_id (global internal) by fetching the user list and matching by nickname/username. The implementation includes proper caching (5min TTL), fallback behavior, and comprehensive test coverage.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The changes are well-tested (68/68 tests passing, 5 new tests), properly scoped to the Synology Chat extension, include appropriate error handling and fallback mechanisms, and follow the existing codebase patterns. The user_id resolution logic is sound with proper caching to minimize API overhead.
- No files require special attention
<sub>Last reviewed commit: ae7aeea</sub>
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#23464: feat(synology-chat): add group/channel support
by druide67 · 2026-02-22
80.8%
#12619: Add Synology Chat channel integration
by MikeWang0316tw · 2026-02-09
80.6%
#14966: fix(webchat): preserve user message visibility after chat.send
by BenediktSchackenberg · 2026-02-12
76.1%
#3721: fix(ui): webchat not displaying chat responses
by maxmaxrouge-rgb · 2026-01-29
74.9%
#23074: fix(synology-chat): prevent restart loop in startAccount
by druide67 · 2026-02-22
74.6%
#23320: fix(slack): respect replyToMode when incomingThreadTs is auto-created
by dorukardahan · 2026-02-22
74.6%
#16548: fix(telegram): enhance chat_id validation and diagnostics
by tanujbhaud · 2026-02-14
74.5%
#13104: fix: persist user command message in chat transcript
by mcaxtr · 2026-02-10
74.0%
#21463: fix(discord): prevent WebSocket death spiral + fix numeric channel ID…
by akropp · 2026-02-20
73.9%
#5312: fix(slack): skip users.list API call when all user entries are IDs
by gunpyo-park-musinsa · 2026-01-31
73.8%