@openclaw/msteams 2026.9.4 → 2026.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/assets/activity.svg +40 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/{adapter.runtime-BzR3RK2J.cjs → .setup/adapter.runtime-CQWZeqB5.cjs} +5 -3
  4. package/dist/{approval-handler.runtime-DRhFNeJS.cjs → .setup/approval-handler.runtime-CUnanUdR.cjs} +3 -3
  5. package/dist/{channel-B9LIyYeu.cjs → .setup/channel-BDp16XRR.cjs} +128 -89
  6. package/dist/{channel.runtime-BergqMHg.cjs → .setup/channel.runtime-Cv5F8JCa.cjs} +61 -34
  7. package/dist/{channel.setup-BhxokviI.cjs → .setup/channel.setup-BVDfgdCc.cjs} +3 -3
  8. package/dist/{delegated-state-DiEz9JIa.cjs → .setup/delegated-state-u-ywZyZT.cjs} +5 -5
  9. package/dist/{messenger-TLdZf9Ar.cjs → .setup/messenger-8RA1FUJa.cjs} +112 -188
  10. package/dist/{oauth-DUtLTz2u.cjs → .setup/oauth-C6m7dvHj.cjs} +1 -1
  11. package/dist/{polls-BBdZPx_R.cjs → .setup/polls-BJ4-4uZm.cjs} +14 -7
  12. package/dist/{reaction-types-BbBBdnQ5.cjs → .setup/reaction-types-C7RA7Wxt.cjs} +1 -1
  13. package/dist/{resolve-allowlist-DmUTQxEz.cjs → .setup/resolve-allowlist-CHzaaWiC.cjs} +135 -93
  14. package/dist/.setup/secret-contract-api-ChQdBeU1.cjs +4 -0
  15. package/dist/.setup/secret-contract-api-ipiUsANg.cjs +28 -0
  16. package/dist/{send-CU61PSDN.cjs → .setup/send-CYN_N7O1.cjs} +99 -34
  17. package/dist/.setup/setup-plugin-api-DpiaA8z1.cjs +3 -0
  18. package/dist/{src-D7Do7sM5.cjs → .setup/src-BfOCwlHp.cjs} +150 -125
  19. package/dist/{sso-token-store-DTeYxubp.cjs → .setup/sso-token-store-YYLHXgFH.cjs} +1 -1
  20. package/dist/{thread-session-NmA7_njI.cjs → .setup/thread-session-CXgHK-yi.cjs} +1 -1
  21. package/dist/api.cjs +2 -2
  22. package/dist/channel-config-api.cjs +1 -1
  23. package/dist/channel-plugin-api.cjs +1 -1
  24. package/dist/configured-state.cjs +1 -1
  25. package/dist/directory-contract-api.cjs +1 -1
  26. package/dist/doctor-contract-api.cjs +64 -62
  27. package/dist/qa-runner-api.cjs +1 -1
  28. package/dist/runtime-api.cjs +1 -1
  29. package/dist/secret-contract-api.cjs +4 -13
  30. package/dist/setup-entry.cjs +5 -3
  31. package/dist/setup-plugin-api.cjs +1 -1
  32. package/openclaw.plugin.json +1 -1
  33. package/package.json +14 -11
  34. /package/dist/{approval-card-CPNH_q3P.cjs → .setup/approval-card-CPNH_q3P.cjs} +0 -0
  35. /package/dist/{config-schema-D22Lr1Qk.cjs → .setup/config-schema-D22Lr1Qk.cjs} +0 -0
  36. /package/dist/{rolldown-runtime-VH7oDXx4.cjs → .setup/rolldown-runtime-VH7oDXx4.cjs} +0 -0
  37. /package/dist/{runtime-gZTAuFux.cjs → .setup/runtime-gZTAuFux.cjs} +0 -0
  38. /package/dist/{secret-input-C65t6kjM.cjs → .setup/secret-input-C65t6kjM.cjs} +0 -0
@@ -1,15 +1,15 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
- require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-DmUTQxEz.cjs");
5
- const require_channel = require("./channel-B9LIyYeu.cjs");
6
- const require_thread_session = require("./thread-session-NmA7_njI.cjs");
7
- const require_channel_setup = require("./channel.setup-BhxokviI.cjs");
8
- const require_polls = require("./polls-BBdZPx_R.cjs");
9
- const require_sso_token_store = require("./sso-token-store-DTeYxubp.cjs");
3
+ require("../runtime-api.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
5
+ const require_channel = require("./channel-BDp16XRR.cjs");
6
+ const require_thread_session = require("./thread-session-CXgHK-yi.cjs");
7
+ const require_channel_setup = require("./channel.setup-BVDfgdCc.cjs");
8
+ const require_polls = require("./polls-BJ4-4uZm.cjs");
9
+ const require_sso_token_store = require("./sso-token-store-YYLHXgFH.cjs");
10
10
  const require_approval_card = require("./approval-card-CPNH_q3P.cjs");
11
- const require_messenger = require("./messenger-TLdZf9Ar.cjs");
12
- const require_reaction_types = require("./reaction-types-BbBBdnQ5.cjs");
11
+ const require_messenger = require("./messenger-8RA1FUJa.cjs");
12
+ const require_reaction_types = require("./reaction-types-C7RA7Wxt.cjs");
13
13
  let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
14
14
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
15
15
  let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
@@ -19,10 +19,10 @@ let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runti
19
19
  let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
20
20
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
21
21
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
22
+ let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
22
23
  let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
23
24
  let node_crypto = require("node:crypto");
24
25
  node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
25
- let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
26
26
  let openclaw_plugin_sdk_channel_inbound = require("openclaw/plugin-sdk/channel-inbound");
27
27
  let openclaw_plugin_sdk_approval_gateway_runtime = require("openclaw/plugin-sdk/approval-gateway-runtime");
28
28
  let openclaw_plugin_sdk_channel_ingress_runtime = require("openclaw/plugin-sdk/channel-ingress-runtime");
@@ -47,18 +47,35 @@ const MAX_LEARNING_ENTRIES = 1e4;
47
47
  function learningStoreKey(storePath, sessionKey) {
48
48
  return node_crypto.default.createHash("sha256").update(`${storePath}\0${sessionKey}`, "utf8").digest("hex");
49
49
  }
50
+ function appendFeedbackLearning(current, prepared) {
51
+ return {
52
+ sessionKey: prepared.sessionKey,
53
+ learnings: [...current?.learnings ?? [], prepared.learning].slice(-10),
54
+ updatedAt: prepared.updatedAt
55
+ };
56
+ }
50
57
  async function storeSessionLearning(params) {
51
58
  const store = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
52
59
  namespace: LEARNINGS_NAMESPACE,
53
60
  maxEntries: MAX_LEARNING_ENTRIES
54
61
  });
55
62
  const key = learningStoreKey(params.storePath, params.sessionKey);
56
- if (!store.update) throw new Error("plugin state atomic update is unavailable");
57
- await store.update(key, (existing) => ({
63
+ if (!store.observe || !store.compareAndApply) throw new Error("plugin state atomic comparison is unavailable");
64
+ const prepared = {
58
65
  sessionKey: params.sessionKey,
59
- learnings: [...existing?.learnings ?? [], params.learning].slice(-10),
66
+ learning: params.learning,
60
67
  updatedAt: Date.now()
61
- }));
68
+ };
69
+ let observed = await store.observe(key);
70
+ while (true) {
71
+ const result = await store.compareAndApply(key, observed.comparison, {
72
+ operation: "update",
73
+ action: "set",
74
+ value: appendFeedbackLearning(observed.value, prepared)
75
+ });
76
+ if (result.status !== "conflict") return;
77
+ observed = result.current;
78
+ }
62
79
  }
63
80
  //#endregion
64
81
  //#region extensions/msteams/src/feedback-reflection.ts
@@ -310,6 +327,7 @@ async function resolveMSTeamsSenderAccess(params) {
310
327
  const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(activity.conversation?.id ?? "unknown");
311
328
  const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(activity.conversation?.conversationType);
312
329
  const isDirectMessage = convType === "personal" || !convType && !activity.conversation?.isGroup;
330
+ const hasConflictingConversationScope = isDirectMessage && (activity.conversation?.isGroup === true || activity.channelData?.team !== void 0 || activity.channelData?.channel !== void 0);
313
331
  const senderId = activity.from?.aadObjectId ?? activity.from?.id ?? "unknown";
314
332
  const senderName = activity.from?.name ?? activity.from?.id ?? senderId;
315
333
  const core = require_runtime.getMSTeamsRuntime();
@@ -332,7 +350,7 @@ async function resolveMSTeamsSenderAccess(params) {
332
350
  channelName: activity.channelData?.channel?.name,
333
351
  allowNameMatching
334
352
  });
335
- const resolved = await (0, openclaw_plugin_sdk_channel_ingress_runtime.resolveStableChannelMessageIngress)({
353
+ const resolved = await core.channel.inbound.ingress.resolveStable({
336
354
  channelId: "msteams",
337
355
  accountId: pairing.accountId,
338
356
  identity: {
@@ -397,6 +415,7 @@ async function resolveMSTeamsSenderAccess(params) {
397
415
  channelIngress: resolved,
398
416
  pairing,
399
417
  isDirectMessage,
418
+ hasConflictingConversationScope,
400
419
  conversationId,
401
420
  senderId,
402
421
  senderName,
@@ -419,9 +438,14 @@ async function admitMSTeamsMessage(params) {
419
438
  activity: params.activity,
420
439
  hasControlCommand: isControlCommand
421
440
  });
422
- const { dmPolicy, senderId, senderName, pairing, isDirectMessage, channelGate, senderAccess, commandAccess, allowNameMatching, groupPolicy, msteamsCfg } = access;
441
+ const { dmPolicy, senderId, senderName, pairing, isDirectMessage, hasConflictingConversationScope, channelGate, senderAccess, commandAccess, allowNameMatching, groupPolicy, msteamsCfg } = access;
423
442
  const effectiveDmAllowFrom = senderAccess.effectiveAllowFrom;
424
443
  const effectiveGroupAllowFrom = senderAccess.effectiveGroupAllowFrom;
444
+ if (hasConflictingConversationScope) {
445
+ params.log.info("dropping message (conflicting conversation scope)", { conversationId: params.conversationId });
446
+ params.log.debug?.("dropping message (conflicting conversation scope)");
447
+ return null;
448
+ }
425
449
  if (isDirectMessage && msteamsCfg && senderAccess.decision !== "allow") {
426
450
  if (senderAccess.reasonCode === "dm_policy_disabled") {
427
451
  params.log.info("dropping dm (dms disabled)", {
@@ -873,11 +897,11 @@ function createAdvertisedMediaFact(kind, sourceId) {
873
897
  if (sourceId) media.sourceId = sourceId;
874
898
  return media;
875
899
  }
876
- function resolveMSTeamsAdvertisedMedia(attachments, limits) {
900
+ function resolveMSTeamsAdvertisedMedia(attachments) {
877
901
  const list = Array.isArray(attachments) ? attachments : [];
878
902
  if (list.length === 0) return [];
879
903
  const fileAttachments = list.filter(require_resolve_allowlist.isAdvertisedFileAttachment);
880
- const inlineMedia = require_resolve_allowlist.extractInlineImageCandidates(list, limits).map((candidate) => createAdvertisedMediaFact("image", candidate.sourceId));
904
+ const inlineMedia = require_resolve_allowlist.extractInlineImageReferences(list).map((candidate) => createAdvertisedMediaFact("image", candidate.sourceId));
881
905
  const htmlAttachmentIds = resolveUnrepresentedHtmlAttachmentIds(list);
882
906
  return [
883
907
  ...fileAttachments.map((attachment) => createAdvertisedMediaFact(require_resolve_allowlist.isLikelyImageAttachment(attachment) ? "image" : require_resolve_allowlist.resolveMSTeamsMediaKind({
@@ -995,6 +1019,44 @@ function scopeCandidatesForUrl(url) {
995
1019
  return ["https://api.botframework.com", "https://graph.microsoft.com"];
996
1020
  }
997
1021
  }
1022
+ function canonicalizeInlineBase64Payload(value) {
1023
+ let cleaned = "";
1024
+ let padding = 0;
1025
+ let sawPadding = false;
1026
+ for (let index = 0; index < value.length; index += 1) {
1027
+ const code = value.charCodeAt(index);
1028
+ if (code <= 32) continue;
1029
+ if (code === 61) {
1030
+ padding += 1;
1031
+ if (padding > 2) return;
1032
+ sawPadding = true;
1033
+ cleaned += "=";
1034
+ continue;
1035
+ }
1036
+ if (sawPadding || !(code >= 65 && code <= 90 || code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 43 || code === 47)) return;
1037
+ cleaned += value[index];
1038
+ }
1039
+ return cleaned && cleaned.length % 4 === 0 ? cleaned : void 0;
1040
+ }
1041
+ function decodeInlineDataImage(src, maxBytes, totalBytes) {
1042
+ const match = /^data:(image\/[a-z0-9.+-]+)?(;base64)?,(.*)$/i.exec(src);
1043
+ if (!match) return null;
1044
+ const contentType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(match[1] ?? "");
1045
+ if (!Boolean(match[2])) return null;
1046
+ const canonicalPayload = canonicalizeInlineBase64Payload(match[3] ?? "");
1047
+ if (!canonicalPayload) return null;
1048
+ const estimatedBytes = Buffer.byteLength(canonicalPayload, "base64");
1049
+ if (estimatedBytes <= 0 || typeof maxBytes === "number" && (estimatedBytes > maxBytes || totalBytes + estimatedBytes > maxBytes)) return null;
1050
+ try {
1051
+ return {
1052
+ data: Buffer.from(canonicalPayload, "base64"),
1053
+ contentType,
1054
+ estimatedBytes
1055
+ };
1056
+ } catch {
1057
+ return null;
1058
+ }
1059
+ }
998
1060
  async function resolveInlineDataImageMime(inline) {
999
1061
  const detectedMime = await require_runtime.getMSTeamsRuntime().media.detectMime({
1000
1062
  buffer: inline.data,
@@ -1070,15 +1132,12 @@ async function downloadMSTeamsAttachments(params) {
1070
1132
  sourceId: attachment.id?.trim() || void 0
1071
1133
  };
1072
1134
  });
1073
- candidates.push(...require_resolve_allowlist.extractInlineImageCandidates(list, {
1074
- maxInlineBytes: params.maxBytes,
1075
- maxInlineTotalBytes: params.maxBytes
1076
- }).map((candidate) => {
1135
+ const maxInlineBytes = params.maxBytes;
1136
+ candidates.push(...require_resolve_allowlist.extractInlineImageReferences(list).map((candidate) => {
1077
1137
  if (candidate.kind === "data") return {
1078
1138
  kind: "data",
1079
1139
  mediaKind: "image",
1080
- data: candidate.data,
1081
- contentType: candidate.contentType,
1140
+ src: candidate.src,
1082
1141
  sourceId: candidate.sourceId
1083
1142
  };
1084
1143
  if (candidate.kind === "url") return {
@@ -1095,30 +1154,33 @@ async function downloadMSTeamsAttachments(params) {
1095
1154
  sourceId: candidate.sourceId
1096
1155
  };
1097
1156
  }));
1098
- const advertisedMedia = resolveMSTeamsAdvertisedMedia(list, {
1099
- maxInlineBytes: params.maxBytes,
1100
- maxInlineTotalBytes: params.maxBytes
1101
- });
1102
- for (const advertised of advertisedMedia.slice(candidates.length)) candidates.push({
1157
+ for (const sourceId of resolveUnrepresentedHtmlAttachmentIds(list)) candidates.push({
1103
1158
  kind: "unavailable",
1104
- mediaKind: advertised.kind,
1105
- sourceId: advertised.sourceId
1159
+ mediaKind: "document",
1160
+ sourceId
1106
1161
  });
1107
1162
  if (candidates.length === 0) return [];
1108
1163
  const out = [];
1164
+ let totalInlineBytes = 0;
1109
1165
  for (const candidate of candidates) {
1110
1166
  if (candidate.kind === "unavailable") {
1111
1167
  out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1112
1168
  continue;
1113
1169
  }
1114
1170
  if (candidate.kind === "data") {
1171
+ const decoded = decodeInlineDataImage(candidate.src, maxInlineBytes, totalInlineBytes);
1172
+ if (!decoded) {
1173
+ out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1174
+ continue;
1175
+ }
1176
+ totalInlineBytes += decoded.estimatedBytes;
1115
1177
  try {
1116
- const contentType = await resolveInlineDataImageMime(candidate);
1178
+ const contentType = await resolveInlineDataImageMime(decoded);
1117
1179
  if (!contentType) {
1118
1180
  out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1119
1181
  continue;
1120
1182
  }
1121
- const saved = await require_runtime.getMSTeamsRuntime().channel.media.saveMediaBuffer(candidate.data, contentType, "inbound", params.maxBytes);
1183
+ const saved = await require_runtime.getMSTeamsRuntime().channel.media.saveMediaBuffer(decoded.data, contentType, "inbound", params.maxBytes);
1122
1184
  out.push(withSourceId({
1123
1185
  path: saved.path,
1124
1186
  contentType: saved.contentType,
@@ -1834,6 +1896,8 @@ function createTeamsReplyStreamController(params) {
1834
1896
  return payloads;
1835
1897
  };
1836
1898
  const progressDraft = (0, openclaw_plugin_sdk_channel_outbound.createChannelProgressDraftCompositor)({
1899
+ preparedItems: true,
1900
+ formatPlainText: (text) => text,
1837
1901
  entry: params.msteamsConfig,
1838
1902
  mode: streamMode,
1839
1903
  active: Boolean(stream) && streamMode === "progress",
@@ -1891,13 +1955,8 @@ function createTeamsReplyStreamController(params) {
1891
1955
  params.log?.warn?.(`msteams stream emit failed, falling back to block delivery: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
1892
1956
  }
1893
1957
  },
1894
- async noteProgressWork(options) {
1895
- if (options?.toolName !== void 0 && !(0, openclaw_plugin_sdk_channel_outbound.isChannelProgressDraftWorkToolName)(options.toolName)) return;
1896
- await progressDraft.noteActivity();
1897
- },
1898
- async pushProgressLine(line, options) {
1899
- await progressDraft.pushToolProgress(line, options);
1900
- },
1958
+ pushItemEvent: progressDraft.pushItemEvent.bind(progressDraft),
1959
+ pushToolEvent: progressDraft.pushToolEvent,
1901
1960
  async pushReasoningProgress(text, options) {
1902
1961
  await progressDraft.pushReasoningProgress(text, options);
1903
1962
  },
@@ -2429,38 +2488,14 @@ function createMSTeamsReplyDispatcher(params) {
2429
2488
  streamController.resetReasoningProgress();
2430
2489
  return false;
2431
2490
  },
2432
- onToolStart: async (payload) => {
2433
- const name = typeof payload?.name === "string" ? payload.name : void 0;
2434
- const detailMode = typeof payload?.detailMode === "string" ? payload.detailMode : void 0;
2435
- await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLineForEntry)(msteamsCfg, {
2436
- event: "tool",
2437
- ...typeof payload?.itemId === "string" ? { itemId: payload.itemId } : {},
2438
- ...typeof payload?.toolCallId === "string" ? { toolCallId: payload.toolCallId } : {},
2439
- ...name ? { name } : {},
2440
- ...typeof payload?.phase === "string" ? { phase: payload.phase } : {},
2441
- ...payload?.args && typeof payload.args === "object" ? { args: payload.args } : {}
2442
- }, detailMode === "explain" || detailMode === "raw" ? { detailMode } : void 0), name ? { toolName: name } : void 0);
2443
- return false;
2444
- },
2445
- onItemEvent: async (payload) => {
2446
- await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLineForEntry)(msteamsCfg, {
2447
- event: "item",
2448
- ...typeof payload?.itemId === "string" ? { itemId: payload.itemId } : {},
2449
- ...typeof payload?.toolCallId === "string" ? { toolCallId: payload.toolCallId } : {},
2450
- ...typeof payload?.kind === "string" ? { itemKind: payload.kind } : {},
2451
- ...typeof payload?.title === "string" ? { title: payload.title } : {},
2452
- ...typeof payload?.name === "string" ? { name: payload.name } : {},
2453
- ...typeof payload?.phase === "string" ? { phase: payload.phase } : {},
2454
- ...typeof payload?.status === "string" ? { status: payload.status } : {},
2455
- ...typeof payload?.summary === "string" ? { summary: payload.summary } : {},
2456
- ...typeof payload?.progressText === "string" ? { progressText: payload.progressText } : {},
2457
- ...typeof payload?.meta === "string" ? { meta: payload.meta } : {}
2458
- }));
2459
- return false;
2460
- },
2491
+ onToolStart: streamController.pushToolEvent,
2492
+ onItemEvent: streamController.pushItemEvent,
2461
2493
  onPlanUpdate: async (payload) => {
2462
2494
  if (payload?.phase !== "update") return false;
2463
- await streamController.pushPlanProgress((0, openclaw_plugin_sdk_channel_outbound.normalizeAgentPlanSteps)(payload.steps), { explanation: typeof payload.explanation === "string" ? payload.explanation : void 0 });
2495
+ await streamController.pushPlanProgress((0, openclaw_plugin_sdk_channel_outbound.normalizeAgentPlanSteps)(payload.steps), {
2496
+ explanation: typeof payload.explanation === "string" ? payload.explanation : void 0,
2497
+ explanationFormat: payload.explanationFormat === "plain" ? "plain" : void 0
2498
+ });
2464
2499
  return false;
2465
2500
  },
2466
2501
  onApprovalEvent: async (payload) => {
@@ -2473,36 +2508,6 @@ function createMSTeamsReplyDispatcher(params) {
2473
2508
  ...typeof payload?.message === "string" ? { message: payload.message } : {}
2474
2509
  });
2475
2510
  return false;
2476
- },
2477
- onCommandOutput: async (payload) => {
2478
- if (payload?.phase !== "end") return false;
2479
- await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLineForEntry)(msteamsCfg, {
2480
- event: "command-output",
2481
- ...typeof payload?.itemId === "string" ? { itemId: payload.itemId } : {},
2482
- ...typeof payload?.toolCallId === "string" ? { toolCallId: payload.toolCallId } : {},
2483
- phase: payload.phase,
2484
- ...typeof payload?.title === "string" ? { title: payload.title } : {},
2485
- ...typeof payload?.name === "string" ? { name: payload.name } : {},
2486
- ...typeof payload?.status === "string" ? { status: payload.status } : {},
2487
- ...typeof payload?.exitCode === "number" ? { exitCode: payload.exitCode } : {}
2488
- }));
2489
- return false;
2490
- },
2491
- onPatchSummary: async (payload) => {
2492
- if (payload?.phase !== "end") return false;
2493
- await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLine)({
2494
- event: "patch",
2495
- ...typeof payload?.itemId === "string" ? { itemId: payload.itemId } : {},
2496
- ...typeof payload?.toolCallId === "string" ? { toolCallId: payload.toolCallId } : {},
2497
- phase: payload.phase,
2498
- ...typeof payload?.title === "string" ? { title: payload.title } : {},
2499
- ...typeof payload?.name === "string" ? { name: payload.name } : {},
2500
- ...Array.isArray(payload?.added) && payload.added.every((s) => typeof s === "string") ? { added: payload.added } : {},
2501
- ...Array.isArray(payload?.modified) && payload.modified.every((s) => typeof s === "string") ? { modified: payload.modified } : {},
2502
- ...Array.isArray(payload?.deleted) && payload.deleted.every((s) => typeof s === "string") ? { deleted: payload.deleted } : {},
2503
- ...typeof payload?.summary === "string" ? { summary: payload.summary } : {}
2504
- }));
2505
- return false;
2506
2511
  }
2507
2512
  } : {};
2508
2513
  return {
@@ -2512,6 +2517,8 @@ function createMSTeamsReplyDispatcher(params) {
2512
2517
  },
2513
2518
  delivery,
2514
2519
  replyOptions: {
2520
+ progressPreambleEnabled: shouldSuppressDefaultToolProgressMessages,
2521
+ commentaryProgressEnabled: shouldSuppressDefaultToolProgressMessages,
2515
2522
  ...streamController.hasStream() ? { onPartialReply: (payload) => {
2516
2523
  streamController.onPartialReply(payload);
2517
2524
  return false;
@@ -2574,7 +2581,7 @@ async function dispatchMSTeamsInboundTurn(params) {
2574
2581
  body: agentBody
2575
2582
  });
2576
2583
  const isRoomish = !isDirectMessage;
2577
- const historyKey = isRoomish ? conversationId : void 0;
2584
+ const historyKey = isRoomish ? facts.historyKey : void 0;
2578
2585
  if (isRoomish && historyKey) combinedBody = (0, openclaw_plugin_sdk_reply_history.createChannelHistoryWindow)({ historyMap: conversationHistories }).buildPendingContext({
2579
2586
  historyKey,
2580
2587
  limit: historyLimit,
@@ -2843,8 +2850,7 @@ function buildStoredConversationReference(params) {
2843
2850
  ...threadId ? { threadId } : {}
2844
2851
  };
2845
2852
  }
2846
- function assembleMSTeamsInboundFacts(params) {
2847
- const { entry, mediaMaxBytes } = params;
2853
+ function assembleMSTeamsInboundFacts(entry) {
2848
2854
  const activity = entry.context.activity;
2849
2855
  const conversation = activity.conversation;
2850
2856
  const rawConversationId = conversation?.id ?? "";
@@ -2854,10 +2860,7 @@ function assembleMSTeamsInboundFacts(params) {
2854
2860
  const isChannel = conversationType === "channel";
2855
2861
  const teamId = activity.channelData?.team?.id;
2856
2862
  const threadId = isChannel ? conversationMessageId ?? activity.replyToId ?? void 0 : void 0;
2857
- const advertisedMedia = resolveMSTeamsAdvertisedMedia(entry.attachments, {
2858
- maxInlineBytes: mediaMaxBytes,
2859
- maxInlineTotalBytes: mediaMaxBytes
2860
- });
2863
+ const advertisedMedia = resolveMSTeamsAdvertisedMedia(entry.attachments);
2861
2864
  return {
2862
2865
  ...entry,
2863
2866
  activity,
@@ -2876,6 +2879,7 @@ function assembleMSTeamsInboundFacts(params) {
2876
2879
  teamId,
2877
2880
  graphChannelId: activity.channelData?.channel?.id?.trim() || conversationId,
2878
2881
  threadId,
2882
+ historyKey: threadId ? `${conversationId}:thread:${threadId}` : conversationId,
2879
2883
  conversationRef: buildStoredConversationReference({
2880
2884
  activity,
2881
2885
  conversationId,
@@ -3149,7 +3153,7 @@ function createMSTeamsMessageHandler(deps) {
3149
3153
  cfg,
3150
3154
  channel: "msteams"
3151
3155
  });
3152
- const historyLimit = Math.max(0, msteamsCfg?.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? openclaw_plugin_sdk_reply_history.DEFAULT_GROUP_HISTORY_LIMIT);
3156
+ const historyLimit = (0, openclaw_plugin_sdk_number_runtime.resolvePromptHistoryLimit)(msteamsCfg?.historyLimit ?? cfg.messages?.groupChat?.historyLimit);
3153
3157
  const conversationHistories = /* @__PURE__ */ new Map();
3154
3158
  const readConfig = (0, openclaw_plugin_sdk_runtime_config_snapshot.createRuntimeConfigReader)(cfg);
3155
3159
  const resolveDebounceMs = () => core.channel.debounce.resolveInboundDebounceMs({
@@ -3157,10 +3161,7 @@ function createMSTeamsMessageHandler(deps) {
3157
3161
  channel: "msteams"
3158
3162
  });
3159
3163
  const handleTeamsMessageNow = async (params) => {
3160
- const facts = assembleMSTeamsInboundFacts({
3161
- entry: params,
3162
- mediaMaxBytes
3163
- });
3164
+ const facts = assembleMSTeamsInboundFacts(params);
3164
3165
  const { context, activity, rawText, text, attachments, advertisedMedia, rawBody, quoteInfo, from, conversation, attachmentTypes, htmlSummary, conversationId, conversationMessageId, conversationType, isChannel, teamId, conversationRef } = facts;
3165
3166
  const historyBody = [text, (0, openclaw_plugin_sdk_channel_inbound.formatMediaPlaceholderText)(advertisedMedia)].filter(Boolean).join("\n");
3166
3167
  log.info("received message", {
@@ -3262,7 +3263,7 @@ function createMSTeamsMessageHandler(deps) {
3262
3263
  if (historyBody) {
3263
3264
  enqueuePrimaryMessageSystemEvent();
3264
3265
  (0, openclaw_plugin_sdk_reply_history.createChannelHistoryWindow)({ historyMap: conversationHistories }).record({
3265
- historyKey: conversationId,
3266
+ historyKey: facts.historyKey,
3266
3267
  limit: historyLimit,
3267
3268
  entry: {
3268
3269
  sender: senderName,
@@ -3420,21 +3421,33 @@ function createMSTeamsReactionHandler(deps) {
3420
3421
  }
3421
3422
  const rawConversationId = activity.conversation?.id ?? "";
3422
3423
  const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
3423
- const conversationType = activity.conversation?.conversationType ?? "personal";
3424
- const isGroupChat = conversationType === "groupChat" || activity.conversation?.isGroup === true;
3425
- const isChannel = conversationType === "channel";
3426
- const isDirectMessage = !isGroupChat && !isChannel;
3424
+ const isChannel = activity.conversation?.conversationType === "channel";
3427
3425
  const senderId = from.aadObjectId ?? from.id;
3428
3426
  const senderName = from.name ?? from.id;
3427
+ const access = await resolveMSTeamsSenderAccess({
3428
+ cfg,
3429
+ activity
3430
+ });
3431
+ const { isDirectMessage, channelGate } = access;
3432
+ if (access.hasConflictingConversationScope) {
3433
+ log.info("dropping reaction (conflicting conversation scope)", { conversationId });
3434
+ return;
3435
+ }
3429
3436
  if (msteamsCfg) {
3430
- const senderAccess = await resolveMSTeamsSenderAccess({
3431
- cfg,
3432
- activity
3433
- });
3434
- if (senderAccess.senderAccess.decision !== "allow") {
3437
+ if (access.senderAccess.decision !== "allow") {
3435
3438
  log.debug?.("dropping reaction (access denied)", {
3436
3439
  sender: senderId,
3437
- reason: senderAccess.senderAccess.reasonCode
3440
+ reason: access.senderAccess.reasonCode
3441
+ });
3442
+ return;
3443
+ }
3444
+ if (!isDirectMessage && channelGate.allowlistConfigured && !channelGate.allowed) {
3445
+ log.info("dropping reaction (not in team/channel allowlist)", {
3446
+ conversationId,
3447
+ teamKey: channelGate.teamKey ?? "none",
3448
+ channelKey: channelGate.channelKey ?? "none",
3449
+ channelMatchKey: channelGate.channelMatchKey ?? "none",
3450
+ channelMatchSource: channelGate.channelMatchSource ?? "none"
3438
3451
  });
3439
3452
  return;
3440
3453
  }
@@ -3449,6 +3462,11 @@ function createMSTeamsReactionHandler(deps) {
3449
3462
  },
3450
3463
  ...teamId ? { teamId } : {}
3451
3464
  });
3465
+ const sessionKey = require_thread_session.resolveMSTeamsRouteSessionKey({
3466
+ baseSessionKey: route.sessionKey,
3467
+ isChannel,
3468
+ conversationMessageId: require_resolve_allowlist.extractMSTeamsConversationMessageId(rawConversationId)
3469
+ });
3452
3470
  const targetMessageId = activity.replyToId ?? "unknown";
3453
3471
  for (const reaction of reactions) {
3454
3472
  const reactionType = reaction.type ?? "unknown";
@@ -3462,7 +3480,7 @@ function createMSTeamsReactionHandler(deps) {
3462
3480
  conversationId
3463
3481
  });
3464
3482
  core.system.enqueueSystemEvent(label, {
3465
- sessionKey: route.sessionKey,
3483
+ sessionKey,
3466
3484
  contextKey: `msteams:reaction:${conversationId}:${targetMessageId}:${senderId}:${reactionType}:${direction}`
3467
3485
  });
3468
3486
  }
@@ -3523,8 +3541,15 @@ async function isInvokeAuthorized(params) {
3523
3541
  activity: context.activity
3524
3542
  });
3525
3543
  const { msteamsCfg, isDirectMessage, conversationId, senderId } = resolved;
3526
- if (!msteamsCfg) return true;
3527
3544
  const maybeInvokeName = includeInvokeName ? { name: context.activity.name } : void 0;
3545
+ if (resolved.hasConflictingConversationScope) {
3546
+ deps.log.info("dropping invoke (conflicting conversation scope)", {
3547
+ conversationId,
3548
+ ...maybeInvokeName
3549
+ });
3550
+ return false;
3551
+ }
3552
+ if (!msteamsCfg) return true;
3528
3553
  if (isDirectMessage && resolved.senderAccess.decision !== "allow") {
3529
3554
  deps.log.debug?.(deniedLogs.dm, {
3530
3555
  sender: senderId,
@@ -1,5 +1,5 @@
1
1
  const require_runtime = require("./runtime-gZTAuFux.cjs");
2
- const require_polls = require("./polls-BBdZPx_R.cjs");
2
+ const require_polls = require("./polls-BJ4-4uZm.cjs");
3
3
  let node_crypto = require("node:crypto");
4
4
  //#region extensions/msteams/src/sso-token-store.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-DmUTQxEz.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
2
2
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
3
3
  let openclaw_plugin_sdk_approval_auth_runtime = require("openclaw/plugin-sdk/approval-auth-runtime");
4
4
  let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
package/dist/api.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_channel = require("./channel-B9LIyYeu.cjs");
3
- const require_channel_setup = require("./channel.setup-BhxokviI.cjs");
2
+ const require_channel = require("./.setup/channel-BDp16XRR.cjs");
3
+ const require_channel_setup = require("./.setup/channel.setup-BVDfgdCc.cjs");
4
4
  exports.createMSTeamsSetupWizardBase = require_channel_setup.createMSTeamsSetupWizardBase;
5
5
  exports.msteamsPlugin = require_channel.msteamsPlugin;
6
6
  exports.msteamsSetupAdapter = require_channel_setup.msteamsSetupAdapter;
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_config_schema = require("./config-schema-D22Lr1Qk.cjs");
2
+ const require_config_schema = require("./.setup/config-schema-D22Lr1Qk.cjs");
3
3
  exports.MSTeamsChannelConfigSchema = require_config_schema.MSTeamsChannelConfigSchema;
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_channel = require("./channel-B9LIyYeu.cjs");
2
+ const require_channel = require("./.setup/channel-BDp16XRR.cjs");
3
3
  exports.msteamsPlugin = require_channel.msteamsPlugin;
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- require("./secret-input-C65t6kjM.cjs");
2
+ require("./.setup/secret-input-C65t6kjM.cjs");
3
3
  let openclaw_plugin_sdk_secret_input = require("openclaw/plugin-sdk/secret-input");
4
4
  //#region extensions/msteams/configured-state.ts
5
5
  /** Mirror Teams auth-mode requirements without loading the Azure SDK or full channel. */
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_resolve_allowlist = require("./resolve-allowlist-DmUTQxEz.cjs");
2
+ const require_resolve_allowlist = require("./.setup/resolve-allowlist-CHzaaWiC.cjs");
3
3
  let openclaw_plugin_sdk_directory_runtime = require("openclaw/plugin-sdk/directory-runtime");
4
4
  const msteamsDirectoryContractPlugin = {
5
5
  id: "msteams",