mirror of https://github.com/openclaw/openclaw.git
fix(telegram): restore thread_id=1 handling for DMs (regression from 19b8416a8) (openclaw#10942) thanks @garnetlyx
Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm test:macmini Co-authored-by: garnetlyx <12513503+garnetlyx@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
parent
1843bcf1db
commit
cc0bfa0f39
|
|
@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai
|
|||
|
||||
### Fixes
|
||||
|
||||
- Telegram: omit `message_thread_id` for DM sends/draft previews and keep forum-topic handling (`id=1` general omitted, non-general kept), preventing DM failures with `400 Bad Request: message thread not found`. (#10942) Thanks @garnetlyx.
|
||||
- Subagents/Models: preserve `agents.defaults.model.fallbacks` when subagent sessions carry a model override, so subagent runs fail over to configured fallback models instead of retrying only the overridden primary model.
|
||||
- Config/Gateway: make sensitive-key whitelist suffix matching case-insensitive while preserving `passwordFile` path exemptions, preventing accidental redaction of non-secret config values like `maxTokens` and IRC password-file paths. (#16042) Thanks @akramcodez.
|
||||
- Group chats: always inject group chat context (name, participants, reply guidance) into the system prompt on every turn, not just the first. Prevents the model from losing awareness of which group it's in and incorrectly using the message tool to send to the same group. (#14447) Thanks @tyler6204.
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ describe("deliverReplies", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("keeps message_thread_id=1 when allowed", async () => {
|
||||
it("does not include message_thread_id for DMs (threads don't exist in private chats)", async () => {
|
||||
const runtime = { error: vi.fn(), log: vi.fn() };
|
||||
const sendMessage = vi.fn().mockResolvedValue({
|
||||
message_id: 4,
|
||||
|
|
@ -191,7 +191,7 @@ describe("deliverReplies", () => {
|
|||
expect(sendMessage).toHaveBeenCalledWith(
|
||||
"123",
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
expect.not.objectContaining({
|
||||
message_thread_id: 1,
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -43,9 +43,24 @@ describe("buildTelegramThreadParams", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("keeps thread id=1 for dm threads", () => {
|
||||
expect(buildTelegramThreadParams({ id: 1, scope: "dm" })).toEqual({
|
||||
message_thread_id: 1,
|
||||
it("skips thread id for dm threads (DMs don't have threads)", () => {
|
||||
expect(buildTelegramThreadParams({ id: 1, scope: "dm" })).toBeUndefined();
|
||||
expect(buildTelegramThreadParams({ id: 2, scope: "dm" })).toBeUndefined();
|
||||
});
|
||||
|
||||
it("normalizes and skips thread id for dm threads even with edge values", () => {
|
||||
expect(buildTelegramThreadParams({ id: 0, scope: "dm" })).toBeUndefined();
|
||||
expect(buildTelegramThreadParams({ id: -1, scope: "dm" })).toBeUndefined();
|
||||
expect(buildTelegramThreadParams({ id: 1.9, scope: "dm" })).toBeUndefined();
|
||||
});
|
||||
|
||||
it("handles thread id 0 for non-dm scopes", () => {
|
||||
// id=0 should be included for forum and none scopes (not falsy)
|
||||
expect(buildTelegramThreadParams({ id: 0, scope: "forum" })).toEqual({
|
||||
message_thread_id: 0,
|
||||
});
|
||||
expect(buildTelegramThreadParams({ id: 0, scope: "none" })).toEqual({
|
||||
message_thread_id: 0,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -56,17 +56,34 @@ export function resolveTelegramThreadSpec(params: {
|
|||
|
||||
/**
|
||||
* Build thread params for Telegram API calls (messages, media).
|
||||
*
|
||||
* IMPORTANT: Thread IDs behave differently based on chat type:
|
||||
* - DMs (private chats): Never send thread_id (threads don't exist)
|
||||
* - Forum topics: Skip thread_id=1 (General topic), include others
|
||||
* - Regular groups: Thread IDs are ignored by Telegram
|
||||
*
|
||||
* General forum topic (id=1) must be treated like a regular supergroup send:
|
||||
* Telegram rejects sendMessage/sendMedia with message_thread_id=1 ("thread not found").
|
||||
*
|
||||
* @param thread - Thread specification with ID and scope
|
||||
* @returns API params object or undefined if thread_id should be omitted
|
||||
*/
|
||||
export function buildTelegramThreadParams(thread?: TelegramThreadSpec | null) {
|
||||
if (!thread?.id) {
|
||||
if (thread?.id == null) {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = Math.trunc(thread.id);
|
||||
if (normalized === TELEGRAM_GENERAL_TOPIC_ID && thread.scope === "forum") {
|
||||
|
||||
// Never send thread_id for DMs (threads don't exist in private chats)
|
||||
if (thread.scope === "dm") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Telegram rejects message_thread_id=1 for General forum topic
|
||||
if (normalized === TELEGRAM_GENERAL_TOPIC_ID) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { message_thread_id: normalized };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ describe("createTelegramDraftStream", () => {
|
|||
await vi.waitFor(() => expect(api.sendMessage).toHaveBeenCalledWith(123, "Hello", undefined));
|
||||
});
|
||||
|
||||
it("keeps message_thread_id for dm threads and clears preview on cleanup", async () => {
|
||||
it("omits message_thread_id for dm threads and clears preview on cleanup", async () => {
|
||||
const api = {
|
||||
sendMessage: vi.fn().mockResolvedValue({ message_id: 17 }),
|
||||
editMessageText: vi.fn().mockResolvedValue(true),
|
||||
|
|
@ -108,9 +108,7 @@ describe("createTelegramDraftStream", () => {
|
|||
});
|
||||
|
||||
stream.update("Hello");
|
||||
await vi.waitFor(() =>
|
||||
expect(api.sendMessage).toHaveBeenCalledWith(123, "Hello", { message_thread_id: 1 }),
|
||||
);
|
||||
await vi.waitFor(() => expect(api.sendMessage).toHaveBeenCalledWith(123, "Hello", undefined));
|
||||
await stream.clear();
|
||||
|
||||
expect(api.deleteMessage).toHaveBeenCalledWith(123, 17);
|
||||
|
|
|
|||
Loading…
Reference in New Issue