Bug Description
When sending files via FileConsentCard in a Teams DM, the file uploads to OneDrive successfully, but the FileInfoCard (download card) never appears in the chat. The user clicks "Allow", nothing visibly happens, and the file is silently uploaded to OneDrive without any chat confirmation.
Root Cause
In extensions/msteams/src/monitor-handler.ts, the handler.run function handles file consent invokes:
handler.run = async (context: unknown) => {
const ctx = context as MSTeamsTurnContext;
if (ctx.activity?.type === "invoke" && ctx.activity?.name === "fileConsent/invoke") {
await ctx.sendActivity({ type: "invokeResponse", value: { status: 200 } });
handleFileConsentInvoke(ctx, deps.log).catch(...);
return; // handler returns → webhook response sent → TurnContext proxy revoked
}
};
- Invoke response is sent immediately ✅
handleFileConsentInvoke is called (fire-and-forget)
- Handler returns → webhook HTTP response completes → TurnContext proxy is revoked by the SDK
- Inside
handleFileConsentInvoke:
uploadToConsentUrl() succeeds (uses plain fetch, no context needed) ✅
context.sendActivity(fileInfoCard) fails ❌ — proxy revoked
Error: TypeError: Cannot perform 'get' on a proxy that has been revoked
Expected Behavior
After the user clicks "Allow":
- File uploads to OneDrive
FileInfoCard appears in the chat with a download link
- User can click to download the file
Actual Behavior
After the user clicks "Allow":
- File uploads to OneDrive ✅
- FileInfoCard never appears in chat ❌
- User sees nothing — appears broken
Attempted Fixes
- Await the handler (keep upload synchronous) — context still revoked because invoke response was already sent
setImmediate async — same proxy revocation
adapter.continueConversation(ref, callback) — Invalid conversation reference object
adapter.continueConversation(appId, ref, callback) — same invalid ref error
Suggested Fix
The handleFileConsentInvoke function needs access to the proactive messaging dependencies (adapter, appId, conversationStore) so it can send the FileInfoCard via proactive messaging after the upload completes — the same path that send.ts uses for regular proactive messages.
// Pass proactive messaging deps to handler
handleFileConsentInvoke(ctx, deps.log, {
adapter: deps.adapter,
appId: deps.appId,
conversationStore: deps.conversationStore,
}).catch(...);
// Inside handleFileConsentInvoke, after upload:
const ref = await conversationStore.get(conversationId);
await adapter.continueConversation(appId, ref, async (proactiveCtx) => {
await proactiveCtx.sendActivity({ type: "message", attachments: [fileInfoCard] });
});
Environment
- OpenClaw: 2026.2.26
- Plugin: @openclaw/msteams
- @microsoft/agents-hosting: 1.3.x
- Bot type: Single Tenant
- Teams client: Desktop (macOS) and Web
- Chat type: Personal (1:1 DM)
- File size: 55 bytes (timing is not the issue — upload takes <1 second)
Related
Bug Description
When sending files via
FileConsentCardin a Teams DM, the file uploads to OneDrive successfully, but theFileInfoCard(download card) never appears in the chat. The user clicks "Allow", nothing visibly happens, and the file is silently uploaded to OneDrive without any chat confirmation.Root Cause
In
extensions/msteams/src/monitor-handler.ts, thehandler.runfunction handles file consent invokes:handleFileConsentInvokeis called (fire-and-forget)handleFileConsentInvoke:uploadToConsentUrl()succeeds (uses plainfetch, no context needed) ✅context.sendActivity(fileInfoCard)fails ❌ — proxy revokedError:
TypeError: Cannot perform 'get' on a proxy that has been revokedExpected Behavior
After the user clicks "Allow":
FileInfoCardappears in the chat with a download linkActual Behavior
After the user clicks "Allow":
Attempted Fixes
setImmediateasync — same proxy revocationadapter.continueConversation(ref, callback)—Invalid conversation reference objectadapter.continueConversation(appId, ref, callback)— same invalid ref errorSuggested Fix
The
handleFileConsentInvokefunction needs access to the proactive messaging dependencies (adapter, appId, conversationStore) so it can send theFileInfoCardvia proactive messaging after the upload completes — the same path thatsend.tsuses for regular proactive messages.Environment
Related