@openclaw/msteams 2026.10.10 → 2026.11.5-beta.1
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.
- package/dist/.setup/{adapter.runtime-BMvpm7sS.cjs → adapter.runtime-UOD_H_ph.cjs} +20 -23
- package/dist/.setup/{approval-card-Bo8kHYbj.cjs → approval-card-CD5q0Nla.cjs} +5 -9
- package/dist/.setup/{approval-handler.runtime-BS3avHFu.cjs → approval-handler.runtime-DbPxvynk.cjs} +4 -4
- package/dist/.setup/{channel-CdCSk3Rg.cjs → channel-DQrXOfhf.cjs} +24 -224
- package/dist/.setup/{channel.runtime--ZjTYgkY.cjs → channel.runtime-Du4GPMES.cjs} +65 -106
- package/dist/.setup/{channel.setup-nSTtK77J.cjs → channel.setup--7ko_Kxv.cjs} +161 -262
- package/dist/.setup/{config-schema-Bm15lF-j.cjs → config-schema-BEXDIOC-.cjs} +120 -123
- package/dist/.setup/{conversation-store-state-NJU9osd-.cjs → conversation-store-state-AVgRyNE9.cjs} +411 -598
- package/dist/.setup/{delegated-state-CbMd3rIh.cjs → delegated-state-DhIHahf1.cjs} +68 -6
- package/dist/.setup/{monitor-BxLDs5fk.cjs → monitor-CXjIKz7o.cjs} +1883 -2284
- package/dist/.setup/{oauth-B-Y5pNM4.cjs → oauth-BWG6qWCd.cjs} +10 -20
- package/dist/.setup/presentation-CaLawc5j.cjs +211 -0
- package/dist/.setup/{reaction-types-BaL1EVBS.cjs → reaction-types-DOzN5oTl.cjs} +1 -1
- package/dist/.setup/{resolve-allowlist-CqNzS9bZ.cjs → resolve-allowlist-Drj1jaq0.cjs} +213 -90
- package/dist/.setup/{secret-contract-api-BOzdWSn9.cjs → secret-contract-api-DFqDvc_a.cjs} +4 -6
- package/dist/.setup/{secret-contract-api-5aH1Fl_c.cjs → secret-contract-api-YGHrfAT0.cjs} +1 -1
- package/dist/.setup/{send-BXjI3ufq.cjs → send-BRUztzVJ.cjs} +86 -182
- package/dist/.setup/{setup-plugin-api-lPpin6Gg.cjs → setup-plugin-api-BHEfter5.cjs} +1 -1
- package/dist/.setup/{thread-session-DZMoCsSR.cjs → thread-session-BUUV1zk_.cjs} +4 -6
- package/dist/.setup/{token-config-DTZ00Ibq.cjs → token-config-7K6UbNCo.cjs} +0 -2
- package/dist/.source-module-urls/7e43ee3ae4faab430a47269c8217f8d99ec60ecd85233f40e81d03efeb543068.json +1 -1
- package/dist/api.cjs +2 -2
- package/dist/channel-config-api.cjs +1 -1
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +6 -13
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/secret-contract-api.cjs +1 -1
- package/dist/setup-entry.cjs +2 -2
- package/dist/setup-plugin-api.cjs +1 -1
- package/openclaw.plugin.json +0 -30
- package/package.json +11 -11
package/dist/.setup/{conversation-store-state-NJU9osd-.cjs → conversation-store-state-AVgRyNE9.cjs}
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-CiKaZLfC.cjs");
|
|
2
2
|
const require_bot_framework_service_url = require("./bot-framework-service-url-CgVuKiIR.cjs");
|
|
3
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
3
|
+
const require_resolve_allowlist = require("./resolve-allowlist-Drj1jaq0.cjs");
|
|
4
4
|
const require_runtime = require("./runtime-CbKazLGv.cjs");
|
|
5
5
|
require("../runtime-api.cjs");
|
|
6
|
-
const require_delegated_state = require("./delegated-state-
|
|
7
|
-
const
|
|
6
|
+
const require_delegated_state = require("./delegated-state-DhIHahf1.cjs");
|
|
7
|
+
const require_presentation = require("./presentation-CaLawc5j.cjs");
|
|
8
|
+
const require_channel_setup = require("./channel.setup--7ko_Kxv.cjs");
|
|
8
9
|
let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
|
|
9
10
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
10
11
|
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
@@ -13,7 +14,6 @@ let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-ht
|
|
|
13
14
|
let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
|
|
14
15
|
let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
|
|
15
16
|
let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
|
|
16
|
-
let node_dns_promises = require("node:dns/promises");
|
|
17
17
|
let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
|
|
18
18
|
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
19
19
|
let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
|
|
@@ -22,13 +22,14 @@ let node_crypto = require("node:crypto");
|
|
|
22
22
|
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
23
23
|
let node_path = require("node:path");
|
|
24
24
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
25
|
+
let openclaw_plugin_sdk_node_crypto_runtime = require("openclaw/plugin-sdk/node-crypto-runtime");
|
|
25
26
|
let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
|
|
26
27
|
let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
|
|
27
28
|
let openclaw_plugin_sdk_markdown_table_runtime = require("openclaw/plugin-sdk/markdown-table-runtime");
|
|
28
|
-
let
|
|
29
|
+
let node_dns_promises = require("node:dns/promises");
|
|
29
30
|
let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
|
|
30
31
|
let openclaw_plugin_sdk_expect_runtime = require("openclaw/plugin-sdk/expect-runtime");
|
|
31
|
-
let
|
|
32
|
+
let openclaw_plugin_sdk_blob_runtime = require("openclaw/plugin-sdk/blob-runtime");
|
|
32
33
|
let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
|
|
33
34
|
let openclaw_plugin_sdk_dedupe_runtime = require("openclaw/plugin-sdk/dedupe-runtime");
|
|
34
35
|
let openclaw_plugin_sdk_plugin_state_runtime = require("openclaw/plugin-sdk/plugin-state-runtime");
|
|
@@ -40,18 +41,11 @@ let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runti
|
|
|
40
41
|
* as upload destinations in the FileConsentCard flow.
|
|
41
42
|
*/
|
|
42
43
|
const CONSENT_UPLOAD_HOST_ALLOWLIST = [
|
|
43
|
-
|
|
44
|
-
"sharepoint.us",
|
|
45
|
-
"sharepoint.de",
|
|
46
|
-
"sharepoint.cn",
|
|
47
|
-
"sharepoint-df.com",
|
|
44
|
+
...require_resolve_allowlist.SHAREPOINT_HOSTS,
|
|
48
45
|
"storage.live.com",
|
|
49
46
|
"onedrive.com",
|
|
50
47
|
"1drv.ms",
|
|
51
|
-
|
|
52
|
-
"graph.microsoft.us",
|
|
53
|
-
"graph.microsoft.de",
|
|
54
|
-
"graph.microsoft.cn"
|
|
48
|
+
...require_resolve_allowlist.GRAPH_HOSTS
|
|
55
49
|
];
|
|
56
50
|
async function validateConsentUploadUrl(url) {
|
|
57
51
|
const parsed = URL.parse(url);
|
|
@@ -127,7 +121,7 @@ async function uploadToConsentUrl(params) {
|
|
|
127
121
|
"Content-Type": params.contentType ?? "application/octet-stream",
|
|
128
122
|
"Content-Range": `bytes 0-${params.buffer.length - 1}/${params.buffer.length}`
|
|
129
123
|
},
|
|
130
|
-
body:
|
|
124
|
+
body: Uint8Array.from(params.buffer)
|
|
131
125
|
}, require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length));
|
|
132
126
|
await res.body?.cancel().catch(() => void 0);
|
|
133
127
|
if (!res.ok) throw new Error(`File upload to consent URL failed: ${res.status} ${res.statusText}`);
|
|
@@ -145,13 +139,13 @@ const PENDING_UPLOAD_META_NAMESPACE = "pending-uploads";
|
|
|
145
139
|
const PENDING_UPLOAD_CHUNKS_NAMESPACE = "pending-upload-chunks";
|
|
146
140
|
const PENDING_UPLOAD_MUTATION_KEY = "pending-uploads";
|
|
147
141
|
function createMetaStore() {
|
|
148
|
-
return require_runtime.getMSTeamsRuntime().state.
|
|
142
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStoreV2({
|
|
149
143
|
namespace: PENDING_UPLOAD_META_NAMESPACE,
|
|
150
144
|
maxEntries: PENDING_UPLOAD_META_MAX_ENTRIES
|
|
151
145
|
});
|
|
152
146
|
}
|
|
153
147
|
function createChunkStore() {
|
|
154
|
-
return require_runtime.getMSTeamsRuntime().state.
|
|
148
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStoreV2({
|
|
155
149
|
namespace: PENDING_UPLOAD_CHUNKS_NAMESPACE,
|
|
156
150
|
maxEntries: MAX_PENDING_UPLOAD_CHUNK_ROWS
|
|
157
151
|
});
|
|
@@ -165,17 +159,6 @@ function buildMetaKey(id) {
|
|
|
165
159
|
function buildChunkKey(id, index) {
|
|
166
160
|
return `${buildUploadKey(id)}:chunk:${String(index).padStart(4, "0")}`;
|
|
167
161
|
}
|
|
168
|
-
function recordToUpload(record, buffer) {
|
|
169
|
-
return {
|
|
170
|
-
id: record.id,
|
|
171
|
-
buffer,
|
|
172
|
-
filename: record.filename,
|
|
173
|
-
contentType: record.contentType,
|
|
174
|
-
conversationId: record.conversationId,
|
|
175
|
-
consentCardActivityId: record.consentCardActivityId,
|
|
176
|
-
createdAt: record.createdAt
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
162
|
async function deleteUploadRows(id, metaStore, chunkStore) {
|
|
180
163
|
const existing = await metaStore.lookup(buildMetaKey(id));
|
|
181
164
|
await metaStore.delete(buildMetaKey(id));
|
|
@@ -191,11 +174,11 @@ async function registerUploadRows(record, metaStore, chunkStore) {
|
|
|
191
174
|
await pruneUploadStore(metaStore, chunkStore, chunkCount);
|
|
192
175
|
for (let index = 0; index < chunkCount; index += 1) {
|
|
193
176
|
const chunk = buffer.subarray(index * RAW_CHUNK_BYTES, (index + 1) * RAW_CHUNK_BYTES);
|
|
194
|
-
await chunkStore.register(buildChunkKey(record.id, index),
|
|
177
|
+
await chunkStore.register(buildChunkKey(record.id, index), {
|
|
195
178
|
id: record.id,
|
|
196
179
|
index,
|
|
197
180
|
dataBase64: chunk.toString("base64")
|
|
198
|
-
})
|
|
181
|
+
});
|
|
199
182
|
}
|
|
200
183
|
await metaStore.register(buildMetaKey(record.id), require_delegated_state.toPluginJsonValue({
|
|
201
184
|
id: record.id,
|
|
@@ -212,16 +195,25 @@ async function readUploadRows(id, metaStore, chunkStore) {
|
|
|
212
195
|
const meta = await metaStore.lookup(buildMetaKey(id));
|
|
213
196
|
if (!meta) return;
|
|
214
197
|
if (!Number.isSafeInteger(meta.chunkCount) || meta.chunkCount < 1 || meta.chunkCount > MAX_CHUNKS_PER_UPLOAD) return;
|
|
215
|
-
const records = await chunkStore.lookupMany
|
|
198
|
+
const records = await chunkStore.lookupMany(Array.from({ length: meta.chunkCount }, (_, index) => buildChunkKey(id, index)));
|
|
216
199
|
const chunks = [];
|
|
217
200
|
for (let index = 0; index < meta.chunkCount; index += 1) {
|
|
218
|
-
const result = records
|
|
201
|
+
const result = records[index];
|
|
219
202
|
if (result && !result.ok) throw result.error;
|
|
220
|
-
const chunk =
|
|
203
|
+
const chunk = result?.value;
|
|
221
204
|
if (!chunk || chunk.id !== id || chunk.index !== index) return;
|
|
222
205
|
chunks.push(Buffer.from(chunk.dataBase64, "base64"));
|
|
223
206
|
}
|
|
224
|
-
|
|
207
|
+
const buffer = Buffer.concat(chunks, meta.byteLength);
|
|
208
|
+
return {
|
|
209
|
+
id: meta.id,
|
|
210
|
+
buffer,
|
|
211
|
+
filename: meta.filename,
|
|
212
|
+
contentType: meta.contentType,
|
|
213
|
+
conversationId: meta.conversationId,
|
|
214
|
+
consentCardActivityId: meta.consentCardActivityId,
|
|
215
|
+
createdAt: meta.createdAt
|
|
216
|
+
};
|
|
225
217
|
}
|
|
226
218
|
async function pruneUploadStore(metaStore, chunkStore, extraChunkRows = 0) {
|
|
227
219
|
const rows = await metaStore.entries();
|
|
@@ -289,10 +281,10 @@ async function setPendingUploadActivityIdFs(id, activityId) {
|
|
|
289
281
|
await require_delegated_state.withMSTeamsSqliteMutationLock(PENDING_UPLOAD_MUTATION_KEY, async () => {
|
|
290
282
|
const record = await metaStore.lookup(buildMetaKey(id));
|
|
291
283
|
if (!record || Date.now() - record.createdAt > PENDING_UPLOAD_TTL_MS$1) return;
|
|
292
|
-
await metaStore.register(buildMetaKey(id),
|
|
284
|
+
await metaStore.register(buildMetaKey(id), {
|
|
293
285
|
...record,
|
|
294
286
|
consentCardActivityId: activityId
|
|
295
|
-
})
|
|
287
|
+
});
|
|
296
288
|
});
|
|
297
289
|
}
|
|
298
290
|
// extensions/msteams/src/pending-uploads.ts
|
|
@@ -303,14 +295,9 @@ async function setPendingUploadActivityIdFs(id, activityId) {
|
|
|
303
295
|
* before upload. This module stores the file data temporarily until the user
|
|
304
296
|
* accepts or declines, or until the TTL expires.
|
|
305
297
|
*/
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
pendingUploadTimers: /* @__PURE__ */ new Map()
|
|
310
|
-
}), (state) => {
|
|
311
|
-
for (const timer of state.pendingUploadTimers.values()) clearTimeout(timer);
|
|
312
|
-
state.pendingUploadTimers.clear();
|
|
313
|
-
state.pendingUploads.clear();
|
|
298
|
+
const pendingUploads = (0, openclaw_plugin_sdk_global_singleton.resolveGlobalSingleton)(Symbol.for("openclaw.msteams.pendingUploadState"), () => /* @__PURE__ */ new Map(), (state) => {
|
|
299
|
+
for (const { timer } of state.values()) clearTimeout(timer);
|
|
300
|
+
state.clear();
|
|
314
301
|
});
|
|
315
302
|
const PENDING_UPLOAD_TTL_MS = 3e5;
|
|
316
303
|
/**
|
|
@@ -324,17 +311,18 @@ function storePendingUpload(upload) {
|
|
|
324
311
|
id,
|
|
325
312
|
createdAt: Date.now()
|
|
326
313
|
};
|
|
327
|
-
pendingUploads.set(id, entry);
|
|
328
314
|
const timer = setTimeout(() => {
|
|
329
315
|
pendingUploads.delete(id);
|
|
330
|
-
pendingUploadTimers.delete(id);
|
|
331
316
|
}, PENDING_UPLOAD_TTL_MS);
|
|
332
|
-
|
|
317
|
+
pendingUploads.set(id, {
|
|
318
|
+
upload: entry,
|
|
319
|
+
timer
|
|
320
|
+
});
|
|
333
321
|
return id;
|
|
334
322
|
}
|
|
335
323
|
function getPendingUpload(id) {
|
|
336
324
|
if (!id) return;
|
|
337
|
-
const entry = pendingUploads.get(id);
|
|
325
|
+
const entry = pendingUploads.get(id)?.upload;
|
|
338
326
|
if (!entry) return;
|
|
339
327
|
if (Date.now() - entry.createdAt > PENDING_UPLOAD_TTL_MS) {
|
|
340
328
|
removePendingUpload(id);
|
|
@@ -348,16 +336,12 @@ function getPendingUpload(id) {
|
|
|
348
336
|
*/
|
|
349
337
|
function removePendingUpload(id) {
|
|
350
338
|
if (id) {
|
|
339
|
+
clearTimeout(pendingUploads.get(id)?.timer);
|
|
351
340
|
pendingUploads.delete(id);
|
|
352
|
-
const timer = pendingUploadTimers.get(id);
|
|
353
|
-
if (timer !== void 0) {
|
|
354
|
-
clearTimeout(timer);
|
|
355
|
-
pendingUploadTimers.delete(id);
|
|
356
|
-
}
|
|
357
341
|
}
|
|
358
342
|
}
|
|
359
343
|
function setPendingUploadActivityId(uploadId, activityId) {
|
|
360
|
-
const entry = pendingUploads.get(uploadId);
|
|
344
|
+
const entry = pendingUploads.get(uploadId)?.upload;
|
|
361
345
|
if (entry) entry.consentCardActivityId = activityId;
|
|
362
346
|
}
|
|
363
347
|
// extensions/msteams/src/file-consent-helpers.ts
|
|
@@ -466,33 +450,6 @@ function rewriteMarkdownIR(ir, edits) {
|
|
|
466
450
|
})) } : {}
|
|
467
451
|
};
|
|
468
452
|
}
|
|
469
|
-
function prefixMSTeamsBlockquotes(ir) {
|
|
470
|
-
const rewritten = rewriteMarkdownIR(ir, ir.styles.filter((span) => span.style === "blockquote").flatMap((span) => {
|
|
471
|
-
const positions = [span.start];
|
|
472
|
-
for (let index = span.start; index < span.end; index += 1) if (ir.text[index] === "\n" && index + 1 < span.end) positions.push(index + 1);
|
|
473
|
-
return positions.map((position) => ({
|
|
474
|
-
start: position,
|
|
475
|
-
end: position,
|
|
476
|
-
text: "> "
|
|
477
|
-
}));
|
|
478
|
-
}));
|
|
479
|
-
return {
|
|
480
|
-
...rewritten,
|
|
481
|
-
styles: rewritten.styles.filter((span) => span.style !== "blockquote")
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
function longestBacktickRun(text) {
|
|
485
|
-
return Math.max(0, ...text.match(/`+/gu)?.map((run) => run.length) ?? []);
|
|
486
|
-
}
|
|
487
|
-
function renderMSTeamsCode(style, text) {
|
|
488
|
-
const marker = "`".repeat(Math.max(style === "code_block" ? 3 : 1, longestBacktickRun(text) + 1));
|
|
489
|
-
if (style === "code_block") return `${marker}\n${text}${marker}`;
|
|
490
|
-
const needsPadding = text.startsWith("`") || text.endsWith("`") || text.startsWith(" ") && text.endsWith(" ") && text.trim().length > 0;
|
|
491
|
-
return `${marker}${needsPadding ? " " : ""}${text}${needsPadding ? " " : ""}${marker}`;
|
|
492
|
-
}
|
|
493
|
-
function serializeMarkdownDestination(href) {
|
|
494
|
-
return `<${href.replace(/([\\<>])/gu, "\\$1")}>`;
|
|
495
|
-
}
|
|
496
453
|
function blankBlockEnd(text, index) {
|
|
497
454
|
if (text[index] !== "\n" && text[index] !== "\r") return;
|
|
498
455
|
const match = /^(?:\r?\n)[ \t]*(?:\r?\n)/u.exec(text.slice(index));
|
|
@@ -552,74 +509,6 @@ function protectDelimitedMarkdown(text, opener, tokenPrefix, values) {
|
|
|
552
509
|
}
|
|
553
510
|
return protectedText + text.slice(cursor);
|
|
554
511
|
}
|
|
555
|
-
function protectRawTables(text, tokenPrefix, rawTables) {
|
|
556
|
-
if (!text.includes("|")) return text;
|
|
557
|
-
const { tables } = (0, openclaw_plugin_sdk_text_chunking.markdownToIRWithMeta)(text, {
|
|
558
|
-
autolink: false,
|
|
559
|
-
linkify: false,
|
|
560
|
-
tableMode: "block"
|
|
561
|
-
});
|
|
562
|
-
let result = "";
|
|
563
|
-
let cursor = 0;
|
|
564
|
-
for (const table of tables) {
|
|
565
|
-
const source = (0, openclaw_plugin_sdk_expect_runtime.expectDefined)((0, openclaw_plugin_sdk_markdown_table_runtime.getMarkdownTableSource)(table), "Markdown table source");
|
|
566
|
-
const lineStart = Math.max(text.lastIndexOf("\n", source.start - 1), text.lastIndexOf("\r", source.start - 1)) + 1;
|
|
567
|
-
const start = lineStart + (/^(?: {0,3}>[ \t]?)*/u.exec(text.slice(lineStart, source.start))?.[0] ?? "").length;
|
|
568
|
-
const end = source.end + (text.slice(source.end, source.end + 2) === "\r\n" ? 1 : 0);
|
|
569
|
-
const index = rawTables.push(text.slice(start, end)) - 1;
|
|
570
|
-
result += text.slice(cursor, start) + `${tokenPrefix}t${index}${TOKEN_END}`;
|
|
571
|
-
cursor = end;
|
|
572
|
-
}
|
|
573
|
-
return result + text.slice(cursor);
|
|
574
|
-
}
|
|
575
|
-
function protectMSTeamsCode(ir, tokenPrefix, code, protectedValues) {
|
|
576
|
-
const codeSpans = ir.styles.filter((span) => span.style === "code" || span.style === "code_block");
|
|
577
|
-
const codeBlocks = codeSpans.filter((span) => span.style === "code_block");
|
|
578
|
-
const adjustedStyles = ir.styles.flatMap((span) => {
|
|
579
|
-
if (span.style !== "blockquote") return [span];
|
|
580
|
-
let segments = [span];
|
|
581
|
-
for (const codeBlock of codeBlocks) segments = segments.flatMap((segment) => {
|
|
582
|
-
if (codeBlock.end <= segment.start || codeBlock.start >= segment.end) return [segment];
|
|
583
|
-
return [...segment.start < codeBlock.start ? [{
|
|
584
|
-
...segment,
|
|
585
|
-
end: codeBlock.start
|
|
586
|
-
}] : [], ...codeBlock.end < segment.end ? [{
|
|
587
|
-
...segment,
|
|
588
|
-
start: codeBlock.end
|
|
589
|
-
}] : []];
|
|
590
|
-
});
|
|
591
|
-
return segments;
|
|
592
|
-
});
|
|
593
|
-
const rewritten = rewriteMarkdownIR({
|
|
594
|
-
...ir,
|
|
595
|
-
styles: adjustedStyles
|
|
596
|
-
}, codeSpans.map((span) => {
|
|
597
|
-
const codeStyle = span.style === "code_block" ? "code_block" : "code";
|
|
598
|
-
const source = protectedValues.reduce((text, protectedValue) => restoreTokens(text, protectedValue.prefix, protectedValue.values), ir.text.slice(span.start, span.end));
|
|
599
|
-
let quoteDepth = 0;
|
|
600
|
-
let hasTrailingQuotedText = false;
|
|
601
|
-
if (codeStyle === "code_block") {
|
|
602
|
-
for (const candidate of ir.styles) if (candidate.style === "blockquote" && span.start >= candidate.start) {
|
|
603
|
-
if (span.start < candidate.end) quoteDepth += 1;
|
|
604
|
-
hasTrailingQuotedText ||= candidate.end > span.end;
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
const rendered = renderMSTeamsCode(codeStyle, source);
|
|
608
|
-
let quoted = quoteDepth > 0 ? `${"> ".repeat(quoteDepth)}${rendered.replaceAll("\n", `\n${"> ".repeat(quoteDepth)}`)}` : rendered;
|
|
609
|
-
const followedByText = codeStyle === "code_block" && span.end < ir.text.length && ir.text[span.end] !== "\n";
|
|
610
|
-
if ((hasTrailingQuotedText || followedByText) && !quoted.endsWith("\n")) quoted += "\n";
|
|
611
|
-
const index = code.push(quoted) - 1;
|
|
612
|
-
return {
|
|
613
|
-
start: span.start,
|
|
614
|
-
end: span.end,
|
|
615
|
-
text: `${tokenPrefix}c${index}${TOKEN_END}`
|
|
616
|
-
};
|
|
617
|
-
}));
|
|
618
|
-
return {
|
|
619
|
-
...rewritten,
|
|
620
|
-
styles: rewritten.styles.filter((span) => span.style !== "code" && span.style !== "code_block")
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
512
|
function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
624
513
|
if (markdown === "") return markdown;
|
|
625
514
|
const rawTables = [];
|
|
@@ -634,7 +523,27 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
634
523
|
return `${tokenPrefix}h${index}${TOKEN_END}`;
|
|
635
524
|
}), "![", `${tokenPrefix}i`, images), "@[", `${tokenPrefix}m`, mentions);
|
|
636
525
|
const tableInput = (0, openclaw_plugin_sdk_text_chunking.convertMarkdownTables)(mentionsProtected, tableMode);
|
|
637
|
-
|
|
526
|
+
let converted = tableInput;
|
|
527
|
+
if (tableMode === "off" && tableInput.includes("|")) {
|
|
528
|
+
const { tables } = (0, openclaw_plugin_sdk_text_chunking.markdownToIRWithMeta)(tableInput, {
|
|
529
|
+
autolink: false,
|
|
530
|
+
linkify: false,
|
|
531
|
+
tableMode: "block"
|
|
532
|
+
});
|
|
533
|
+
let result = "";
|
|
534
|
+
let cursor = 0;
|
|
535
|
+
for (const table of tables) {
|
|
536
|
+
const source = (0, openclaw_plugin_sdk_expect_runtime.expectDefined)((0, openclaw_plugin_sdk_markdown_table_runtime.getMarkdownTableSource)(table), "Markdown table source");
|
|
537
|
+
const lineStart = Math.max(tableInput.lastIndexOf("\n", source.start - 1), tableInput.lastIndexOf("\r", source.start - 1)) + 1;
|
|
538
|
+
const start = lineStart + (/^(?: {0,3}>[ \t]?)*/u.exec(tableInput.slice(lineStart, source.start))?.[0] ?? "").length;
|
|
539
|
+
const end = source.end + (tableInput.slice(source.end, source.end + 2) === "\r\n" ? 1 : 0);
|
|
540
|
+
const index = rawTables.push(tableInput.slice(start, end)) - 1;
|
|
541
|
+
result += tableInput.slice(cursor, start) + `${tokenPrefix}t${index}${TOKEN_END}`;
|
|
542
|
+
cursor = end;
|
|
543
|
+
}
|
|
544
|
+
converted = result + tableInput.slice(cursor);
|
|
545
|
+
}
|
|
546
|
+
const protectedMarkdown = converted.replace(ESCAPED_MARKDOWN_RE, (escaped) => {
|
|
638
547
|
const index = escapedMarkdown.push(escaped) - 1;
|
|
639
548
|
return `${tokenPrefix}e${index}${TOKEN_END}`;
|
|
640
549
|
});
|
|
@@ -668,7 +577,71 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
668
577
|
values: entities
|
|
669
578
|
}
|
|
670
579
|
];
|
|
671
|
-
const
|
|
580
|
+
const codeSpans = parsed.styles.filter((span) => span.style === "code" || span.style === "code_block");
|
|
581
|
+
const codeBlocks = codeSpans.filter((span) => span.style === "code_block");
|
|
582
|
+
const adjustedStyles = parsed.styles.flatMap((span) => {
|
|
583
|
+
if (span.style !== "blockquote") return [span];
|
|
584
|
+
let segments = [span];
|
|
585
|
+
for (const codeBlock of codeBlocks) segments = segments.flatMap((segment) => {
|
|
586
|
+
if (codeBlock.end <= segment.start || codeBlock.start >= segment.end) return [segment];
|
|
587
|
+
return [...segment.start < codeBlock.start ? [{
|
|
588
|
+
...segment,
|
|
589
|
+
end: codeBlock.start
|
|
590
|
+
}] : [], ...codeBlock.end < segment.end ? [{
|
|
591
|
+
...segment,
|
|
592
|
+
start: codeBlock.end
|
|
593
|
+
}] : []];
|
|
594
|
+
});
|
|
595
|
+
return segments;
|
|
596
|
+
});
|
|
597
|
+
const codeRewritten = rewriteMarkdownIR({
|
|
598
|
+
...parsed,
|
|
599
|
+
styles: adjustedStyles
|
|
600
|
+
}, codeSpans.map((span) => {
|
|
601
|
+
const codeStyle = span.style === "code_block" ? "code_block" : "code";
|
|
602
|
+
const source = protectedValues.reduce((text, protectedValue) => restoreTokens(text, protectedValue.prefix, protectedValue.values), parsed.text.slice(span.start, span.end));
|
|
603
|
+
let quoteDepth = 0;
|
|
604
|
+
let hasTrailingQuotedText = false;
|
|
605
|
+
if (codeStyle === "code_block") {
|
|
606
|
+
for (const candidate of parsed.styles) if (candidate.style === "blockquote" && span.start >= candidate.start) {
|
|
607
|
+
if (span.start < candidate.end) quoteDepth += 1;
|
|
608
|
+
hasTrailingQuotedText ||= candidate.end > span.end;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
const marker = "`".repeat(Math.max(codeStyle === "code_block" ? 3 : 1, Math.max(0, ...source.match(/`+/gu)?.map((run) => run.length) ?? []) + 1));
|
|
612
|
+
let rendered;
|
|
613
|
+
if (codeStyle === "code_block") rendered = `${marker}\n${source}${marker}`;
|
|
614
|
+
else {
|
|
615
|
+
const needsPadding = source.startsWith("`") || source.endsWith("`") || source.startsWith(" ") && source.endsWith(" ") && source.trim().length > 0;
|
|
616
|
+
rendered = `${marker}${needsPadding ? " " : ""}${source}${needsPadding ? " " : ""}${marker}`;
|
|
617
|
+
}
|
|
618
|
+
let quoted = quoteDepth > 0 ? `${"> ".repeat(quoteDepth)}${rendered.replaceAll("\n", `\n${"> ".repeat(quoteDepth)}`)}` : rendered;
|
|
619
|
+
const followedByText = codeStyle === "code_block" && span.end < parsed.text.length && parsed.text[span.end] !== "\n";
|
|
620
|
+
if ((hasTrailingQuotedText || followedByText) && !quoted.endsWith("\n")) quoted += "\n";
|
|
621
|
+
const index = codeRegions.push(quoted) - 1;
|
|
622
|
+
return {
|
|
623
|
+
start: span.start,
|
|
624
|
+
end: span.end,
|
|
625
|
+
text: `${tokenPrefix}c${index}${TOKEN_END}`
|
|
626
|
+
};
|
|
627
|
+
}));
|
|
628
|
+
const codeProtected = {
|
|
629
|
+
...codeRewritten,
|
|
630
|
+
styles: codeRewritten.styles.filter((span) => span.style !== "code" && span.style !== "code_block")
|
|
631
|
+
};
|
|
632
|
+
const rewritten = rewriteMarkdownIR(codeProtected, codeProtected.styles.filter((span) => span.style === "blockquote").flatMap((span) => {
|
|
633
|
+
const positions = [span.start];
|
|
634
|
+
for (let index = span.start; index < span.end; index += 1) if (codeProtected.text[index] === "\n" && index + 1 < span.end) positions.push(index + 1);
|
|
635
|
+
return positions.map((position) => ({
|
|
636
|
+
start: position,
|
|
637
|
+
end: position,
|
|
638
|
+
text: "> "
|
|
639
|
+
}));
|
|
640
|
+
}));
|
|
641
|
+
const ir = {
|
|
642
|
+
...rewritten,
|
|
643
|
+
styles: rewritten.styles.filter((span) => span.style !== "blockquote")
|
|
644
|
+
};
|
|
672
645
|
const rendered = (0, openclaw_plugin_sdk_text_chunking.renderMarkdownWithMarkers)(ir, {
|
|
673
646
|
styleMarkers: MSTEAMS_MARKERS,
|
|
674
647
|
escapeText: (text) => text,
|
|
@@ -676,7 +649,7 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
676
649
|
start: link.start,
|
|
677
650
|
end: link.end,
|
|
678
651
|
open: "[",
|
|
679
|
-
close: `](
|
|
652
|
+
close: `](<${link.href.replace(/([\\<>])/gu, "\\$1")}>)`
|
|
680
653
|
})
|
|
681
654
|
}, MSTEAMS_FORMAT_CAPABILITIES);
|
|
682
655
|
return protectedValues.reduce((text, { prefix, values }) => restoreTokens(text, prefix, values), restoreTokens(rendered, `${tokenPrefix}c`, codeRegions));
|
|
@@ -741,26 +714,6 @@ async function requestSharePointJson(params, request) {
|
|
|
741
714
|
}
|
|
742
715
|
});
|
|
743
716
|
}
|
|
744
|
-
async function uploadToSharePoint(params) {
|
|
745
|
-
const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
|
|
746
|
-
const data = await requestSharePointJson(params, {
|
|
747
|
-
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`,
|
|
748
|
-
timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
|
|
749
|
-
init: () => ({
|
|
750
|
-
method: "PUT",
|
|
751
|
-
headers: { "Content-Type": params.contentType ?? "application/octet-stream" },
|
|
752
|
-
body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)])
|
|
753
|
-
}),
|
|
754
|
-
error: "SharePoint upload failed",
|
|
755
|
-
label: "msteams.graph-upload.uploadSharePointFile"
|
|
756
|
-
});
|
|
757
|
-
if (!data.id || !data.webUrl || !data.name) throw new Error("SharePoint upload response missing required fields");
|
|
758
|
-
return {
|
|
759
|
-
id: data.id,
|
|
760
|
-
webUrl: data.webUrl,
|
|
761
|
-
name: data.name
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
717
|
async function getDriveItemProperties(params) {
|
|
765
718
|
const data = await requestSharePointJson(params, {
|
|
766
719
|
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`,
|
|
@@ -774,27 +727,44 @@ async function getDriveItemProperties(params) {
|
|
|
774
727
|
name: data.name
|
|
775
728
|
};
|
|
776
729
|
}
|
|
777
|
-
async function getChatMemberIds(params) {
|
|
778
|
-
return ((await requestSharePointJson(params, {
|
|
779
|
-
url: `${GRAPH_ROOT}/chats/${params.chatId}/members`,
|
|
780
|
-
error: (res) => res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed",
|
|
781
|
-
label: "msteams.graph-upload.getChatMembers"
|
|
782
|
-
})).value ?? []).flatMap((member) => member.userId ? [member.userId] : []);
|
|
783
|
-
}
|
|
784
730
|
/**
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
* For per-user
|
|
731
|
+
* Upload a file to SharePoint and create a sharing link.
|
|
732
|
+
*
|
|
733
|
+
* For group chats, this creates a per-user sharing link scoped to chat members.
|
|
734
|
+
* For channels, this creates an organization-wide sharing link.
|
|
788
735
|
*/
|
|
789
|
-
async function
|
|
790
|
-
const
|
|
736
|
+
async function uploadAndShareSharePoint(params) {
|
|
737
|
+
const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
|
|
738
|
+
const data = await requestSharePointJson(params, {
|
|
739
|
+
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`,
|
|
740
|
+
timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
|
|
741
|
+
init: () => ({
|
|
742
|
+
method: "PUT",
|
|
743
|
+
headers: { "Content-Type": params.contentType ?? "application/octet-stream" },
|
|
744
|
+
body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)])
|
|
745
|
+
}),
|
|
746
|
+
error: "SharePoint upload failed",
|
|
747
|
+
label: "msteams.graph-upload.uploadSharePointFile"
|
|
748
|
+
});
|
|
749
|
+
if (!data.id) throw new Error("SharePoint upload response missing required fields");
|
|
750
|
+
const itemId = data.id;
|
|
751
|
+
let recipientObjectIds;
|
|
752
|
+
if (params.usePerUserSharing && params.chatId) {
|
|
753
|
+
recipientObjectIds = ((await requestSharePointJson(params, {
|
|
754
|
+
url: `${GRAPH_ROOT}/chats/${params.chatId}/members`,
|
|
755
|
+
error: (res) => res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed",
|
|
756
|
+
label: "msteams.graph-upload.getChatMembers"
|
|
757
|
+
})).value ?? []).flatMap((member) => member.userId ? [member.userId] : []);
|
|
758
|
+
if (recipientObjectIds.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
|
|
759
|
+
}
|
|
760
|
+
const apiRoot = recipientObjectIds ? GRAPH_BETA : GRAPH_ROOT;
|
|
791
761
|
const body = {
|
|
792
762
|
type: "view",
|
|
793
|
-
scope:
|
|
763
|
+
scope: recipientObjectIds ? "users" : "organization"
|
|
794
764
|
};
|
|
795
|
-
if (
|
|
796
|
-
|
|
797
|
-
url: `${apiRoot}/sites/${params.siteId}/drive/items/${
|
|
765
|
+
if (recipientObjectIds) body.recipients = recipientObjectIds.map((id) => ({ objectId: id }));
|
|
766
|
+
await requestSharePointJson(params, {
|
|
767
|
+
url: `${apiRoot}/sites/${params.siteId}/drive/items/${itemId}/createLink`,
|
|
798
768
|
init: () => ({
|
|
799
769
|
method: "POST",
|
|
800
770
|
headers: { "Content-Type": "application/json" },
|
|
@@ -803,39 +773,7 @@ async function createSharePointSharingLink(params) {
|
|
|
803
773
|
error: "Create SharePoint sharing link failed",
|
|
804
774
|
label: "msteams.graph-upload.createSharePointSharingLink"
|
|
805
775
|
});
|
|
806
|
-
|
|
807
|
-
return data.link.webUrl;
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Upload a file to SharePoint and create a sharing link.
|
|
811
|
-
*
|
|
812
|
-
* For group chats, this creates a per-user sharing link scoped to chat members.
|
|
813
|
-
* For channels, this creates an organization-wide sharing link.
|
|
814
|
-
*/
|
|
815
|
-
async function uploadAndShareSharePoint(params) {
|
|
816
|
-
const uploaded = await uploadToSharePoint(params);
|
|
817
|
-
let recipientObjectIds;
|
|
818
|
-
if (params.usePerUserSharing && params.chatId) {
|
|
819
|
-
recipientObjectIds = await getChatMemberIds({
|
|
820
|
-
chatId: params.chatId,
|
|
821
|
-
tokenProvider: params.tokenProvider,
|
|
822
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
823
|
-
});
|
|
824
|
-
if (recipientObjectIds.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
|
|
825
|
-
}
|
|
826
|
-
const shareUrl = await createSharePointSharingLink({
|
|
827
|
-
siteId: params.siteId,
|
|
828
|
-
itemId: uploaded.id,
|
|
829
|
-
tokenProvider: params.tokenProvider,
|
|
830
|
-
recipientObjectIds,
|
|
831
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
832
|
-
});
|
|
833
|
-
return {
|
|
834
|
-
itemId: uploaded.id,
|
|
835
|
-
webUrl: uploaded.webUrl,
|
|
836
|
-
shareUrl,
|
|
837
|
-
name: uploaded.name
|
|
838
|
-
};
|
|
776
|
+
return { itemId };
|
|
839
777
|
}
|
|
840
778
|
// extensions/msteams/src/media-helpers.ts
|
|
841
779
|
const MSTEAMS_MAX_MEDIA_BYTES = 104857600;
|
|
@@ -882,7 +820,7 @@ function extractMessageId(response) {
|
|
|
882
820
|
const { id } = response;
|
|
883
821
|
return typeof id === "string" && id ? id : null;
|
|
884
822
|
}
|
|
885
|
-
// extensions/msteams/src/
|
|
823
|
+
// extensions/msteams/src/message-activity.ts
|
|
886
824
|
/**
|
|
887
825
|
* Check whether an ID looks like a valid Teams user/bot identifier.
|
|
888
826
|
* Accepts:
|
|
@@ -894,38 +832,6 @@ function extractMessageId(response) {
|
|
|
894
832
|
*/
|
|
895
833
|
const TEAMS_BOT_ID_PATTERN = /^\d+:[a-z0-9._=-]+(?::[a-z0-9._=-]+)*$/i;
|
|
896
834
|
const AAD_OBJECT_ID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
897
|
-
function isValidTeamsId(id) {
|
|
898
|
-
return TEAMS_BOT_ID_PATTERN.test(id) || AAD_OBJECT_ID_PATTERN.test(id);
|
|
899
|
-
}
|
|
900
|
-
/**
|
|
901
|
-
* Convert @[Name](id) into matching <at> text and mention entities.
|
|
902
|
-
* Only matches where the id looks like a real Teams user/bot ID are treated
|
|
903
|
-
* as mentions. This avoids false positives from documentation or code samples
|
|
904
|
-
* embedded in the message (e.g. `@[表示名](ユーザーID)` in backticks).
|
|
905
|
-
*/
|
|
906
|
-
function parseMentions(text) {
|
|
907
|
-
const mentionPattern = /@\[((?:\\[\s\S]|[^\]\\])+)\]\(([^)]+)\)/g;
|
|
908
|
-
const entities = [];
|
|
909
|
-
return {
|
|
910
|
-
text: text.replace(mentionPattern, (match, name, id) => {
|
|
911
|
-
const trimmedId = id.trim();
|
|
912
|
-
if (!isValidTeamsId(trimmedId)) return match;
|
|
913
|
-
const trimmedName = name.replace(/\\([\\[\]])/g, "$1").trim();
|
|
914
|
-
const mentionTag = `<at>${trimmedName}</at>`;
|
|
915
|
-
entities.push({
|
|
916
|
-
type: "mention",
|
|
917
|
-
text: mentionTag,
|
|
918
|
-
mentioned: {
|
|
919
|
-
id: trimmedId,
|
|
920
|
-
name: trimmedName
|
|
921
|
-
}
|
|
922
|
-
});
|
|
923
|
-
return mentionTag;
|
|
924
|
-
}),
|
|
925
|
-
entities
|
|
926
|
-
};
|
|
927
|
-
}
|
|
928
|
-
// extensions/msteams/src/message-activity.ts
|
|
929
835
|
const AI_GENERATED_ENTITY = {
|
|
930
836
|
type: "https://schema.org/Message",
|
|
931
837
|
"@type": "Message",
|
|
@@ -933,13 +839,36 @@ const AI_GENERATED_ENTITY = {
|
|
|
933
839
|
"@id": "",
|
|
934
840
|
additionalType: ["AIGeneratedContent"]
|
|
935
841
|
};
|
|
842
|
+
/**
|
|
843
|
+
* Convert @[Name](id) into matching <at> text and mention entities.
|
|
844
|
+
* Only matches where the id looks like a real Teams user/bot ID are treated
|
|
845
|
+
* as mentions. This avoids false positives from documentation or code samples
|
|
846
|
+
* embedded in the message (e.g. `@[表示名](ユーザーID)` in backticks).
|
|
847
|
+
*/
|
|
936
848
|
/** Build final transport text and its matching entities after Markdown rendering. */
|
|
937
849
|
function buildMSTeamsMessageActivity(text) {
|
|
938
|
-
const
|
|
850
|
+
const sourceText = text ?? "";
|
|
851
|
+
const mentionPattern = /@\[((?:\\[\s\S]|[^\]\\])+)\]\(([^)]+)\)/g;
|
|
852
|
+
const entities = [];
|
|
853
|
+
const formattedText = sourceText.replace(mentionPattern, (match, name, id) => {
|
|
854
|
+
const trimmedId = id.trim();
|
|
855
|
+
if (!(TEAMS_BOT_ID_PATTERN.test(trimmedId) || AAD_OBJECT_ID_PATTERN.test(trimmedId))) return match;
|
|
856
|
+
const trimmedName = name.replace(/\\([\\[\]])/g, "$1").trim();
|
|
857
|
+
const mentionTag = `<at>${trimmedName}</at>`;
|
|
858
|
+
entities.push({
|
|
859
|
+
type: "mention",
|
|
860
|
+
text: mentionTag,
|
|
861
|
+
mentioned: {
|
|
862
|
+
id: trimmedId,
|
|
863
|
+
name: trimmedName
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
return mentionTag;
|
|
867
|
+
});
|
|
939
868
|
return {
|
|
940
869
|
type: "message",
|
|
941
|
-
...text === void 0 ? {} : { text:
|
|
942
|
-
entities: [...
|
|
870
|
+
...text === void 0 ? {} : { text: formattedText },
|
|
871
|
+
entities: [...entities, AI_GENERATED_ENTITY]
|
|
943
872
|
};
|
|
944
873
|
}
|
|
945
874
|
function buildMSTeamsAdaptiveCardActivity(card) {
|
|
@@ -951,16 +880,6 @@ function buildMSTeamsAdaptiveCardActivity(card) {
|
|
|
951
880
|
}]
|
|
952
881
|
};
|
|
953
882
|
}
|
|
954
|
-
// extensions/msteams/src/revoked-context.ts
|
|
955
|
-
async function withRevokedProxyFallback(params) {
|
|
956
|
-
try {
|
|
957
|
-
return await params.run();
|
|
958
|
-
} catch (err) {
|
|
959
|
-
if (!require_channel_setup.isRevokedProxyError(err)) throw err;
|
|
960
|
-
params.onRevokedLog?.();
|
|
961
|
-
return await params.onRevoked();
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
883
|
// extensions/msteams/src/sent-message-cache.ts
|
|
965
884
|
const TTL_MS = 864e5;
|
|
966
885
|
const MAX_ENTRIES = 2e4;
|
|
@@ -970,7 +889,7 @@ const MSTEAMS_SENT_MESSAGES_KEY = Symbol.for("openclaw.msteamsSentMessages");
|
|
|
970
889
|
const namedAccountCaches = /* @__PURE__ */ new Map();
|
|
971
890
|
function createSentMessageCache(accountId) {
|
|
972
891
|
const isDefault = accountId === "default";
|
|
973
|
-
const accountDigest = isDefault ? void 0 : (0,
|
|
892
|
+
const accountDigest = isDefault ? void 0 : (0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(accountId);
|
|
974
893
|
return (0, openclaw_plugin_sdk_dedupe_runtime.createPersistentDedupeCache)({
|
|
975
894
|
globalKey: isDefault ? MSTEAMS_SENT_MESSAGES_KEY : Symbol.for(`openclaw.msteamsSentMessages.account.v1.${accountDigest}`),
|
|
976
895
|
ttlMs: TTL_MS,
|
|
@@ -1018,20 +937,15 @@ async function quoteMSTeamsActivity(activity, messageId) {
|
|
|
1018
937
|
if (activity.type !== "message") return activity;
|
|
1019
938
|
return MessageActivityInput.from(activity).prependQuote(messageId);
|
|
1020
939
|
}
|
|
1021
|
-
function resolveThreadedConversationId(conversationId, threadActivityId) {
|
|
1022
|
-
const baseId = conversationId.split(";")[0] ?? conversationId;
|
|
1023
|
-
return threadActivityId ? `${baseId};messageid=${threadActivityId}` : baseId;
|
|
1024
|
-
}
|
|
1025
|
-
function normalizeRequiredServiceUrl(ref) {
|
|
1026
|
-
if (!ref.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
|
|
1027
|
-
return require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(ref.serviceUrl);
|
|
1028
|
-
}
|
|
1029
940
|
function buildSdkConversationReference(source, options) {
|
|
1030
|
-
const bot = source.agent ?? source.bot
|
|
941
|
+
const bot = source.agent ?? source.bot;
|
|
1031
942
|
if (!bot?.id) throw new Error("Invalid stored reference: missing agent.id");
|
|
1032
|
-
const
|
|
943
|
+
const baseId = source.conversation.id.split(";")[0] ?? source.conversation.id;
|
|
944
|
+
const threadActivityId = options?.threadActivityId;
|
|
945
|
+
const conversationId = threadActivityId ? `${baseId};messageid=${threadActivityId}` : baseId;
|
|
1033
946
|
const tenantId = source.tenantId ?? source.conversation.tenantId;
|
|
1034
|
-
|
|
947
|
+
if (!source.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
|
|
948
|
+
const serviceUrl = require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(source.serviceUrl);
|
|
1035
949
|
if (options?.serviceUrlBoundary) require_resolve_allowlist.validateMSTeamsProactiveServiceUrlBoundary({
|
|
1036
950
|
cloud: options.serviceUrlBoundary.cloud,
|
|
1037
951
|
conversationId,
|
|
@@ -1059,74 +973,52 @@ function buildSdkConversationReference(source, options) {
|
|
|
1059
973
|
...source.aadObjectId ? { aadObjectId: source.aadObjectId } : {}
|
|
1060
974
|
};
|
|
1061
975
|
}
|
|
1062
|
-
function
|
|
1063
|
-
|
|
1064
|
-
try {
|
|
1065
|
-
return require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(left) === right;
|
|
1066
|
-
} catch {
|
|
1067
|
-
return false;
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
function stringifyReferenceFallbackActivity(activity) {
|
|
1071
|
-
if (typeof activity === "string") return activity;
|
|
1072
|
-
if (activity == null) return "";
|
|
1073
|
-
if (typeof activity === "number" || typeof activity === "boolean" || typeof activity === "bigint") return String(activity);
|
|
1074
|
-
return "";
|
|
1075
|
-
}
|
|
1076
|
-
async function getApiClientForReference(app, ref) {
|
|
1077
|
-
const api = app.api;
|
|
1078
|
-
if (sameServiceUrl(api.serviceUrl, ref.serviceUrl)) return api;
|
|
1079
|
-
const appInternals = app;
|
|
1080
|
-
const httpClient = appInternals.api?.http ?? appInternals.client;
|
|
1081
|
-
if (!httpClient) return api;
|
|
1082
|
-
const { Client } = await loadMSTeamsApiModule();
|
|
1083
|
-
return new Client(ref.serviceUrl, httpClient);
|
|
1084
|
-
}
|
|
1085
|
-
function mergeReferenceIntoActivity(activity, ref) {
|
|
1086
|
-
const source = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(activity) ?? {
|
|
1087
|
-
type: "message",
|
|
1088
|
-
text: stringifyReferenceFallbackActivity(activity)
|
|
1089
|
-
};
|
|
1090
|
-
const existingChannelData = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(source.channelData);
|
|
1091
|
-
const existingTenant = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(existingChannelData?.tenant);
|
|
1092
|
-
let channelData = existingChannelData ? { ...existingChannelData } : void 0;
|
|
1093
|
-
if (ref.tenantId) {
|
|
1094
|
-
channelData ??= {};
|
|
1095
|
-
channelData.tenant = existingTenant ? {
|
|
1096
|
-
...existingTenant,
|
|
1097
|
-
id: ref.tenantId
|
|
1098
|
-
} : { id: ref.tenantId };
|
|
1099
|
-
}
|
|
1100
|
-
return {
|
|
1101
|
-
...source,
|
|
1102
|
-
channelId: ref.channelId,
|
|
1103
|
-
from: ref.bot,
|
|
1104
|
-
recipient: ref.user,
|
|
1105
|
-
conversation: ref.conversation,
|
|
1106
|
-
...channelData ? { channelData } : {},
|
|
1107
|
-
locale: ref.locale,
|
|
1108
|
-
...ref.tenantId ? { tenantId: ref.tenantId } : {},
|
|
1109
|
-
...ref.aadObjectId ? { aadObjectId: ref.aadObjectId } : {}
|
|
1110
|
-
};
|
|
976
|
+
function getApiClientForReference(app, ref) {
|
|
977
|
+
return app.api.serviceUrl === ref.serviceUrl ? app.api : app.api.fromServiceUrl({ serviceUrl: ref.serviceUrl });
|
|
1111
978
|
}
|
|
1112
979
|
async function sendMSTeamsActivityWithReference(app, source, activity, options) {
|
|
1113
980
|
return require_resolve_allowlist.withMSTeamsConnectorHandoff(options ?? {}, async (handoff) => {
|
|
1114
981
|
require_resolve_allowlist.assertMSTeamsSendHandoff(handoff);
|
|
1115
982
|
const ref = buildSdkConversationReference(source, options);
|
|
1116
|
-
const activities =
|
|
1117
|
-
const
|
|
983
|
+
const activities = getApiClientForReference(app, ref).conversations.activities(ref.conversation.id);
|
|
984
|
+
const quotedActivity = options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity;
|
|
985
|
+
const activitySource = typeof quotedActivity === "string" ? {
|
|
986
|
+
type: "message",
|
|
987
|
+
text: quotedActivity
|
|
988
|
+
} : quotedActivity;
|
|
989
|
+
const existingChannelData = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(activitySource.channelData);
|
|
990
|
+
const existingTenant = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(existingChannelData?.tenant);
|
|
991
|
+
let channelData = existingChannelData ? { ...existingChannelData } : void 0;
|
|
992
|
+
if (ref.tenantId) {
|
|
993
|
+
channelData ??= {};
|
|
994
|
+
channelData.tenant = existingTenant ? {
|
|
995
|
+
...existingTenant,
|
|
996
|
+
id: ref.tenantId
|
|
997
|
+
} : { id: ref.tenantId };
|
|
998
|
+
}
|
|
999
|
+
const activityWithRef = {
|
|
1000
|
+
...activitySource,
|
|
1001
|
+
channelId: ref.channelId,
|
|
1002
|
+
from: ref.bot,
|
|
1003
|
+
recipient: ref.user,
|
|
1004
|
+
conversation: ref.conversation,
|
|
1005
|
+
...channelData ? { channelData } : {},
|
|
1006
|
+
locale: ref.locale,
|
|
1007
|
+
...ref.tenantId ? { tenantId: ref.tenantId } : {},
|
|
1008
|
+
...ref.aadObjectId ? { aadObjectId: ref.aadObjectId } : {}
|
|
1009
|
+
};
|
|
1118
1010
|
const isTargeted = activityWithRef.recipient?.isTargeted === true;
|
|
1119
1011
|
if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
|
|
1120
1012
|
const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
|
|
1121
1013
|
require_resolve_allowlist.assertMSTeamsSendHandoff(handoff);
|
|
1122
1014
|
if (activityId) {
|
|
1123
|
-
const res = isTargeted
|
|
1015
|
+
const res = isTargeted ? await activities.updateTargeted(activityId, activityWithRef) : await activities.update(activityId, activityWithRef);
|
|
1124
1016
|
return {
|
|
1125
1017
|
...activityWithRef,
|
|
1126
1018
|
...res && typeof res === "object" ? res : {}
|
|
1127
1019
|
};
|
|
1128
1020
|
}
|
|
1129
|
-
const res = isTargeted
|
|
1021
|
+
const res = isTargeted ? await activities.createTargeted(activityWithRef) : await activities.create(activityWithRef);
|
|
1130
1022
|
const conversationId = ref.conversation.id.split(";")[0] ?? ref.conversation.id;
|
|
1131
1023
|
if (res.id && activityWithRef.type === "message" && ref.conversation.conversationType === "channel" && ref.conversation.id === conversationId) recordMSTeamsSentMessage(conversationId, res.id, {
|
|
1132
1024
|
accountId: options?.accountId,
|
|
@@ -1140,11 +1032,11 @@ async function sendMSTeamsActivityWithReference(app, source, activity, options)
|
|
|
1140
1032
|
}
|
|
1141
1033
|
async function updateMSTeamsActivityWithReference(app, source, activityId, activity, options) {
|
|
1142
1034
|
const ref = buildSdkConversationReference(source, options);
|
|
1143
|
-
return
|
|
1035
|
+
return getApiClientForReference(app, ref).conversations.activities(ref.conversation.id).update(activityId, activity);
|
|
1144
1036
|
}
|
|
1145
1037
|
async function deleteMSTeamsActivityWithReference(app, source, activityId, options) {
|
|
1146
1038
|
const ref = buildSdkConversationReference(source, options);
|
|
1147
|
-
return
|
|
1039
|
+
return getApiClientForReference(app, ref).conversations.activities(ref.conversation.id).delete(activityId);
|
|
1148
1040
|
}
|
|
1149
1041
|
// extensions/msteams/src/messenger.ts
|
|
1150
1042
|
const MSTEAMS_SEND_ATTEMPTS = 3;
|
|
@@ -1152,7 +1044,7 @@ const MSTEAMS_SEND_RETRY_MAX_DELAY_MS = 1e4;
|
|
|
1152
1044
|
function buildConversationReference(ref) {
|
|
1153
1045
|
const conversationId = ref.conversation?.id?.trim();
|
|
1154
1046
|
if (!conversationId) throw new Error("Invalid stored reference: missing conversation.id");
|
|
1155
|
-
const agent = ref.agent ?? ref.bot
|
|
1047
|
+
const agent = ref.agent ?? ref.bot;
|
|
1156
1048
|
if (agent == null || !agent.id) throw new Error("Invalid stored reference: missing agent.id");
|
|
1157
1049
|
const user = ref.user;
|
|
1158
1050
|
if (!user?.id) throw new Error("Invalid stored reference: missing user.id");
|
|
@@ -1183,105 +1075,109 @@ function renderReplyPayloadsToMessages(replies, options) {
|
|
|
1183
1075
|
const chunkMode = options.chunkMode ?? "length";
|
|
1184
1076
|
for (const payload of replies) {
|
|
1185
1077
|
const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: formatMSTeamsMarkdown(payload.text ?? "", options.tableMode) });
|
|
1186
|
-
if (!reply.hasContent) continue;
|
|
1078
|
+
if (!reply.hasContent && !payload.presentation) continue;
|
|
1187
1079
|
if (reply.text) {
|
|
1188
1080
|
const chunks = require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(reply.text, chunkLimit, chunkMode);
|
|
1189
1081
|
for (const chunk of chunks) {
|
|
1190
1082
|
const text = chunk.trim();
|
|
1191
|
-
if (text
|
|
1083
|
+
if (text) out.push({ text });
|
|
1192
1084
|
}
|
|
1193
1085
|
}
|
|
1086
|
+
if (payload.presentation) out.push({ adaptiveCard: require_presentation.buildMSTeamsPresentationCard({ presentation: payload.presentation }) });
|
|
1194
1087
|
out.push(...reply.mediaUrls.map((mediaUrl) => ({ mediaUrl })));
|
|
1195
1088
|
}
|
|
1196
1089
|
return out;
|
|
1197
1090
|
}
|
|
1198
|
-
async function buildActivity(msg, conversationRef, tokenProvider, sharePointSiteId, mediaMaxBytes, options) {
|
|
1199
|
-
const activity = buildMSTeamsMessageActivity(msg.text);
|
|
1200
|
-
activity.channelData = { feedbackLoopEnabled: options?.feedbackLoopEnabled ?? false };
|
|
1201
|
-
if (msg.mediaUrl) {
|
|
1202
|
-
let contentUrl = msg.mediaUrl;
|
|
1203
|
-
let contentType = await getMimeType(msg.mediaUrl);
|
|
1204
|
-
let fileName = await extractFilename(msg.mediaUrl);
|
|
1205
|
-
if (isLocalPath(msg.mediaUrl)) {
|
|
1206
|
-
const maxBytes = mediaMaxBytes ?? 104857600;
|
|
1207
|
-
const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
|
|
1208
|
-
contentType = media.contentType ?? contentType;
|
|
1209
|
-
fileName = media.fileName ?? fileName;
|
|
1210
|
-
const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(conversationRef.conversation?.conversationType);
|
|
1211
|
-
const isPersonal = conversationType === "personal";
|
|
1212
|
-
const isImage = media.kind === "image";
|
|
1213
|
-
if (requiresFileConsent({
|
|
1214
|
-
conversationType,
|
|
1215
|
-
contentType,
|
|
1216
|
-
bufferSize: media.buffer.length
|
|
1217
|
-
})) {
|
|
1218
|
-
const conversationId = conversationRef.conversation?.id ?? "unknown";
|
|
1219
|
-
require_resolve_allowlist.assertMSTeamsSendHandoff(options);
|
|
1220
|
-
const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
|
|
1221
|
-
media: {
|
|
1222
|
-
buffer: media.buffer,
|
|
1223
|
-
filename: fileName,
|
|
1224
|
-
contentType
|
|
1225
|
-
},
|
|
1226
|
-
conversationId,
|
|
1227
|
-
description: msg.text || void 0
|
|
1228
|
-
});
|
|
1229
|
-
consentActivity["_pendingUploadId"] = uploadId;
|
|
1230
|
-
return consentActivity;
|
|
1231
|
-
}
|
|
1232
|
-
if (!isPersonal && !isImage) {
|
|
1233
|
-
const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
|
|
1234
|
-
if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
|
|
1235
|
-
const chatId = conversationRef.conversation?.id;
|
|
1236
|
-
const uploaded = await uploadAndShareSharePoint({
|
|
1237
|
-
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1238
|
-
buffer: media.buffer,
|
|
1239
|
-
filename: fileName,
|
|
1240
|
-
contentType,
|
|
1241
|
-
tokenProvider,
|
|
1242
|
-
siteId,
|
|
1243
|
-
chatId: chatId ?? void 0,
|
|
1244
|
-
usePerUserSharing: conversationType === "groupchat"
|
|
1245
|
-
});
|
|
1246
|
-
activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
|
|
1247
|
-
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1248
|
-
siteId,
|
|
1249
|
-
itemId: uploaded.itemId,
|
|
1250
|
-
tokenProvider
|
|
1251
|
-
}))];
|
|
1252
|
-
return activity;
|
|
1253
|
-
}
|
|
1254
|
-
const base64 = media.buffer.toString("base64");
|
|
1255
|
-
contentUrl = `data:${media.contentType};base64,${base64}`;
|
|
1256
|
-
}
|
|
1257
|
-
activity.attachments = [{
|
|
1258
|
-
name: fileName,
|
|
1259
|
-
contentType,
|
|
1260
|
-
contentUrl
|
|
1261
|
-
}];
|
|
1262
|
-
}
|
|
1263
|
-
return activity;
|
|
1264
|
-
}
|
|
1265
1091
|
async function sendMSTeamsMessages(params) {
|
|
1266
|
-
const messages = params.messages.filter((m) => m.text && m.text.trim().length > 0 || m.mediaUrl);
|
|
1092
|
+
const messages = params.messages.filter((m) => m.text && m.text.trim().length > 0 || m.mediaUrl || m.adaptiveCard);
|
|
1267
1093
|
if (messages.length === 0) return [];
|
|
1268
1094
|
let providerDispatchStarted = false;
|
|
1269
1095
|
const sendMessageInContext = async (sendFn, message, messageIndex) => {
|
|
1270
|
-
|
|
1271
|
-
|
|
1096
|
+
async function buildActivity() {
|
|
1097
|
+
const msg = message;
|
|
1098
|
+
const { conversationRef, tokenProvider, sharePointSiteId, mediaMaxBytes } = params;
|
|
1099
|
+
const options = {
|
|
1100
|
+
feedbackLoopEnabled: params.feedbackLoopEnabled,
|
|
1101
|
+
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1102
|
+
};
|
|
1103
|
+
const activity = buildMSTeamsMessageActivity(msg.text);
|
|
1104
|
+
if (msg.adaptiveCard) Object.assign(activity, buildMSTeamsAdaptiveCardActivity(msg.adaptiveCard));
|
|
1105
|
+
activity.channelData = { feedbackLoopEnabled: options?.feedbackLoopEnabled ?? false };
|
|
1106
|
+
if (msg.mediaUrl) {
|
|
1107
|
+
let contentUrl = msg.mediaUrl;
|
|
1108
|
+
let contentType = await getMimeType(msg.mediaUrl);
|
|
1109
|
+
let fileName = await extractFilename(msg.mediaUrl);
|
|
1110
|
+
if (isLocalPath(msg.mediaUrl)) {
|
|
1111
|
+
const maxBytes = mediaMaxBytes ?? 104857600;
|
|
1112
|
+
const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
|
|
1113
|
+
contentType = media.contentType ?? contentType;
|
|
1114
|
+
fileName = media.fileName ?? fileName;
|
|
1115
|
+
const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(conversationRef.conversation?.conversationType);
|
|
1116
|
+
const isPersonal = conversationType === "personal";
|
|
1117
|
+
const isImage = media.kind === "image";
|
|
1118
|
+
if (requiresFileConsent({
|
|
1119
|
+
conversationType,
|
|
1120
|
+
contentType,
|
|
1121
|
+
bufferSize: media.buffer.length
|
|
1122
|
+
})) {
|
|
1123
|
+
const conversationId = conversationRef.conversation?.id ?? "unknown";
|
|
1124
|
+
require_resolve_allowlist.assertMSTeamsSendHandoff(options);
|
|
1125
|
+
const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
|
|
1126
|
+
media: {
|
|
1127
|
+
buffer: media.buffer,
|
|
1128
|
+
filename: fileName,
|
|
1129
|
+
contentType
|
|
1130
|
+
},
|
|
1131
|
+
conversationId,
|
|
1132
|
+
description: msg.text || void 0
|
|
1133
|
+
});
|
|
1134
|
+
return {
|
|
1135
|
+
activity: consentActivity,
|
|
1136
|
+
pendingUploadId: uploadId
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
if (!isPersonal && !isImage) {
|
|
1140
|
+
const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
|
|
1141
|
+
if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
|
|
1142
|
+
const chatId = conversationRef.conversation?.id;
|
|
1143
|
+
const uploaded = await uploadAndShareSharePoint({
|
|
1144
|
+
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1145
|
+
buffer: media.buffer,
|
|
1146
|
+
filename: fileName,
|
|
1147
|
+
contentType,
|
|
1148
|
+
tokenProvider,
|
|
1149
|
+
siteId,
|
|
1150
|
+
chatId,
|
|
1151
|
+
usePerUserSharing: conversationType === "groupchat"
|
|
1152
|
+
});
|
|
1153
|
+
activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
|
|
1154
|
+
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1155
|
+
siteId,
|
|
1156
|
+
itemId: uploaded.itemId,
|
|
1157
|
+
tokenProvider
|
|
1158
|
+
}))];
|
|
1159
|
+
return { activity };
|
|
1160
|
+
}
|
|
1161
|
+
const base64 = media.buffer.toString("base64");
|
|
1162
|
+
contentUrl = `data:${media.contentType};base64,${base64}`;
|
|
1163
|
+
}
|
|
1164
|
+
activity.attachments = [{
|
|
1165
|
+
name: fileName,
|
|
1166
|
+
contentType,
|
|
1167
|
+
contentUrl
|
|
1168
|
+
}];
|
|
1169
|
+
}
|
|
1170
|
+
return { activity };
|
|
1171
|
+
}
|
|
1172
|
+
let prepared;
|
|
1272
1173
|
let response;
|
|
1273
1174
|
try {
|
|
1274
1175
|
response = await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(async () => {
|
|
1275
1176
|
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
1276
|
-
|
|
1277
|
-
feedbackLoopEnabled: params.feedbackLoopEnabled,
|
|
1278
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1279
|
-
});
|
|
1280
|
-
pendingUploadId ??= typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
|
|
1281
|
-
delete activity["_pendingUploadId"];
|
|
1177
|
+
prepared ??= await buildActivity();
|
|
1282
1178
|
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
1283
1179
|
providerDispatchStarted = true;
|
|
1284
|
-
return await sendFn(activity);
|
|
1180
|
+
return await sendFn(prepared.activity);
|
|
1285
1181
|
}, {
|
|
1286
1182
|
attempts: MSTEAMS_SEND_ATTEMPTS,
|
|
1287
1183
|
minDelayMs: 0,
|
|
@@ -1310,54 +1206,33 @@ async function sendMSTeamsMessages(params) {
|
|
|
1310
1206
|
}
|
|
1311
1207
|
const messageId = extractMessageId(response) ?? "unknown";
|
|
1312
1208
|
await params.onMessageSent?.(messageId, messageIndex);
|
|
1209
|
+
const pendingUploadId = prepared?.pendingUploadId;
|
|
1313
1210
|
if (pendingUploadId && messageId !== "unknown") setPendingUploadActivityId(pendingUploadId, messageId);
|
|
1314
1211
|
return messageId;
|
|
1315
1212
|
};
|
|
1316
|
-
|
|
1213
|
+
let sendFn;
|
|
1214
|
+
const ctx = params.replyStyle === "thread" ? params.context : void 0;
|
|
1215
|
+
if (ctx) sendFn = (activity) => require_resolve_allowlist.withMSTeamsConnectorHandoff(params, () => ctx.sendActivity(activity));
|
|
1216
|
+
else {
|
|
1317
1217
|
let baseRef;
|
|
1318
1218
|
try {
|
|
1319
1219
|
baseRef = buildConversationReference(params.conversationRef);
|
|
1320
1220
|
} catch (error) {
|
|
1321
|
-
if (providerDispatchStarted) throw error;
|
|
1322
1221
|
throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams conversation preparation failed", { cause: error });
|
|
1323
1222
|
}
|
|
1324
1223
|
const isChannel = params.conversationRef.conversation?.conversationType === "channel";
|
|
1325
|
-
const
|
|
1224
|
+
const threadActivityId = params.replyStyle === "thread" && isChannel ? params.conversationRef.threadId ?? params.conversationRef.activityId : void 0;
|
|
1225
|
+
sendFn = (activity) => sendMSTeamsActivityWithReference(params.app, baseRef, activity, {
|
|
1326
1226
|
accountId: params.accountId,
|
|
1327
1227
|
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
|
|
1328
1228
|
onPlatformSendDispatch: params.onPlatformSendDispatch,
|
|
1329
|
-
threadActivityId
|
|
1229
|
+
threadActivityId,
|
|
1330
1230
|
serviceUrlBoundary: params.serviceUrlBoundary
|
|
1331
1231
|
});
|
|
1332
|
-
const messageIds = [];
|
|
1333
|
-
for (const [idx, message] of batch.entries()) messageIds.push(await sendMessageInContext(sendFn, message, startIndex + idx));
|
|
1334
|
-
return messageIds;
|
|
1335
|
-
};
|
|
1336
|
-
const resolvedThreadId = params.conversationRef.threadId ?? params.conversationRef.activityId;
|
|
1337
|
-
if (params.replyStyle === "thread") {
|
|
1338
|
-
const ctx = params.context;
|
|
1339
|
-
if (!ctx) return await sendProactively(messages, 0, resolvedThreadId);
|
|
1340
|
-
const sendFn = (activity) => require_resolve_allowlist.withMSTeamsConnectorHandoff(params, () => ctx.sendActivity(activity));
|
|
1341
|
-
const messageIds = [];
|
|
1342
|
-
for (const [idx, message] of messages.entries()) {
|
|
1343
|
-
const result = await withRevokedProxyFallback({
|
|
1344
|
-
run: async () => ({
|
|
1345
|
-
ids: [await sendMessageInContext(sendFn, message, idx)],
|
|
1346
|
-
fellBack: false
|
|
1347
|
-
}),
|
|
1348
|
-
onRevoked: async () => {
|
|
1349
|
-
return {
|
|
1350
|
-
ids: await sendProactively(messages.slice(idx), idx, resolvedThreadId),
|
|
1351
|
-
fellBack: true
|
|
1352
|
-
};
|
|
1353
|
-
}
|
|
1354
|
-
});
|
|
1355
|
-
messageIds.push(...result.ids);
|
|
1356
|
-
if (result.fellBack) return messageIds;
|
|
1357
|
-
}
|
|
1358
|
-
return messageIds;
|
|
1359
1232
|
}
|
|
1360
|
-
|
|
1233
|
+
const messageIds = [];
|
|
1234
|
+
for (const [idx, message] of messages.entries()) messageIds.push(await sendMessageInContext(sendFn, message, idx));
|
|
1235
|
+
return messageIds;
|
|
1361
1236
|
}
|
|
1362
1237
|
// extensions/msteams/src/polls.ts
|
|
1363
1238
|
const MSTEAMS_POLLS_NAMESPACE = "polls";
|
|
@@ -1431,57 +1306,51 @@ function extractMSTeamsPollVote(activity) {
|
|
|
1431
1306
|
}
|
|
1432
1307
|
function buildMSTeamsPollCard(params) {
|
|
1433
1308
|
const pollId = node_crypto.default.randomUUID();
|
|
1434
|
-
const maxSelections =
|
|
1309
|
+
const maxSelections = params.maxSelections !== void 0 && params.maxSelections > 1 ? Math.floor(params.maxSelections) : 1;
|
|
1435
1310
|
const cappedMaxSelections = Math.min(Math.max(1, maxSelections), params.options.length);
|
|
1436
1311
|
const choices = params.options.map((option, index) => ({
|
|
1437
1312
|
title: option,
|
|
1438
1313
|
value: String(index)
|
|
1439
1314
|
}));
|
|
1440
1315
|
const hint = cappedMaxSelections > 1 ? `Select up to ${cappedMaxSelections} options.` : "Select one option.";
|
|
1441
|
-
const card = {
|
|
1442
|
-
type: "AdaptiveCard",
|
|
1443
|
-
version: "1.5",
|
|
1444
|
-
body: [
|
|
1445
|
-
{
|
|
1446
|
-
type: "TextBlock",
|
|
1447
|
-
text: params.question,
|
|
1448
|
-
wrap: true,
|
|
1449
|
-
weight: "Bolder",
|
|
1450
|
-
size: "Medium"
|
|
1451
|
-
},
|
|
1452
|
-
{
|
|
1453
|
-
type: "Input.ChoiceSet",
|
|
1454
|
-
id: "choices",
|
|
1455
|
-
isMultiSelect: cappedMaxSelections > 1,
|
|
1456
|
-
style: "expanded",
|
|
1457
|
-
choices
|
|
1458
|
-
},
|
|
1459
|
-
{
|
|
1460
|
-
type: "TextBlock",
|
|
1461
|
-
text: hint,
|
|
1462
|
-
wrap: true,
|
|
1463
|
-
isSubtle: true,
|
|
1464
|
-
spacing: "Small"
|
|
1465
|
-
}
|
|
1466
|
-
],
|
|
1467
|
-
actions: [{
|
|
1468
|
-
type: "Action.Execute",
|
|
1469
|
-
title: "Vote",
|
|
1470
|
-
verb: "openclaw.poll.vote",
|
|
1471
|
-
data: {
|
|
1472
|
-
openclawPollId: pollId,
|
|
1473
|
-
pollId
|
|
1474
|
-
}
|
|
1475
|
-
}]
|
|
1476
|
-
};
|
|
1477
|
-
const fallbackLines = [`Poll: ${params.question}`, ...params.options.map((option, index) => `${index + 1}. ${option}`)];
|
|
1478
1316
|
return {
|
|
1479
1317
|
pollId,
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1318
|
+
card: {
|
|
1319
|
+
type: "AdaptiveCard",
|
|
1320
|
+
version: "1.5",
|
|
1321
|
+
body: [
|
|
1322
|
+
{
|
|
1323
|
+
type: "TextBlock",
|
|
1324
|
+
text: params.question,
|
|
1325
|
+
wrap: true,
|
|
1326
|
+
weight: "Bolder",
|
|
1327
|
+
size: "Medium"
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
type: "Input.ChoiceSet",
|
|
1331
|
+
id: "choices",
|
|
1332
|
+
isMultiSelect: cappedMaxSelections > 1,
|
|
1333
|
+
style: "expanded",
|
|
1334
|
+
choices
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
type: "TextBlock",
|
|
1338
|
+
text: hint,
|
|
1339
|
+
wrap: true,
|
|
1340
|
+
isSubtle: true,
|
|
1341
|
+
spacing: "Small"
|
|
1342
|
+
}
|
|
1343
|
+
],
|
|
1344
|
+
actions: [{
|
|
1345
|
+
type: "Action.Execute",
|
|
1346
|
+
title: "Vote",
|
|
1347
|
+
verb: "openclaw.poll.vote",
|
|
1348
|
+
data: {
|
|
1349
|
+
openclawPollId: pollId,
|
|
1350
|
+
pollId
|
|
1351
|
+
}
|
|
1352
|
+
}]
|
|
1353
|
+
}
|
|
1485
1354
|
};
|
|
1486
1355
|
}
|
|
1487
1356
|
function isPollExpired(poll) {
|
|
@@ -1516,59 +1385,12 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1516
1385
|
namespace: require_delegated_state.resolveMSTeamsAccountStateNamespace(MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE, params?.accountId),
|
|
1517
1386
|
maxEntries: MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS
|
|
1518
1387
|
});
|
|
1519
|
-
const readPollVotes = async (pollId) => {
|
|
1520
|
-
const votes = {};
|
|
1521
|
-
for (const row of await voteBucketStore.entries()) if (row.value.pollId === pollId) Object.assign(votes, row.value.votes);
|
|
1522
|
-
return votes;
|
|
1523
|
-
};
|
|
1524
1388
|
const deletePollVotes = async (pollId, cachedRows) => {
|
|
1525
1389
|
for (const row of cachedRows?.values() ?? await voteBucketStore.entries()) if (row.value.pollId === pollId) {
|
|
1526
1390
|
await voteBucketStore.delete(row.key);
|
|
1527
1391
|
cachedRows?.delete(row.key);
|
|
1528
1392
|
}
|
|
1529
1393
|
};
|
|
1530
|
-
const registerPollVotes = async (pollId, votes, updatedAt) => {
|
|
1531
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
1532
|
-
for (const [voterId, selections] of Object.entries(votes)) {
|
|
1533
|
-
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1534
|
-
const bucketVotes = buckets.get(bucket) ?? {};
|
|
1535
|
-
bucketVotes[voterId] = selections;
|
|
1536
|
-
buckets.set(bucket, bucketVotes);
|
|
1537
|
-
}
|
|
1538
|
-
for (const [bucket, bucketVotes] of buckets) {
|
|
1539
|
-
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1540
|
-
const existing = await voteBucketStore.lookup(key);
|
|
1541
|
-
await voteBucketStore.register(key, require_delegated_state.toPluginJsonValue({
|
|
1542
|
-
pollId,
|
|
1543
|
-
bucket,
|
|
1544
|
-
votes: {
|
|
1545
|
-
...bucketVotes,
|
|
1546
|
-
...existing?.votes
|
|
1547
|
-
},
|
|
1548
|
-
updatedAt
|
|
1549
|
-
}));
|
|
1550
|
-
}
|
|
1551
|
-
};
|
|
1552
|
-
const registerPollVote = async (pollId, voterId, selections, updatedAt) => {
|
|
1553
|
-
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1554
|
-
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1555
|
-
const existing = await voteBucketStore.lookup(key);
|
|
1556
|
-
await voteBucketStore.register(key, require_delegated_state.toPluginJsonValue({
|
|
1557
|
-
pollId,
|
|
1558
|
-
bucket,
|
|
1559
|
-
votes: {
|
|
1560
|
-
...existing?.votes,
|
|
1561
|
-
[voterId]: selections
|
|
1562
|
-
},
|
|
1563
|
-
updatedAt
|
|
1564
|
-
}));
|
|
1565
|
-
};
|
|
1566
|
-
const reconstructPoll = async (metadata) => {
|
|
1567
|
-
return {
|
|
1568
|
-
...metadata,
|
|
1569
|
-
votes: await readPollVotes(metadata.id)
|
|
1570
|
-
};
|
|
1571
|
-
};
|
|
1572
1394
|
const prunePollStoreToLimit = async () => {
|
|
1573
1395
|
let voteRows;
|
|
1574
1396
|
const deletePrunedPollVotes = async (pollId) => {
|
|
@@ -1595,10 +1417,8 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1595
1417
|
};
|
|
1596
1418
|
const createPoll = async (poll) => {
|
|
1597
1419
|
await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
1598
|
-
|
|
1599
|
-
await pollStore.register(buildMSTeamsPollStateKey(poll.id), require_delegated_state.toPluginJsonValue(metadata));
|
|
1420
|
+
await pollStore.register(buildMSTeamsPollStateKey(poll.id), require_delegated_state.toPluginJsonValue(poll));
|
|
1600
1421
|
await deletePollVotes(poll.id);
|
|
1601
|
-
await registerPollVotes(poll.id, votes, poll.updatedAt ?? poll.createdAt);
|
|
1602
1422
|
await prunePollStoreToLimit();
|
|
1603
1423
|
});
|
|
1604
1424
|
};
|
|
@@ -1606,7 +1426,7 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1606
1426
|
const poll = await pollStore.lookup(buildMSTeamsPollStateKey(pollId));
|
|
1607
1427
|
if (!poll) return null;
|
|
1608
1428
|
if (isPollExpired(poll)) return null;
|
|
1609
|
-
return
|
|
1429
|
+
return poll;
|
|
1610
1430
|
};
|
|
1611
1431
|
const recordVote = async (vote) => {
|
|
1612
1432
|
return await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
@@ -1618,13 +1438,26 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1618
1438
|
await deletePollVotes(vote.pollId);
|
|
1619
1439
|
return null;
|
|
1620
1440
|
}
|
|
1621
|
-
const normalized = normalizeMSTeamsPollSelections(
|
|
1441
|
+
const normalized = normalizeMSTeamsPollSelections(poll, vote.selections);
|
|
1622
1442
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1623
1443
|
poll.updatedAt = updatedAt;
|
|
1624
|
-
await pollStore.register(pollKey,
|
|
1625
|
-
|
|
1444
|
+
await pollStore.register(pollKey, poll);
|
|
1445
|
+
const pollId = vote.pollId;
|
|
1446
|
+
const voterId = vote.voterId;
|
|
1447
|
+
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1448
|
+
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1449
|
+
const existing = await voteBucketStore.lookup(key);
|
|
1450
|
+
await voteBucketStore.register(key, {
|
|
1451
|
+
pollId,
|
|
1452
|
+
bucket,
|
|
1453
|
+
votes: {
|
|
1454
|
+
...existing?.votes,
|
|
1455
|
+
[voterId]: normalized
|
|
1456
|
+
},
|
|
1457
|
+
updatedAt
|
|
1458
|
+
});
|
|
1626
1459
|
await prunePollStoreToLimit();
|
|
1627
|
-
return
|
|
1460
|
+
return true;
|
|
1628
1461
|
});
|
|
1629
1462
|
};
|
|
1630
1463
|
return {
|
|
@@ -1633,44 +1466,11 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1633
1466
|
recordVote
|
|
1634
1467
|
};
|
|
1635
1468
|
}
|
|
1636
|
-
// extensions/msteams/src/conversation-store-helpers.ts
|
|
1637
|
-
function mergeStoredConversationReference(existing, incoming, nowIso) {
|
|
1638
|
-
return {
|
|
1639
|
-
...existing?.timezone && !incoming.timezone ? { timezone: existing.timezone } : {},
|
|
1640
|
-
...existing?.tenantId && !incoming.tenantId ? { tenantId: existing.tenantId } : {},
|
|
1641
|
-
...existing?.aadObjectId && !incoming.aadObjectId ? { aadObjectId: existing.aadObjectId } : {},
|
|
1642
|
-
...incoming,
|
|
1643
|
-
lastSeenAt: nowIso
|
|
1644
|
-
};
|
|
1645
|
-
}
|
|
1646
|
-
function findPreferredDmConversationByUserId(entries, id) {
|
|
1647
|
-
const target = id.trim();
|
|
1648
|
-
if (!target) return null;
|
|
1649
|
-
let preferred = null;
|
|
1650
|
-
let preferredIsPersonal = false;
|
|
1651
|
-
let preferredTimestamp = 0;
|
|
1652
|
-
for (const entry of entries) {
|
|
1653
|
-
if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
|
|
1654
|
-
const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType);
|
|
1655
|
-
if (convType === "channel" || convType === "groupchat") continue;
|
|
1656
|
-
const isPersonal = convType === "personal";
|
|
1657
|
-
const timestamp = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(entry.reference.lastSeenAt) ?? 0;
|
|
1658
|
-
if (!preferred || isPersonal && !preferredIsPersonal || isPersonal === preferredIsPersonal && timestamp > preferredTimestamp) {
|
|
1659
|
-
preferred = entry;
|
|
1660
|
-
preferredIsPersonal = isPersonal;
|
|
1661
|
-
preferredTimestamp = timestamp;
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
return preferred;
|
|
1665
|
-
}
|
|
1666
1469
|
// extensions/msteams/src/conversation-store-state.ts
|
|
1667
1470
|
const MSTEAMS_CONVERSATIONS_NAMESPACE = "conversations";
|
|
1668
1471
|
const MSTEAMS_MAX_CONVERSATIONS = 1e3;
|
|
1669
1472
|
const MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS = 2e3;
|
|
1670
1473
|
const MSTEAMS_CONVERSATION_TTL_MS = 31536e6;
|
|
1671
|
-
function buildMSTeamsConversationStateKey(conversationId) {
|
|
1672
|
-
return node_crypto.default.createHash("sha256").update(conversationId).digest("hex");
|
|
1673
|
-
}
|
|
1674
1474
|
function getStoredConversationId(reference) {
|
|
1675
1475
|
const rawId = reference.conversation?.id;
|
|
1676
1476
|
return rawId ? require_resolve_allowlist.normalizeMSTeamsConversationId(rawId) : null;
|
|
@@ -1687,7 +1487,7 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1687
1487
|
};
|
|
1688
1488
|
const lookupStored = async (conversationId) => {
|
|
1689
1489
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1690
|
-
const value = await conversationStore.lookup(
|
|
1490
|
+
const value = await conversationStore.lookup((0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(normalizedId));
|
|
1691
1491
|
return value && !isExpired(value) ? value : null;
|
|
1692
1492
|
};
|
|
1693
1493
|
const list = async () => {
|
|
@@ -1705,7 +1505,7 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1705
1505
|
};
|
|
1706
1506
|
const register = async (conversationId, reference) => {
|
|
1707
1507
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1708
|
-
await conversationStore.register(
|
|
1508
|
+
await conversationStore.register((0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(normalizedId), require_delegated_state.toPluginJsonValue({
|
|
1709
1509
|
...reference,
|
|
1710
1510
|
conversation: {
|
|
1711
1511
|
...reference.conversation,
|
|
@@ -1721,29 +1521,54 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1721
1521
|
rows.push(row);
|
|
1722
1522
|
}
|
|
1723
1523
|
if (rows.length <= MSTEAMS_MAX_CONVERSATIONS) return;
|
|
1724
|
-
|
|
1524
|
+
rows.sort((a, b) => {
|
|
1725
1525
|
const aTs = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(a.value.lastSeenAt) ?? 0;
|
|
1726
1526
|
const bTs = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(b.value.lastSeenAt) ?? 0;
|
|
1727
1527
|
const aId = getStoredConversationId(a.value) ?? a.key;
|
|
1728
1528
|
const bId = getStoredConversationId(b.value) ?? b.key;
|
|
1729
1529
|
return aTs - bTs || aId.localeCompare(bId);
|
|
1730
1530
|
});
|
|
1731
|
-
for (const row of
|
|
1531
|
+
for (const row of rows.slice(0, rows.length - MSTEAMS_MAX_CONVERSATIONS)) await conversationStore.delete(row.key);
|
|
1732
1532
|
};
|
|
1733
1533
|
const findPreferredDmByUserId = async (id) => {
|
|
1734
|
-
|
|
1534
|
+
const entries = await list();
|
|
1535
|
+
const target = id.trim();
|
|
1536
|
+
if (!target) return null;
|
|
1537
|
+
let preferred = null;
|
|
1538
|
+
let preferredIsPersonal = false;
|
|
1539
|
+
let preferredTimestamp = 0;
|
|
1540
|
+
for (const entry of entries) {
|
|
1541
|
+
if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
|
|
1542
|
+
const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType);
|
|
1543
|
+
if (convType === "channel" || convType === "groupchat") continue;
|
|
1544
|
+
const isPersonal = convType === "personal";
|
|
1545
|
+
const timestamp = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(entry.reference.lastSeenAt) ?? 0;
|
|
1546
|
+
if (!preferred || isPersonal && !preferredIsPersonal || isPersonal === preferredIsPersonal && timestamp > preferredTimestamp) {
|
|
1547
|
+
preferred = entry;
|
|
1548
|
+
preferredIsPersonal = isPersonal;
|
|
1549
|
+
preferredTimestamp = timestamp;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return preferred;
|
|
1735
1553
|
};
|
|
1736
1554
|
const upsert = async (conversationId, reference) => {
|
|
1737
1555
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1738
1556
|
await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
1739
|
-
const
|
|
1740
|
-
|
|
1557
|
+
const previous = await lookupStored(normalizedId) ?? void 0;
|
|
1558
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
1559
|
+
await register(normalizedId, {
|
|
1560
|
+
...previous?.timezone && !reference.timezone ? { timezone: previous.timezone } : {},
|
|
1561
|
+
...previous?.tenantId && !reference.tenantId ? { tenantId: previous.tenantId } : {},
|
|
1562
|
+
...previous?.aadObjectId && !reference.aadObjectId ? { aadObjectId: previous.aadObjectId } : {},
|
|
1563
|
+
...reference,
|
|
1564
|
+
lastSeenAt: nowIso
|
|
1565
|
+
});
|
|
1741
1566
|
});
|
|
1742
1567
|
};
|
|
1743
1568
|
const remove = async (conversationId) => {
|
|
1744
1569
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1745
1570
|
return await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
1746
|
-
return await conversationStore.delete(
|
|
1571
|
+
return await conversationStore.delete((0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(normalizedId));
|
|
1747
1572
|
});
|
|
1748
1573
|
};
|
|
1749
1574
|
return {
|
|
@@ -1754,12 +1579,6 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1754
1579
|
findPreferredDmByUserId
|
|
1755
1580
|
};
|
|
1756
1581
|
}
|
|
1757
|
-
Object.defineProperty(exports, "FILE_CONSENT_THRESHOLD_BYTES", {
|
|
1758
|
-
enumerable: true,
|
|
1759
|
-
get: function() {
|
|
1760
|
-
return FILE_CONSENT_THRESHOLD_BYTES;
|
|
1761
|
-
}
|
|
1762
|
-
});
|
|
1763
1582
|
Object.defineProperty(exports, "MSTEAMS_MAX_MEDIA_BYTES", {
|
|
1764
1583
|
enumerable: true,
|
|
1765
1584
|
get: function() {
|
|
@@ -1958,9 +1777,3 @@ Object.defineProperty(exports, "wasMSTeamsMessageSentWithPersistence", {
|
|
|
1958
1777
|
return wasMSTeamsMessageSentWithPersistence;
|
|
1959
1778
|
}
|
|
1960
1779
|
});
|
|
1961
|
-
Object.defineProperty(exports, "withRevokedProxyFallback", {
|
|
1962
|
-
enumerable: true,
|
|
1963
|
-
get: function() {
|
|
1964
|
-
return withRevokedProxyFallback;
|
|
1965
|
-
}
|
|
1966
|
-
});
|