fix(msteams): add proactive fallback for revoked turn context

Fixes #27189

When an inbound message is debounced, the Bot Framework turn context is
revoked before the debouncer flushes and the reply is dispatched. Any
attempt to use the revoked context proxy throws a TypeError, causing the
reply to fail silently.

This commit fixes the issue by adding a fallback to proactive messaging
when the turn context is revoked:

- `isRevokedProxyError()`: New error utility to reliably detect when a
  proxy has been revoked.

- `reply-dispatcher.ts`: `sendTypingIndicator` now catches revoked proxy
  errors and falls back to sending the typing indicator via
  `adapter.continueConversation`.

- `messenger.ts`: `sendMSTeamsMessages` now catches revoked proxy errors
  when `replyStyle` is `thread` and falls back to proactive messaging.

This ensures that replies are delivered reliably even when the inbound
message was debounced, resolving the core issue where the bot appeared
to ignore messages.
This commit is contained in:
root
2026-02-26 13:36:04 +08:00
committed by Peter Steinberger
parent d2bb04b436
commit e0b91067e3
5 changed files with 110 additions and 3 deletions

View File

@@ -10,7 +10,7 @@ import {
} from "openclaw/plugin-sdk";
import type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
import type { StoredConversationReference } from "./conversation-store.js";
import { classifyMSTeamsSendError } from "./errors.js";
import { classifyMSTeamsSendError, isRevokedProxyError } from "./errors.js";
import { prepareFileConsentActivity, requiresFileConsent } from "./file-consent-helpers.js";
import { buildTeamsFileInfoCard } from "./graph-chat.js";
import {
@@ -467,7 +467,15 @@ export async function sendMSTeamsMessages(params: {
if (!ctx) {
throw new Error("Missing context for replyStyle=thread");
}
return await sendMessagesInContext(ctx);
try {
return await sendMessagesInContext(ctx);
} catch (err) {
if (!isRevokedProxyError(err)) {
throw err;
}
// Turn context revoked (debounced message) — fall back to proactive
// messaging so the reply still reaches the user.
}
}
const baseRef = buildConversationReference(params.conversationRef);