mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-20 16:15:15 +00:00
fix(feishu): Remove incorrect oc_ prefix assumption in resolveFeishuSession (#10407)
* fix(feishu): remove incorrect oc_ prefix assumption in resolveFeishuSession - Feishu oc_ is a generic chat_id that can represent both groups and DMs - Must use chat_mode field from API to distinguish, not ID prefix - Only ou_/on_ prefixes reliably indicate user IDs (always DM) - Fixes session misrouting for DMs with oc_ chat IDs This bug caused DM messages with oc_ chat_ids to be incorrectly created as group sessions, breaking session isolation and routing. * docs: update Feishu ID format comment to reflect oc_ ambiguity The previous comment incorrectly stated oc_ is always a group chat. This update clarifies that oc_ chat_ids can be either groups or DMs, and explicit prefixes (dm:/group:) should be used to distinguish. * feishu: add regression coverage for oc session routing --------- Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Feishu/Reply media attachments: send Feishu reply `mediaUrl`/`mediaUrls` payloads as attachments alongside text/streamed replies in the reply dispatcher, including legacy fallback when `mediaUrls` is empty. (#28959)
|
||||
- Feishu/Reaction notifications: add `channels.feishu.reactionNotifications` (`off | own | all`, default `own`) so operators can disable reaction ingress or allow all verified reaction events (not only bot-authored message reactions). (#28529)
|
||||
- Feishu/Outbound session routing: stop assuming bare `oc_` identifiers are always group chats, honor explicit `dm:`/`group:` prefixes for `oc_` chat IDs, and default ambiguous bare `oc_` targets to direct routing to avoid DM session misclassification. (#10407) Thanks @Bermudarat.
|
||||
- Feishu/Group session routing: add configurable group session scopes (`group`, `group_sender`, `group_topic`, `group_topic_sender`) with legacy `topicSessionMode=enabled` compatibility so Feishu group conversations can isolate sessions by sender/topic as configured. (#17798)
|
||||
- Feishu/Reply-in-thread routing: add `replyInThread` config (`disabled|enabled`) for group replies, propagate `reply_in_thread` across text/card/media/streaming sends, and align topic-scoped session routing so newly created reply threads stay on the same session root. (#27325)
|
||||
- Feishu/Typing backoff: re-throw Feishu typing add/remove rate-limit and quota errors (`429`, `99991400`, `99991403`) and detect SDK non-throwing backoff responses so the typing keepalive circuit breaker can stop retries instead of looping indefinitely. (#28494)
|
||||
|
||||
@@ -786,7 +786,7 @@ function resolveTlonSession(
|
||||
|
||||
/**
|
||||
* Feishu ID formats:
|
||||
* - oc_xxx: chat_id (group chat)
|
||||
* - oc_xxx: chat_id (can be group or DM, use chat_mode to distinguish or explicit dm:/group: prefix)
|
||||
* - ou_xxx: user open_id (DM)
|
||||
* - on_xxx: user union_id (DM)
|
||||
* - cli_xxx: app_id (not a valid send target)
|
||||
@@ -802,20 +802,27 @@ function resolveFeishuSession(
|
||||
|
||||
const lower = trimmed.toLowerCase();
|
||||
let isGroup = false;
|
||||
let typeExplicit = false;
|
||||
|
||||
if (lower.startsWith("group:") || lower.startsWith("chat:")) {
|
||||
trimmed = trimmed.replace(/^(group|chat):/i, "").trim();
|
||||
isGroup = true;
|
||||
typeExplicit = true;
|
||||
} else if (lower.startsWith("user:") || lower.startsWith("dm:")) {
|
||||
trimmed = trimmed.replace(/^(user|dm):/i, "").trim();
|
||||
isGroup = false;
|
||||
typeExplicit = true;
|
||||
}
|
||||
|
||||
const idLower = trimmed.toLowerCase();
|
||||
if (idLower.startsWith("oc_")) {
|
||||
isGroup = true;
|
||||
} else if (idLower.startsWith("ou_") || idLower.startsWith("on_")) {
|
||||
isGroup = false;
|
||||
// Only infer type from ID prefix if not explicitly specified
|
||||
// Note: oc_ is a chat_id and can be either group or DM (must check chat_mode from API)
|
||||
// Only ou_/on_ can be reliably identified as user IDs (always DM)
|
||||
if (!typeExplicit) {
|
||||
if (idLower.startsWith("ou_") || idLower.startsWith("on_")) {
|
||||
isGroup = false;
|
||||
}
|
||||
// oc_ requires explicit prefix: dm:oc_xxx or group:oc_xxx
|
||||
}
|
||||
|
||||
const peer: RoutePeer = {
|
||||
|
||||
@@ -973,6 +973,42 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
from: "slack:group:G123",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Feishu explicit group prefix keeps group routing",
|
||||
cfg: baseConfig,
|
||||
channel: "feishu",
|
||||
target: "group:oc_group_chat",
|
||||
expected: {
|
||||
sessionKey: "agent:main:feishu:group:oc_group_chat",
|
||||
from: "feishu:group:oc_group_chat",
|
||||
to: "oc_group_chat",
|
||||
chatType: "group",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Feishu explicit dm prefix keeps direct routing",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "feishu",
|
||||
target: "dm:oc_dm_chat",
|
||||
expected: {
|
||||
sessionKey: "agent:main:feishu:direct:oc_dm_chat",
|
||||
from: "feishu:oc_dm_chat",
|
||||
to: "oc_dm_chat",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Feishu bare oc_ target defaults to direct routing",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "feishu",
|
||||
target: "oc_ambiguous_chat",
|
||||
expected: {
|
||||
sessionKey: "agent:main:feishu:direct:oc_ambiguous_chat",
|
||||
from: "feishu:oc_ambiguous_chat",
|
||||
to: "oc_ambiguous_chat",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of cases) {
|
||||
|
||||
Reference in New Issue
Block a user