Skip to content

Commit 847590b

Browse files
vongohrenclaude
andcommitted
refactor(msteams): extract implicit mention logic into testable utility
Extract the implicit mention computation from message-handler.ts into a dedicated implicit-mention.ts module. Both the production code and the tests now import the same function, so regressions in the logic will be caught by the test suite. Addresses review feedback about test helper duplicating production logic. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 826c5dd commit 847590b

3 files changed

Lines changed: 32 additions & 47 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { extractMSTeamsConversationMessageId, normalizeMSTeamsConversationId } from "../inbound.js";
2+
import { wasMSTeamsMessageSent } from "../sent-message-cache.js";
3+
4+
/**
5+
* Determines whether an inbound Teams activity is an implicit mention —
6+
* i.e. a thread reply to a message the bot previously sent.
7+
*
8+
* Two lookup paths:
9+
* 1. `replyToId` directly references a bot-sent message.
10+
* 2. `conversation.id` contains `;messageid=<threadRootId>` pointing to a
11+
* bot-sent (or bot-cached) thread root. This covers the case where Teams
12+
* omits `replyToId` on thread replies.
13+
*/
14+
export function computeImplicitMention(activity: {
15+
conversation?: { id?: string };
16+
replyToId?: string;
17+
}): boolean {
18+
const rawConversationId = activity.conversation?.id ?? "";
19+
const conversationId = normalizeMSTeamsConversationId(rawConversationId);
20+
const replyToId = activity.replyToId ?? undefined;
21+
const threadRootId = extractMSTeamsConversationMessageId(rawConversationId);
22+
return Boolean(
23+
conversationId &&
24+
((replyToId && wasMSTeamsMessageSent(conversationId, replyToId)) ||
25+
(threadRootId && wasMSTeamsMessageSent(conversationId, threadRootId))),
26+
);
27+
}

extensions/msteams/src/monitor-handler/message-handler.implicit-mention.test.ts

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,6 @@
11
import { describe, expect, it, beforeEach } from "vitest";
2-
import { extractMSTeamsConversationMessageId, normalizeMSTeamsConversationId } from "../inbound.js";
3-
import {
4-
clearMSTeamsSentMessageCache,
5-
recordMSTeamsSentMessage,
6-
wasMSTeamsMessageSent,
7-
} from "../sent-message-cache.js";
8-
9-
/**
10-
* Tests for the implicit mention detection logic as implemented in
11-
* message-handler.ts lines 678-687. We test the computation directly
12-
* rather than through the full handler to avoid needing the full
13-
* PluginRuntime/routing setup.
14-
*
15-
* The logic under test:
16-
* const rawConversationId = activity.conversation?.id ?? "";
17-
* const conversationId = normalizeMSTeamsConversationId(rawConversationId);
18-
* const replyToId = activity.replyToId ?? undefined;
19-
* const threadRootId = extractMSTeamsConversationMessageId(rawConversationId);
20-
* const implicitMention = Boolean(
21-
* conversationId && (
22-
* (replyToId && wasMSTeamsMessageSent(conversationId, replyToId)) ||
23-
* (threadRootId && wasMSTeamsMessageSent(conversationId, threadRootId))
24-
* ),
25-
* );
26-
*/
27-
function computeImplicitMention(activity: {
28-
conversation?: { id?: string };
29-
replyToId?: string;
30-
}): boolean {
31-
const rawConversationId = activity.conversation?.id ?? "";
32-
const conversationId = normalizeMSTeamsConversationId(rawConversationId);
33-
const replyToId = activity.replyToId ?? undefined;
34-
const threadRootId = extractMSTeamsConversationMessageId(rawConversationId);
35-
return Boolean(
36-
conversationId &&
37-
((replyToId && wasMSTeamsMessageSent(conversationId, replyToId)) ||
38-
(threadRootId && wasMSTeamsMessageSent(conversationId, threadRootId))),
39-
);
40-
}
2+
import { clearMSTeamsSentMessageCache, recordMSTeamsSentMessage } from "../sent-message-cache.js";
3+
import { computeImplicitMention } from "./implicit-mention.js";
414

425
describe("implicit mention detection (conversation.id threadRootId fallback)", () => {
436
const CONV_ID = "19:group@thread.tacv2";

extensions/msteams/src/monitor-handler/message-handler.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ import { extractMSTeamsPollVote } from "../polls.js";
4646
import { createMSTeamsReplyDispatcher } from "../reply-dispatcher.js";
4747
import { getMSTeamsRuntime } from "../runtime.js";
4848
import type { MSTeamsTurnContext } from "../sdk-types.js";
49-
import { recordMSTeamsSentMessage, wasMSTeamsMessageSent } from "../sent-message-cache.js";
49+
import { recordMSTeamsSentMessage } from "../sent-message-cache.js";
50+
import { computeImplicitMention } from "./implicit-mention.js";
5051
import { resolveMSTeamsInboundMedia } from "./inbound-media.js";
5152

5253
export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
@@ -687,13 +688,7 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
687688
const wasMentioned = wasMSTeamsBotMentioned(activity);
688689
const rawConversationId = activity.conversation?.id ?? "";
689690
const conversationId = normalizeMSTeamsConversationId(rawConversationId);
690-
const replyToId = activity.replyToId ?? undefined;
691-
const threadRootId = extractMSTeamsConversationMessageId(rawConversationId);
692-
const implicitMention = Boolean(
693-
conversationId &&
694-
((replyToId && wasMSTeamsMessageSent(conversationId, replyToId)) ||
695-
(threadRootId && wasMSTeamsMessageSent(conversationId, threadRootId))),
696-
);
691+
const implicitMention = computeImplicitMention(activity);
697692

698693
await inboundDebouncer.enqueue({
699694
context,

0 commit comments

Comments
 (0)