@openclaw/msteams 2026.10.2 → 2026.10.5-beta.2

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 (26) hide show
  1. package/dist/.setup/{adapter.runtime-D0HYByze.cjs → adapter.runtime-JoPydWqP.cjs} +1 -1
  2. package/dist/.setup/{approval-handler.runtime-C-RJ3wXc.cjs → approval-handler.runtime-bUN9icMr.cjs} +3 -3
  3. package/dist/.setup/{bot-framework-service-url-BUhTe8F3.cjs → bot-framework-service-url-CPp4d-Q6.cjs} +1 -5
  4. package/dist/.setup/{channel-BFhXodl2.cjs → channel-Cifn9fsv.cjs} +230 -430
  5. package/dist/.setup/{channel.runtime-D9jrw2SN.cjs → channel.runtime-DWRAolil.cjs} +70 -44
  6. package/dist/.setup/{channel.setup-ss0TO-ap.cjs → channel.setup-BjbHugkL.cjs} +5 -7
  7. package/dist/.setup/{config-schema-0KoBzb0t.cjs → config-schema-Dk0mRIam.cjs} +1 -1
  8. package/dist/.setup/{conversation-store-state-f7V8CVNy.cjs → conversation-store-state-DprmOfl7.cjs} +103 -236
  9. package/dist/.setup/{monitor-DfSPCRkk.cjs → monitor-C9x_CJhY.cjs} +173 -322
  10. package/dist/.setup/oauth-CWJ85AMw.cjs +55 -0
  11. package/dist/.setup/{reaction-types-B-GEv57k.cjs → reaction-types-Ig9sQJuR.cjs} +3 -3
  12. package/dist/.setup/{resolve-allowlist-Ct9yxQUw.cjs → resolve-allowlist-DdDBVCzl.cjs} +77 -174
  13. package/dist/.setup/{send-7VV1iCai.cjs → send-rJpcVtRp.cjs} +8 -9
  14. package/dist/.setup/{setup-plugin-api-B0OFG32J.cjs → setup-plugin-api-DfoVOqMJ.cjs} +1 -1
  15. package/dist/.setup/{thread-session-ClI-lSyG.cjs → thread-session-B74FC1Id.cjs} +1 -1
  16. package/dist/.setup/{token-config-DOt3XwVa.cjs → token-config-CqIh8z7Q.cjs} +6 -7
  17. package/dist/api.cjs +2 -2
  18. package/dist/channel-config-api.cjs +1 -1
  19. package/dist/channel-plugin-api.cjs +1 -1
  20. package/dist/directory-contract-api.cjs +2 -2
  21. package/dist/doctor-contract-api.cjs +1 -1
  22. package/dist/qa-runner-api.cjs +9 -10
  23. package/dist/setup-entry.cjs +1 -1
  24. package/dist/setup-plugin-api.cjs +1 -1
  25. package/package.json +4 -4
  26. package/dist/.setup/oauth-CYxMYIOQ.cjs +0 -102
@@ -1,9 +1,9 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-BloeesfJ.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("../runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-Ct9yxQUw.cjs");
5
- const require_bot_framework_service_url = require("./bot-framework-service-url-BUhTe8F3.cjs");
6
- const require_channel_setup = require("./channel.setup-ss0TO-ap.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-DdDBVCzl.cjs");
5
+ const require_bot_framework_service_url = require("./bot-framework-service-url-CPp4d-Q6.cjs");
6
+ const require_channel_setup = require("./channel.setup-BjbHugkL.cjs");
7
7
  let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
8
8
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
9
9
  let openclaw_plugin_sdk_fetch_runtime = require("openclaw/plugin-sdk/fetch-runtime");
@@ -53,21 +53,15 @@ const CONSENT_UPLOAD_HOST_ALLOWLIST = [
53
53
  "graph.microsoft.de",
54
54
  "graph.microsoft.cn"
55
55
  ];
56
- async function validateConsentUploadUrl(url, opts) {
57
- let parsed;
58
- try {
59
- parsed = new URL(url);
60
- } catch {
61
- throw new Error("Consent upload URL is not a valid URL");
62
- }
56
+ async function validateConsentUploadUrl(url) {
57
+ const parsed = URL.parse(url);
58
+ if (!parsed) throw new Error("Consent upload URL is not a valid URL");
63
59
  if (parsed.protocol !== "https:") throw new Error(`Consent upload URL must use HTTPS, got ${parsed.protocol}`);
64
60
  const hostname = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(parsed.hostname);
65
- if (!(opts?.allowlist ?? CONSENT_UPLOAD_HOST_ALLOWLIST).some((entry) => hostname === entry || hostname.endsWith(`.${entry}`))) throw new Error(`Consent upload URL hostname "${hostname}" is not in the allowed domains`);
66
- const resolveFn = opts?.resolveFn ?? ((name) => (0, node_dns_promises.lookup)(name, { all: true }));
61
+ if (!CONSENT_UPLOAD_HOST_ALLOWLIST.some((entry) => hostname === entry || hostname.endsWith(`.${entry}`))) throw new Error(`Consent upload URL hostname "${hostname}" is not in the allowed domains`);
67
62
  let resolved;
68
63
  try {
69
- const result = await resolveFn(hostname);
70
- resolved = Array.isArray(result) ? result : [result];
64
+ resolved = await (0, node_dns_promises.lookup)(hostname, { all: true });
71
65
  } catch {
72
66
  throw new Error(`Failed to resolve consent upload URL hostname "${hostname}"`);
73
67
  }
@@ -125,8 +119,7 @@ function parseFileConsentInvoke(activity) {
125
119
  * The URL is provided in the fileConsent/invoke response after user accepts.
126
120
  */
127
121
  async function uploadToConsentUrl(params) {
128
- await validateConsentUploadUrl(params.url, params.validationOpts);
129
- const fetchFn = params.fetchFn ?? fetch;
122
+ await validateConsentUploadUrl(params.url);
130
123
  const res = await (0, openclaw_plugin_sdk_text_utility_runtime.fetchWithTimeout)(params.url, {
131
124
  method: "PUT",
132
125
  headers: {
@@ -135,34 +128,16 @@ async function uploadToConsentUrl(params) {
135
128
  "Content-Range": `bytes 0-${params.buffer.length - 1}/${params.buffer.length}`
136
129
  },
137
130
  body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)])
138
- }, params.timeoutMs ?? require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length), fetchFn);
131
+ }, require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length));
139
132
  await res.body?.cancel().catch(() => void 0);
140
133
  if (!res.ok) throw new Error(`File upload to consent URL failed: ${res.status} ${res.statusText}`);
141
134
  }
142
135
  //#endregion
143
136
  //#region extensions/msteams/src/sqlite-state.ts
144
- function resolveStateDirOverride(options) {
145
- if (!options) return;
146
- if (options.stateDir) return options.stateDir;
147
- if (options.storePath) return node_path.default.dirname(options.storePath);
148
- if (options.homedir) return require_runtime.getMSTeamsRuntime().state.resolveStateDir(options.env ?? process.env, options.homedir);
149
- return options.env?.OPENCLAW_STATE_DIR?.trim() || void 0;
150
- }
151
- function resolveMSTeamsSqliteStateEnv(options) {
152
- const stateDir = resolveStateDirOverride(options);
153
- if (!stateDir) return options?.env;
154
- return {
155
- ...options?.env ?? process.env,
156
- OPENCLAW_STATE_DIR: stateDir
157
- };
158
- }
159
137
  function toPluginJsonValue(value) {
160
138
  const serialized = JSON.stringify(value);
161
139
  return JSON.parse(serialized);
162
140
  }
163
- function resolveMSTeamsSqliteStateDir(options) {
164
- return resolveStateDirOverride(options) ?? require_runtime.getMSTeamsRuntime().state.resolveStateDir(options?.env ?? process.env, options?.homedir);
165
- }
166
141
  const sqliteMutationLocks = new openclaw_plugin_sdk_keyed_async_queue.KeyedAsyncQueue();
167
142
  const MSTEAMS_MUTATION_LOCK_OPTIONS = {
168
143
  retries: {
@@ -174,11 +149,9 @@ const MSTEAMS_MUTATION_LOCK_OPTIONS = {
174
149
  },
175
150
  stale: 3e4
176
151
  };
177
- async function withMSTeamsSqliteMutationLock(options, mutationKey, fn) {
178
- const scopedMutationKey = node_path.default.join(resolveMSTeamsSqliteStateDir(options), mutationKey);
179
- return await sqliteMutationLocks.enqueue(scopedMutationKey, async () => {
180
- return await (0, openclaw_plugin_sdk_file_lock.withFileLock)(scopedMutationKey, MSTEAMS_MUTATION_LOCK_OPTIONS, fn);
181
- });
152
+ async function withMSTeamsSqliteMutationLock(mutationKey, fn) {
153
+ const scopedMutationKey = node_path.default.join(require_runtime.getMSTeamsRuntime().state.resolveStateDir(), mutationKey);
154
+ return await sqliteMutationLocks.enqueue(scopedMutationKey, () => (0, openclaw_plugin_sdk_file_lock.withFileLock)(scopedMutationKey, MSTEAMS_MUTATION_LOCK_OPTIONS, fn));
182
155
  }
183
156
  //#endregion
184
157
  //#region extensions/msteams/src/pending-uploads-fs.ts
@@ -193,18 +166,16 @@ const PENDING_UPLOAD_META_MAX_ENTRIES = 200;
193
166
  const PENDING_UPLOAD_META_NAMESPACE = "pending-uploads";
194
167
  const PENDING_UPLOAD_CHUNKS_NAMESPACE = "pending-upload-chunks";
195
168
  const PENDING_UPLOAD_MUTATION_KEY = "pending-uploads";
196
- function createMetaStore(options) {
169
+ function createMetaStore() {
197
170
  return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
198
171
  namespace: PENDING_UPLOAD_META_NAMESPACE,
199
- maxEntries: PENDING_UPLOAD_META_MAX_ENTRIES,
200
- env: resolveMSTeamsSqliteStateEnv(options)
172
+ maxEntries: PENDING_UPLOAD_META_MAX_ENTRIES
201
173
  });
202
174
  }
203
- function createChunkStore(options) {
175
+ function createChunkStore() {
204
176
  return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
205
177
  namespace: PENDING_UPLOAD_CHUNKS_NAMESPACE,
206
- maxEntries: MAX_PENDING_UPLOAD_CHUNK_ROWS,
207
- env: resolveMSTeamsSqliteStateEnv(options)
178
+ maxEntries: MAX_PENDING_UPLOAD_CHUNK_ROWS
208
179
  });
209
180
  }
210
181
  function buildUploadKey(id) {
@@ -234,12 +205,12 @@ async function deleteUploadRows(id, metaStore, chunkStore) {
234
205
  const chunkCount = existing.chunkCount;
235
206
  for (let index = 0; index < chunkCount; index += 1) await chunkStore.delete(buildChunkKey(id, index));
236
207
  }
237
- async function registerUploadRows(record, metaStore, chunkStore, ttlMs) {
208
+ async function registerUploadRows(record, metaStore, chunkStore) {
238
209
  const buffer = Buffer.from(record.buffer);
239
210
  const chunkCount = Math.max(1, Math.ceil(buffer.byteLength / RAW_CHUNK_BYTES));
240
211
  if (chunkCount > MAX_CHUNKS_PER_UPLOAD) throw new Error(`Microsoft Teams pending upload ${record.id} exceeds SQLite chunk limit (${chunkCount}/${MAX_CHUNKS_PER_UPLOAD})`);
241
212
  await deleteUploadRows(record.id, metaStore, chunkStore);
242
- await pruneUploadStore(metaStore, chunkStore, ttlMs, chunkCount);
213
+ await pruneUploadStore(metaStore, chunkStore, chunkCount);
243
214
  for (let index = 0; index < chunkCount; index += 1) {
244
215
  const chunk = buffer.subarray(index * RAW_CHUNK_BYTES, (index + 1) * RAW_CHUNK_BYTES);
245
216
  await chunkStore.register(buildChunkKey(record.id, index), toPluginJsonValue({
@@ -259,9 +230,6 @@ async function registerUploadRows(record, metaStore, chunkStore, ttlMs) {
259
230
  byteLength: buffer.byteLength
260
231
  }));
261
232
  }
262
- async function withPendingUploadLock(options, run) {
263
- return await withMSTeamsSqliteMutationLock(options, PENDING_UPLOAD_MUTATION_KEY, run);
264
- }
265
233
  async function readUploadRows(id, metaStore, chunkStore) {
266
234
  const meta = await metaStore.lookup(buildMetaKey(id));
267
235
  if (!meta) return;
@@ -277,13 +245,13 @@ async function readUploadRows(id, metaStore, chunkStore) {
277
245
  }
278
246
  return recordToUpload(meta, Buffer.concat(chunks, meta.byteLength));
279
247
  }
280
- async function pruneUploadStore(metaStore, chunkStore, ttlMs, extraChunkRows = 0) {
248
+ async function pruneUploadStore(metaStore, chunkStore, extraChunkRows = 0) {
281
249
  const rows = await metaStore.entries();
282
250
  const liveRows = [];
283
251
  const now = Date.now();
284
252
  let liveChunkRows = 0;
285
253
  for (const row of rows) {
286
- if (now - row.value.createdAt > ttlMs) {
254
+ if (now - row.value.createdAt > PENDING_UPLOAD_TTL_MS$1) {
287
255
  await deleteUploadRows(row.value.id, metaStore, chunkStore);
288
256
  continue;
289
257
  }
@@ -304,11 +272,10 @@ async function pruneUploadStore(metaStore, chunkStore, ttlMs, extraChunkRows = 0
304
272
  * Pass in the pre-generated id (same as the one placed in the consent card
305
273
  * context) so the in-memory and FS stores share the same key.
306
274
  */
307
- async function storePendingUploadFs(upload, options) {
308
- const ttlMs = options?.ttlMs ?? PENDING_UPLOAD_TTL_MS$1;
309
- const metaStore = createMetaStore(options);
310
- const chunkStore = createChunkStore(options);
311
- await withPendingUploadLock(options, async () => {
275
+ async function storePendingUploadFs(upload) {
276
+ const metaStore = createMetaStore();
277
+ const chunkStore = createChunkStore();
278
+ await withMSTeamsSqliteMutationLock(PENDING_UPLOAD_MUTATION_KEY, async () => {
312
279
  await registerUploadRows({
313
280
  id: upload.id,
314
281
  buffer: upload.buffer,
@@ -317,35 +284,33 @@ async function storePendingUploadFs(upload, options) {
317
284
  conversationId: upload.conversationId,
318
285
  consentCardActivityId: upload.consentCardActivityId,
319
286
  createdAt: Date.now()
320
- }, metaStore, chunkStore, ttlMs);
321
- await pruneUploadStore(metaStore, chunkStore, ttlMs);
287
+ }, metaStore, chunkStore);
288
+ await pruneUploadStore(metaStore, chunkStore);
322
289
  });
323
290
  }
324
- async function getPendingUploadFs(id, options) {
291
+ async function getPendingUploadFs(id) {
325
292
  if (!id) return;
326
- const ttlMs = options?.ttlMs ?? PENDING_UPLOAD_TTL_MS$1;
327
- const upload = await readUploadRows(id, createMetaStore(options), createChunkStore(options));
293
+ const upload = await readUploadRows(id, createMetaStore(), createChunkStore());
328
294
  if (!upload) return;
329
- if (Date.now() - upload.createdAt > ttlMs) {
330
- await removePendingUploadFs(id, options);
295
+ if (Date.now() - upload.createdAt > PENDING_UPLOAD_TTL_MS$1) {
296
+ await removePendingUploadFs(id);
331
297
  return;
332
298
  }
333
299
  return upload;
334
300
  }
335
- async function removePendingUploadFs(id, options) {
301
+ async function removePendingUploadFs(id) {
336
302
  if (!id) return;
337
- const metaStore = createMetaStore(options);
338
- const chunkStore = createChunkStore(options);
339
- await withPendingUploadLock(options, async () => {
303
+ const metaStore = createMetaStore();
304
+ const chunkStore = createChunkStore();
305
+ await withMSTeamsSqliteMutationLock(PENDING_UPLOAD_MUTATION_KEY, async () => {
340
306
  await deleteUploadRows(id, metaStore, chunkStore);
341
307
  });
342
308
  }
343
- async function setPendingUploadActivityIdFs(id, activityId, options) {
344
- const ttlMs = options?.ttlMs ?? PENDING_UPLOAD_TTL_MS$1;
345
- const metaStore = createMetaStore(options);
346
- await withPendingUploadLock(options, async () => {
309
+ async function setPendingUploadActivityIdFs(id, activityId) {
310
+ const metaStore = createMetaStore();
311
+ await withMSTeamsSqliteMutationLock(PENDING_UPLOAD_MUTATION_KEY, async () => {
347
312
  const record = await metaStore.lookup(buildMetaKey(id));
348
- if (!record || Date.now() - record.createdAt > ttlMs) return;
313
+ if (!record || Date.now() - record.createdAt > PENDING_UPLOAD_TTL_MS$1) return;
349
314
  await metaStore.register(buildMetaKey(id), toPluginJsonValue({
350
315
  ...record,
351
316
  consentCardActivityId: activityId
@@ -421,18 +386,6 @@ function setPendingUploadActivityId(uploadId, activityId) {
421
386
  //#endregion
422
387
  //#region extensions/msteams/src/file-consent-helpers.ts
423
388
  const FILE_CONSENT_THRESHOLD_BYTES = 4194304;
424
- function buildConsentActivity(params) {
425
- const { media, description, uploadId } = params;
426
- return {
427
- type: "message",
428
- attachments: [buildFileConsentCard({
429
- filename: media.filename,
430
- description: description || `File: ${media.filename}`,
431
- sizeInBytes: media.buffer.length,
432
- context: { uploadId }
433
- })]
434
- };
435
- }
436
389
  /** In-process replies keep consent bytes in memory; CLI sends use the persisted variant below. */
437
390
  function prepareFileConsentActivity(params) {
438
391
  const { media, conversationId, description } = params;
@@ -443,11 +396,15 @@ function prepareFileConsentActivity(params) {
443
396
  conversationId
444
397
  });
445
398
  return {
446
- activity: buildConsentActivity({
447
- media,
448
- description,
449
- uploadId
450
- }),
399
+ activity: {
400
+ type: "message",
401
+ attachments: [buildFileConsentCard({
402
+ filename: media.filename,
403
+ description: description || `File: ${media.filename}`,
404
+ sizeInBytes: media.buffer.length,
405
+ context: { uploadId }
406
+ })]
407
+ },
451
408
  uploadId
452
409
  };
453
410
  }
@@ -521,30 +478,8 @@ function restoreTokens(text, prefix, values) {
521
478
  return text.replace(new RegExp(`${escapedPrefix}(\\d+)${TOKEN_END}`, "gu"), (_token, index) => values[Number(index)] ?? "");
522
479
  }
523
480
  function rewriteMarkdownIR(ir, edits) {
524
- const ordered = edits.toSorted((a, b) => a.start - b.start);
525
- const cumulativeDeltas = [];
526
- const exactEdits = /* @__PURE__ */ new Map();
527
- let text = "";
528
- let cursor = 0;
529
- let delta = 0;
530
- for (const edit of ordered) {
531
- text += ir.text.slice(cursor, edit.start) + edit.text;
532
- cursor = edit.end;
533
- delta += edit.text.length - (edit.end - edit.start);
534
- cumulativeDeltas.push(delta);
535
- exactEdits.set(`${edit.start}:${edit.end}`, edit);
536
- }
537
- text += ir.text.slice(cursor);
538
- const mapOffset = (offset) => {
539
- let low = 0;
540
- let high = ordered.length;
541
- while (low < high) {
542
- const middle = low + Math.floor((high - low) / 2);
543
- if ((ordered[middle]?.end ?? Number.POSITIVE_INFINITY) <= offset) low = middle + 1;
544
- else high = middle;
545
- }
546
- return offset + (low > 0 ? cumulativeDeltas[low - 1] ?? 0 : 0);
547
- };
481
+ const { text, mapOffset } = (0, openclaw_plugin_sdk_text_chunking.applyMarkdownTextEdits)(ir.text, edits);
482
+ const exactEdits = new Map(edits.map((edit) => [`${edit.start}:${edit.end}`, edit]));
548
483
  const mapRange = (range) => {
549
484
  const exact = exactEdits.get(`${range.start}:${range.end}`);
550
485
  const start = mapOffset(range.start);
@@ -824,7 +759,6 @@ async function requestSharePointJson(params, request) {
824
759
  },
825
760
  signal
826
761
  },
827
- fetchImpl: params.fetchFn,
828
762
  mode: "trusted_env_proxy",
829
763
  beforeRequest: () => require_resolve_allowlist.assertMSTeamsSendHandoff(params),
830
764
  maxRedirects: 20,
@@ -883,13 +817,12 @@ async function getChatMemberIds(params) {
883
817
  * For per-user scope, uses beta API with recipients.
884
818
  */
885
819
  async function createSharePointSharingLink(params) {
886
- const scope = params.scope ?? "organization";
887
- const apiRoot = scope === "users" ? GRAPH_BETA : GRAPH_ROOT;
820
+ const apiRoot = params.recipientObjectIds ? GRAPH_BETA : GRAPH_ROOT;
888
821
  const body = {
889
822
  type: "view",
890
- scope: scope === "users" ? "users" : "organization"
823
+ scope: params.recipientObjectIds ? "users" : "organization"
891
824
  };
892
- if (scope === "users" && params.recipientObjectIds?.length) body.recipients = params.recipientObjectIds.map((id) => ({ objectId: id }));
825
+ if (params.recipientObjectIds) body.recipients = params.recipientObjectIds.map((id) => ({ objectId: id }));
893
826
  const data = await requestSharePointJson(params, {
894
827
  url: `${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`,
895
828
  init: () => ({
@@ -911,25 +844,20 @@ async function createSharePointSharingLink(params) {
911
844
  */
912
845
  async function uploadAndShareSharePoint(params) {
913
846
  const uploaded = await uploadToSharePoint(params);
914
- let scope = "organization";
915
847
  let recipientObjectIds;
916
848
  if (params.usePerUserSharing && params.chatId) {
917
849
  recipientObjectIds = await getChatMemberIds({
918
850
  chatId: params.chatId,
919
851
  tokenProvider: params.tokenProvider,
920
- fetchFn: params.fetchFn,
921
852
  assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
922
853
  });
923
854
  if (recipientObjectIds.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
924
- scope = "users";
925
855
  }
926
856
  const shareUrl = await createSharePointSharingLink({
927
857
  siteId: params.siteId,
928
858
  itemId: uploaded.id,
929
859
  tokenProvider: params.tokenProvider,
930
- scope,
931
860
  recipientObjectIds,
932
- fetchFn: params.fetchFn,
933
861
  assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
934
862
  });
935
863
  return {
@@ -1233,6 +1161,8 @@ async function deleteMSTeamsActivityWithReference(app, source, activityId, optio
1233
1161
  }
1234
1162
  //#endregion
1235
1163
  //#region extensions/msteams/src/messenger.ts
1164
+ const MSTEAMS_SEND_ATTEMPTS = 3;
1165
+ const MSTEAMS_SEND_RETRY_MAX_DELAY_MS = 1e4;
1236
1166
  function buildConversationReference(ref) {
1237
1167
  const conversationId = ref.conversation?.id?.trim();
1238
1168
  if (!conversationId) throw new Error("Invalid stored reference: missing conversation.id");
@@ -1261,64 +1191,21 @@ function buildConversationReference(ref) {
1261
1191
  ...aadObjectId ? { aadObjectId } : {}
1262
1192
  };
1263
1193
  }
1264
- function pushTextMessages(out, text, opts) {
1265
- if (!text) return;
1266
- const chunks = opts.chunkText ? require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(text, opts.chunkLimit, opts.chunkMode) : [text];
1267
- for (const chunk of chunks) {
1268
- const trimmed = chunk.trim();
1269
- if (trimmed && !(0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) out.push({ text: trimmed });
1270
- }
1271
- }
1272
- function clampMs(value, maxMs) {
1273
- if (!Number.isFinite(value) || value < 0) return 0;
1274
- return Math.min(value, maxMs);
1275
- }
1276
- function resolveRetryOptions(retry) {
1277
- if (!retry) return {
1278
- enabled: false,
1279
- maxAttempts: 1,
1280
- baseDelayMs: 0,
1281
- maxDelayMs: 0
1282
- };
1283
- return {
1284
- enabled: true,
1285
- maxAttempts: Math.max(1, retry.maxAttempts ?? 3),
1286
- baseDelayMs: Math.max(0, retry.baseDelayMs ?? 250),
1287
- maxDelayMs: Math.max(0, retry.maxDelayMs ?? 1e4)
1288
- };
1289
- }
1290
- function computeRetryDelayMs(attempt, classification, opts) {
1291
- if (classification.kind === "replay-safe" && classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
1292
- return clampMs(opts.baseDelayMs * 2 ** Math.max(0, attempt - 1), opts.maxDelayMs);
1293
- }
1294
1194
  function renderReplyPayloadsToMessages(replies, options) {
1295
1195
  const out = [];
1296
1196
  const chunkLimit = Math.min(options.textChunkLimit, 4e3);
1297
- const chunkText = options.chunkText !== false;
1298
1197
  const chunkMode = options.chunkMode ?? "length";
1299
- const mediaMode = options.mediaMode ?? "split";
1300
- const tableMode = options.tableMode ?? require_runtime.getMSTeamsRuntime().channel.text.resolveMarkdownTableMode({
1301
- cfg: require_runtime.getMSTeamsRuntime().config.current(),
1302
- channel: "msteams"
1303
- });
1304
1198
  for (const payload of replies) {
1305
- const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: formatMSTeamsMarkdown(payload.text ?? "", tableMode) });
1199
+ const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: formatMSTeamsMarkdown(payload.text ?? "", options.tableMode) });
1306
1200
  if (!reply.hasContent) continue;
1307
- const [firstMedia, ...remainingMedia] = reply.mediaUrls;
1308
- if (mediaMode === "inline" && firstMedia) {
1309
- out.push({
1310
- text: reply.text || void 0,
1311
- mediaUrl: firstMedia
1312
- });
1313
- out.push(...remainingMedia.map((mediaUrl) => ({ mediaUrl })));
1314
- } else {
1315
- pushTextMessages(out, reply.text, {
1316
- chunkText,
1317
- chunkLimit,
1318
- chunkMode
1319
- });
1320
- out.push(...reply.mediaUrls.map((mediaUrl) => ({ mediaUrl })));
1201
+ if (reply.text) {
1202
+ const chunks = require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(reply.text, chunkLimit, chunkMode);
1203
+ for (const chunk of chunks) {
1204
+ const text = chunk.trim();
1205
+ if (text && !(0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(text, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) out.push({ text });
1206
+ }
1321
1207
  }
1208
+ out.push(...reply.mediaUrls.map((mediaUrl) => ({ mediaUrl })));
1322
1209
  }
1323
1210
  return out;
1324
1211
  }
@@ -1392,35 +1279,13 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1392
1279
  async function sendMSTeamsMessages(params) {
1393
1280
  const messages = params.messages.filter((m) => m.text && m.text.trim().length > 0 || m.mediaUrl);
1394
1281
  if (messages.length === 0) return [];
1395
- const retryOptions = resolveRetryOptions(params.retry);
1396
- const sendWithRetry = async (sendOnce, meta) => {
1397
- if (!retryOptions.enabled) return await sendOnce();
1398
- return await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(sendOnce, {
1399
- attempts: retryOptions.maxAttempts,
1400
- minDelayMs: 0,
1401
- maxDelayMs: retryOptions.maxDelayMs,
1402
- shouldRetry: (err) => require_channel_setup.classifyMSTeamsSendError(err).kind === "replay-safe",
1403
- delayMs: ({ attempt, err }) => computeRetryDelayMs(attempt, require_channel_setup.classifyMSTeamsSendError(err), retryOptions),
1404
- onRetry: ({ attempt, err, delayMs }) => {
1405
- params.onRetry?.({
1406
- messageIndex: meta.messageIndex,
1407
- messageCount: meta.messageCount,
1408
- nextAttempt: attempt + 1,
1409
- maxAttempts: retryOptions.maxAttempts,
1410
- delayMs,
1411
- classification: require_channel_setup.classifyMSTeamsSendError(err)
1412
- });
1413
- },
1414
- sleep: (delayMs) => (0, openclaw_plugin_sdk_runtime_env.sleepWithAbort)(delayMs)
1415
- });
1416
- };
1417
1282
  let providerDispatchStarted = false;
1418
1283
  const sendMessageInContext = async (sendFn, message, messageIndex) => {
1419
1284
  let activity;
1420
1285
  let pendingUploadId;
1421
1286
  let response;
1422
1287
  try {
1423
- response = await sendWithRetry(async () => {
1288
+ response = await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(async () => {
1424
1289
  require_resolve_allowlist.assertMSTeamsSendHandoff(params);
1425
1290
  activity ??= await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, {
1426
1291
  feedbackLoopEnabled: params.feedbackLoopEnabled,
@@ -1432,8 +1297,26 @@ async function sendMSTeamsMessages(params) {
1432
1297
  providerDispatchStarted = true;
1433
1298
  return await sendFn(activity);
1434
1299
  }, {
1435
- messageIndex,
1436
- messageCount: messages.length
1300
+ attempts: MSTEAMS_SEND_ATTEMPTS,
1301
+ minDelayMs: 0,
1302
+ maxDelayMs: MSTEAMS_SEND_RETRY_MAX_DELAY_MS,
1303
+ shouldRetry: (err) => require_channel_setup.classifyMSTeamsSendError(err).kind === "replay-safe",
1304
+ delayMs: ({ attempt, err }) => {
1305
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
1306
+ const retryAfterMs = classification.kind === "replay-safe" ? classification.retryAfterMs : void 0;
1307
+ return Math.min(retryAfterMs ?? 250 * 2 ** (attempt - 1), MSTEAMS_SEND_RETRY_MAX_DELAY_MS);
1308
+ },
1309
+ onRetry: ({ attempt, err, delayMs }) => {
1310
+ params.onRetry?.({
1311
+ messageIndex,
1312
+ messageCount: messages.length,
1313
+ nextAttempt: attempt + 1,
1314
+ maxAttempts: MSTEAMS_SEND_ATTEMPTS,
1315
+ delayMs,
1316
+ classification: require_channel_setup.classifyMSTeamsSendError(err)
1317
+ });
1318
+ },
1319
+ sleep: (delayMs) => (0, openclaw_plugin_sdk_runtime_env.sleepWithAbort)(delayMs)
1437
1320
  });
1438
1321
  } catch (error) {
1439
1322
  if (!providerDispatchStarted && !(error instanceof openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError)) throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams activity preparation failed", { cause: error });
@@ -1561,7 +1444,7 @@ function extractMSTeamsPollVote(activity) {
1561
1444
  };
1562
1445
  }
1563
1446
  function buildMSTeamsPollCard(params) {
1564
- const pollId = params.pollId ?? node_crypto.default.randomUUID();
1447
+ const pollId = node_crypto.default.randomUUID();
1565
1448
  const maxSelections = typeof params.maxSelections === "number" && params.maxSelections > 1 ? Math.floor(params.maxSelections) : 1;
1566
1449
  const cappedMaxSelections = Math.min(Math.max(1, maxSelections), params.options.length);
1567
1450
  const choices = params.options.map((option, index) => ({
@@ -1615,27 +1498,13 @@ function buildMSTeamsPollCard(params) {
1615
1498
  fallbackText: fallbackLines.join("\n")
1616
1499
  };
1617
1500
  }
1618
- function createPollStateStore(params) {
1619
- return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1620
- namespace: MSTEAMS_POLLS_NAMESPACE,
1621
- maxEntries: MSTEAMS_SQLITE_MAX_POLL_ROWS,
1622
- env: resolveMSTeamsSqliteStateEnv(params)
1623
- });
1624
- }
1625
- function createPollVoteBucketStateStore(params) {
1626
- return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1627
- namespace: MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE,
1628
- maxEntries: MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS,
1629
- env: resolveMSTeamsSqliteStateEnv(params)
1630
- });
1631
- }
1632
1501
  function isPollExpired(poll) {
1633
1502
  const cutoff = Date.now() - MSTEAMS_POLL_TTL_MS;
1634
1503
  return !(((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(poll.updatedAt ?? poll.createdAt) ?? 0) >= cutoff);
1635
1504
  }
1636
1505
  function normalizeMSTeamsPollSelections(poll, selections) {
1637
1506
  const maxSelections = Math.max(1, poll.maxSelections);
1638
- const mapped = selections.map((entry) => (0, openclaw_plugin_sdk_number_runtime.parseStrictNonNegativeInteger)(entry)).filter((value) => value !== void 0).filter((value) => value >= 0 && value < poll.options.length).map((value) => String(value));
1507
+ const mapped = selections.map((entry) => (0, openclaw_plugin_sdk_number_runtime.parseStrictNonNegativeInteger)(entry)).filter((value) => value !== void 0 && value < poll.options.length).map((value) => String(value));
1639
1508
  return (0, openclaw_plugin_sdk_string_coerce_runtime.uniqueStrings)(mapped).slice(0, maxSelections);
1640
1509
  }
1641
1510
  function hashMSTeamsPollVote(pollId, voterId) {
@@ -1651,9 +1520,15 @@ function selectMSTeamsPollVoteBucket(pollId, voterId) {
1651
1520
  function buildMSTeamsPollVoteBucketKey(pollId, bucket) {
1652
1521
  return `${buildMSTeamsPollStateKey(pollId)}:${bucket}`;
1653
1522
  }
1654
- function createMSTeamsPollStoreState(params) {
1655
- const pollStore = createPollStateStore(params);
1656
- const voteBucketStore = createPollVoteBucketStateStore(params);
1523
+ function createMSTeamsPollStoreState() {
1524
+ const pollStore = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1525
+ namespace: MSTEAMS_POLLS_NAMESPACE,
1526
+ maxEntries: MSTEAMS_SQLITE_MAX_POLL_ROWS
1527
+ });
1528
+ const voteBucketStore = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1529
+ namespace: MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE,
1530
+ maxEntries: MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS
1531
+ });
1657
1532
  const readPollVotes = async (pollId) => {
1658
1533
  const votes = {};
1659
1534
  for (const row of await voteBucketStore.entries()) if (row.value.pollId === pollId) Object.assign(votes, row.value.votes);
@@ -1732,7 +1607,7 @@ function createMSTeamsPollStoreState(params) {
1732
1607
  }
1733
1608
  };
1734
1609
  const createPoll = async (poll) => {
1735
- await withMSTeamsSqliteMutationLock(params, MSTEAMS_POLLS_NAMESPACE, async () => {
1610
+ await withMSTeamsSqliteMutationLock(MSTEAMS_POLLS_NAMESPACE, async () => {
1736
1611
  const { votes, ...metadata } = poll;
1737
1612
  await pollStore.register(buildMSTeamsPollStateKey(poll.id), toPluginJsonValue(metadata));
1738
1613
  await deletePollVotes(poll.id);
@@ -1747,7 +1622,7 @@ function createMSTeamsPollStoreState(params) {
1747
1622
  return await reconstructPoll(poll);
1748
1623
  };
1749
1624
  const recordVote = async (vote) => {
1750
- return await withMSTeamsSqliteMutationLock(params, MSTEAMS_POLLS_NAMESPACE, async () => {
1625
+ return await withMSTeamsSqliteMutationLock(MSTEAMS_POLLS_NAMESPACE, async () => {
1751
1626
  const pollKey = buildMSTeamsPollStateKey(vote.pollId);
1752
1627
  const poll = await pollStore.lookup(pollKey);
1753
1628
  if (!poll) return null;
@@ -1790,7 +1665,7 @@ function findPreferredDmConversationByUserId(entries, id) {
1790
1665
  let preferredTimestamp = 0;
1791
1666
  for (const entry of entries) {
1792
1667
  if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
1793
- const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType ?? "");
1668
+ const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType);
1794
1669
  if (convType === "channel" || convType === "groupchat") continue;
1795
1670
  const isPersonal = convType === "personal";
1796
1671
  const timestamp = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(entry.reference.lastSeenAt) ?? 0;
@@ -1816,16 +1691,14 @@ function getStoredConversationId(reference) {
1816
1691
  const rawId = reference.conversation?.id;
1817
1692
  return rawId ? require_resolve_allowlist.normalizeMSTeamsConversationId(rawId) : null;
1818
1693
  }
1819
- function createMSTeamsConversationStoreState(params) {
1820
- const ttlMs = params?.ttlMs ?? MSTEAMS_CONVERSATION_TTL_MS;
1694
+ function createMSTeamsConversationStoreState() {
1821
1695
  const conversationStore = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1822
1696
  namespace: MSTEAMS_CONVERSATIONS_NAMESPACE,
1823
- maxEntries: MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS,
1824
- env: resolveMSTeamsSqliteStateEnv(params)
1697
+ maxEntries: MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS
1825
1698
  });
1826
1699
  const isExpired = (reference) => {
1827
1700
  const lastSeenAt = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(reference.lastSeenAt);
1828
- return lastSeenAt != null && Date.now() - lastSeenAt > ttlMs;
1701
+ return lastSeenAt != null && Date.now() - lastSeenAt > MSTEAMS_CONVERSATION_TTL_MS;
1829
1702
  };
1830
1703
  const lookupStored = async (conversationId) => {
1831
1704
  const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
@@ -1877,14 +1750,14 @@ function createMSTeamsConversationStoreState(params) {
1877
1750
  };
1878
1751
  const upsert = async (conversationId, reference) => {
1879
1752
  const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
1880
- await withMSTeamsSqliteMutationLock(params, CONVERSATION_MUTATION_KEY, async () => {
1753
+ await withMSTeamsSqliteMutationLock(CONVERSATION_MUTATION_KEY, async () => {
1881
1754
  const existing = await lookupStored(normalizedId);
1882
1755
  await register(normalizedId, mergeStoredConversationReference(existing ?? void 0, reference, (/* @__PURE__ */ new Date()).toISOString()));
1883
1756
  });
1884
1757
  };
1885
1758
  const remove = async (conversationId) => {
1886
1759
  const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
1887
- return await withMSTeamsSqliteMutationLock(params, CONVERSATION_MUTATION_KEY, async () => {
1760
+ return await withMSTeamsSqliteMutationLock(CONVERSATION_MUTATION_KEY, async () => {
1888
1761
  return await conversationStore.delete(buildMSTeamsConversationStateKey(normalizedId));
1889
1762
  });
1890
1763
  };
@@ -2053,12 +1926,6 @@ Object.defineProperty(exports, "requiresFileConsent", {
2053
1926
  return requiresFileConsent;
2054
1927
  }
2055
1928
  });
2056
- Object.defineProperty(exports, "resolveMSTeamsSqliteStateEnv", {
2057
- enumerable: true,
2058
- get: function() {
2059
- return resolveMSTeamsSqliteStateEnv;
2060
- }
2061
- });
2062
1929
  Object.defineProperty(exports, "sendMSTeamsActivityWithReference", {
2063
1930
  enumerable: true,
2064
1931
  get: function() {