fix(msteams): re-land revoked-context proactive fallback#59937
fix(msteams): re-land revoked-context proactive fallback#59937BradGroux wants to merge 1 commit intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Re-lands the Microsoft Teams “revoked turn context” proactive fallback so batched thread replies are not silently dropped when the Bot Framework turn context proxy is revoked (e.g., via message debouncing).
Changes:
- Refactors
sendMSTeamsMessagesto extractsendMessagesInContext/sendProactively, and adds per-message revoked-context detection to fall back to proactive sends for remaining messages. - Reintroduces
isRevokedProxyError()to detect revoked proxy failures. - Adds unit tests covering full and partial revoked-context fallback behavior, plus a shared
createRecordedSendActivityhelper. - Adds an Unreleased changelog entry documenting the fix.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
extensions/msteams/src/messenger.ts |
Adds per-message revoked-context fallback from thread sends to proactive sends; extracts helper functions. |
extensions/msteams/src/errors.ts |
Adds isRevokedProxyError() utility used by the fallback logic. |
extensions/msteams/src/messenger.test.ts |
Adds regression tests for full/partial revocation and a shared send-activity recorder helper. |
CHANGELOG.md |
Documents the fix under Unreleased > Fixes. |
Greptile SummaryThis PR re-lands the revoked-context proactive fallback for MS Teams (#27224) that was lost in a subsequent force-push to Key observations:
Confidence Score: 4/5Safe to merge — the re-landed logic is correct and well-tested; only minor style nits remain. The core fallback logic is sound: per-message try/catch, correct slice semantics (failing message is included in the proactive batch), non-revocation errors still propagate, and retry does not fire for revoked-proxy TypeErrors. Two new integration tests cover both full and partial revocation. Small deductions for the always-true No files require special attention; the two style items are non-blocking. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/msteams/src/messenger.ts
Line: 490-493
Comment:
**Redundant guard — `remaining` is always non-empty here**
`messages.slice(idx)` always includes at least `messages[idx]` (the currently-failing message), so `remaining.length > 0` is always `true` at this point. The `if` branch is dead code and can be removed to avoid confusion for future readers.
```suggestion
messageIds.push(...(await sendProactively(remaining, idx)));
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/msteams/src/errors.ts
Line: 177-182
Comment:
**No dedicated unit tests for `isRevokedProxyError`**
`isRevokedProxyError` is only exercised indirectly through the `messenger.test.ts` integration tests. Consider adding a small unit test block in `errors.test.ts` covering:
- non-`TypeError` values (plain `Error`, a string, `null`) → should return `false`
- a `TypeError` with an unrelated message → should return `false`
- a `TypeError` with the canonical revoked-proxy message → should return `true`
This makes the utility's contract explicit and guards against future regressions to the regex independently of the messenger layer.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(msteams): re-land revoked-context pr..." | Re-trigger Greptile |
| const remaining = messages.slice(idx); | ||
| if (remaining.length > 0) { | ||
| messageIds.push(...(await sendProactively(remaining, idx))); | ||
| } |
There was a problem hiding this comment.
Redundant guard —
remaining is always non-empty here
messages.slice(idx) always includes at least messages[idx] (the currently-failing message), so remaining.length > 0 is always true at this point. The if branch is dead code and can be removed to avoid confusion for future readers.
| const remaining = messages.slice(idx); | |
| if (remaining.length > 0) { | |
| messageIds.push(...(await sendProactively(remaining, idx))); | |
| } | |
| messageIds.push(...(await sendProactively(remaining, idx))); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/messenger.ts
Line: 490-493
Comment:
**Redundant guard — `remaining` is always non-empty here**
`messages.slice(idx)` always includes at least `messages[idx]` (the currently-failing message), so `remaining.length > 0` is always `true` at this point. The `if` branch is dead code and can be removed to avoid confusion for future readers.
```suggestion
messageIds.push(...(await sendProactively(remaining, idx)));
```
How can I resolve this? If you propose a fix, please make it concise.| export function isRevokedProxyError(err: unknown): boolean { | ||
| if (!(err instanceof TypeError)) { | ||
| return false; | ||
| } | ||
| return /proxy that has been revoked/i.test(err.message); | ||
| } |
There was a problem hiding this comment.
No dedicated unit tests for
isRevokedProxyError
isRevokedProxyError is only exercised indirectly through the messenger.test.ts integration tests. Consider adding a small unit test block in errors.test.ts covering:
- non-
TypeErrorvalues (plainError, a string,null) → should returnfalse - a
TypeErrorwith an unrelated message → should returnfalse - a
TypeErrorwith the canonical revoked-proxy message → should returntrue
This makes the utility's contract explicit and guards against future regressions to the regex independently of the messenger layer.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/errors.ts
Line: 177-182
Comment:
**No dedicated unit tests for `isRevokedProxyError`**
`isRevokedProxyError` is only exercised indirectly through the `messenger.test.ts` integration tests. Consider adding a small unit test block in `errors.test.ts` covering:
- non-`TypeError` values (plain `Error`, a string, `null`) → should return `false`
- a `TypeError` with an unrelated message → should return `false`
- a `TypeError` with the canonical revoked-proxy message → should return `true`
This makes the utility's contract explicit and guards against future regressions to the regex independently of the messenger layer.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
) Re-lands the revoked-context fallback from openclaw#27224 (originally by @openperf, merged by @steipete) which was lost during a force-push to main. When a thread reply's turn context is revoked (e.g. due to message debouncing), falls back to proactive messaging per-message so remaining replies still reach the user instead of being silently lost. Changes: - Extract sendMessagesInContext and sendProactively helpers - Per-message try/catch in thread path with revoke detection - Remaining messages fall through to proactive path on revocation - Add isRevokedProxyError to errors.ts (also lost in refactor) - Add test coverage for full and partial revocation scenarios Co-authored-by: openperf <[email protected]>
cefd93b to
9841c67
Compare
|
Closing — the revoked-context fallback from #27224 was already re-landed upstream as part of 866bd91 ( Our fork was behind upstream/main, which made it look missing locally. No action needed. |
Summary
Re-lands the revoked-context proactive fallback from #27224 (originally by @openperf, merged by @steipete on Mar 2) which was lost during a subsequent force-push to main.
This is a prerequisite for #55198 (channel reply threading fix).
Problem
When a thread reply's turn context is revoked (e.g. due to Bot Framework message debouncing), all remaining messages in the batch are silently lost. The original fix landed in #27224 but the merge commit (
089a878) is no longer onmain.Changes
messenger.ts: ExtractsendMessagesInContextandsendProactivelyhelpers from inline code. Thread path now uses per-message try/catch withisRevokedProxyErrordetection — on revocation, remaining messages fall through to the proactive delivery path.errors.ts: AddisRevokedProxyError()utility (also lost in the refactor).messenger.test.ts: Add test coverage for both full revocation (all messages) and partial revocation (first succeeds, rest fall back). Add sharedcreateRecordedSendActivitytest helper.CHANGELOG.md: Entry under Unreleased > Fixes.Testing
getOAuthProvidersimport chain issue is unrelated — reproduces onmainwithout this PR)Related