mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-21 07:44:59 +00:00
test(feishu): assert typing cleanup on dispatch paths (#27640)
This commit is contained in:
@@ -44,6 +44,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Feishu/Doc tools: route `feishu_doc` and `feishu_app_scopes` through the active agent account context (with explicit `accountId` override support) so multi-account agents no longer default to the first configured app, with regression coverage for context routing and explicit override behavior. (#27338) thanks @AaronL725.
|
||||
- Feishu/Inbound message metadata: include inbound `message_id` in `BodyForAgent` on a dedicated metadata line so agents can reliably correlate and act on media/message operations that require message IDs, with regression coverage. (#27253) thanks @xss925175263.
|
||||
- Feishu/Permission error dispatch: merge sender-name permission notices into the main inbound dispatch so one user message produces one agent turn/reply (instead of a duplicate permission-notice turn), with regression coverage. (#27381) thanks @byungsker.
|
||||
- Feishu/Typing cleanup: always call dispatcher completion/idle cleanup in `finally` after Feishu dispatch, so typing indicator keepalive loops stop on both success and error paths; added regression coverage for cleanup on both paths. (#27640) thanks @kevinWangSheng.
|
||||
- Telegram/Inline buttons: allow callback-query button handling in groups (including `/models` follow-up buttons) when group policy authorizes the sender, by removing the redundant callback allowlist gate that blocked open-policy groups. (#27343) Thanks @GodsBoy.
|
||||
- Telegram/Streaming preview: when finalizing without an existing preview message, prime pending preview text with final answer before stop-flush so users do not briefly see stale 1-2 word fragments (for example `no` before `no problem`). (#27449) Thanks @emanuelst for the original fix direction in #19673.
|
||||
- Telegram/sendChatAction 401 handling: add bounded exponential backoff + temporary local typing suppression after repeated unauthorized failures to stop unbounded `sendChatAction` retry loops that can trigger Telegram abuse enforcement and bot deletion. (#27415) Thanks @widingmarcus-cyber.
|
||||
|
||||
@@ -11,11 +11,14 @@ const {
|
||||
mockDownloadMessageResourceFeishu,
|
||||
mockCreateFeishuClient,
|
||||
} = vi.hoisted(() => ({
|
||||
mockCreateFeishuReplyDispatcher: vi.fn(() => ({
|
||||
dispatcher: vi.fn(),
|
||||
replyOptions: {},
|
||||
markDispatchIdle: vi.fn(),
|
||||
})),
|
||||
mockCreateFeishuReplyDispatcher: vi.fn(() => {
|
||||
const markComplete = vi.fn();
|
||||
return {
|
||||
dispatcher: { markComplete },
|
||||
replyOptions: {},
|
||||
markDispatchIdle: vi.fn(),
|
||||
};
|
||||
}),
|
||||
mockSendMessageFeishu: vi.fn().mockResolvedValue({ messageId: "pairing-msg", chatId: "oc-dm" }),
|
||||
mockGetMessageFeishu: vi.fn().mockResolvedValue(null),
|
||||
mockDownloadMessageResourceFeishu: vi.fn().mockResolvedValue({
|
||||
@@ -517,4 +520,77 @@ describe("handleFeishuMessage command authorization", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("always marks dispatcher complete and dispatch idle after successful dispatch", async () => {
|
||||
mockShouldComputeCommandAuthorized.mockReturnValue(false);
|
||||
const cfg: ClawdbotConfig = {
|
||||
channels: {
|
||||
feishu: {
|
||||
dmPolicy: "open",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
const event: FeishuMessageEvent = {
|
||||
sender: {
|
||||
sender_id: {
|
||||
open_id: "ou-success",
|
||||
},
|
||||
},
|
||||
message: {
|
||||
message_id: "msg-success-cleanup",
|
||||
chat_id: "oc-dm",
|
||||
chat_type: "p2p",
|
||||
message_type: "text",
|
||||
content: JSON.stringify({ text: "hello" }),
|
||||
},
|
||||
};
|
||||
|
||||
await dispatchMessage({ cfg, event });
|
||||
|
||||
const dispatcherResult = mockCreateFeishuReplyDispatcher.mock.results.at(-1)?.value as
|
||||
| {
|
||||
dispatcher: { markComplete: ReturnType<typeof vi.fn> };
|
||||
markDispatchIdle: ReturnType<typeof vi.fn>;
|
||||
}
|
||||
| undefined;
|
||||
expect(dispatcherResult?.dispatcher.markComplete).toHaveBeenCalledTimes(1);
|
||||
expect(dispatcherResult?.markDispatchIdle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("marks dispatcher complete and dispatch idle when dispatch throws", async () => {
|
||||
mockShouldComputeCommandAuthorized.mockReturnValue(false);
|
||||
mockDispatchReplyFromConfig.mockRejectedValueOnce(new Error("dispatch boom"));
|
||||
const cfg: ClawdbotConfig = {
|
||||
channels: {
|
||||
feishu: {
|
||||
dmPolicy: "open",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
const event: FeishuMessageEvent = {
|
||||
sender: {
|
||||
sender_id: {
|
||||
open_id: "ou-fail",
|
||||
},
|
||||
},
|
||||
message: {
|
||||
message_id: "msg-error-cleanup",
|
||||
chat_id: "oc-dm",
|
||||
chat_type: "p2p",
|
||||
message_type: "text",
|
||||
content: JSON.stringify({ text: "hello" }),
|
||||
},
|
||||
};
|
||||
|
||||
await dispatchMessage({ cfg, event });
|
||||
|
||||
const dispatcherResult = mockCreateFeishuReplyDispatcher.mock.results.at(-1)?.value as
|
||||
| {
|
||||
dispatcher: { markComplete: ReturnType<typeof vi.fn> };
|
||||
markDispatchIdle: ReturnType<typeof vi.fn>;
|
||||
}
|
||||
| undefined;
|
||||
expect(dispatcherResult?.dispatcher.markComplete).toHaveBeenCalledTimes(1);
|
||||
expect(dispatcherResult?.markDispatchIdle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user