@openclaw/msteams 2026.11.3 → 2026.11.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.
- package/dist/.setup/{adapter.runtime-B-6Q3nMI.cjs → adapter.runtime-BB38Rdj_.cjs} +20 -23
- package/dist/.setup/{approval-card-DWPDItvq.cjs → approval-card-BHAKsdAM.cjs} +5 -9
- package/dist/.setup/{approval-handler.runtime-D0jbDypb.cjs → approval-handler.runtime-C16UvawQ.cjs} +4 -4
- package/dist/.setup/{channel-Ci6K9Njb.cjs → channel-BaTw0JW3.cjs} +35 -254
- package/dist/.setup/{channel.runtime-DeHVAVxL.cjs → channel.runtime-Ch2M_-jN.cjs} +65 -107
- package/dist/.setup/{channel.setup-BN3uhq3r.cjs → channel.setup-B9yKGEse.cjs} +161 -262
- package/dist/.setup/{config-schema-CkKdphSp.cjs → config-schema-3lVZ45cB.cjs} +120 -125
- package/dist/.setup/{conversation-store-state-B-4g4uq5.cjs → conversation-store-state-CVhMM0QY.cjs} +411 -601
- package/dist/.setup/{delegated-state-Bv5cWuec.cjs → delegated-state-ilYzKwD8.cjs} +68 -6
- package/dist/.setup/{monitor-cuifGELM.cjs → monitor-b0zPpnmW.cjs} +1883 -2310
- package/dist/.setup/{oauth-BBUQCwmq.cjs → oauth-CUtfkgKE.cjs} +10 -21
- package/dist/.setup/presentation-Duoi9Ijn.cjs +213 -0
- package/dist/.setup/{reaction-types-CwP5RVQB.cjs → reaction-types-C6F6g2nk.cjs} +1 -1
- package/dist/.setup/{resolve-allowlist-gI34MnpE.cjs → resolve-allowlist-7mIEepXB.cjs} +214 -90
- package/dist/.setup/{secret-contract-api-wAyY5UHv.cjs → secret-contract-api-D554HIrH.cjs} +4 -6
- package/dist/.setup/{secret-contract-api-YY3v6MP8.cjs → secret-contract-api-r3hRtbBW.cjs} +1 -1
- package/dist/.setup/{send-C9JY42T6.cjs → send-D1w7a_ip.cjs} +86 -182
- package/dist/.setup/{setup-plugin-api-B-NYBLkF.cjs → setup-plugin-api-ChovZJU6.cjs} +1 -1
- package/dist/.setup/{thread-session-BWVCoYza.cjs → thread-session-CeWYiol_.cjs} +4 -6
- package/dist/.setup/{token-config-bEpua_Q7.cjs → token-config-DICiuJWr.cjs} +0 -2
- package/dist/.source-module-urls/7e43ee3ae4faab430a47269c8217f8d99ec60ecd85233f40e81d03efeb543068.json +1 -0
- 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 +3 -11
- 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-B-4g4uq5.cjs → conversation-store-state-CVhMM0QY.cjs}
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-BloeesfJ.cjs");
|
|
2
2
|
const require_bot_framework_service_url = require("./bot-framework-service-url-B3FWn2SV.cjs");
|
|
3
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
3
|
+
const require_resolve_allowlist = require("./resolve-allowlist-7mIEepXB.cjs");
|
|
4
4
|
const require_runtime = require("./runtime-gZTAuFux.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-ilYzKwD8.cjs");
|
|
7
|
+
const require_presentation = require("./presentation-Duoi9Ijn.cjs");
|
|
8
|
+
const require_channel_setup = require("./channel.setup-B9yKGEse.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}`);
|
|
@@ -146,13 +140,13 @@ const PENDING_UPLOAD_META_NAMESPACE = "pending-uploads";
|
|
|
146
140
|
const PENDING_UPLOAD_CHUNKS_NAMESPACE = "pending-upload-chunks";
|
|
147
141
|
const PENDING_UPLOAD_MUTATION_KEY = "pending-uploads";
|
|
148
142
|
function createMetaStore() {
|
|
149
|
-
return require_runtime.getMSTeamsRuntime().state.
|
|
143
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStoreV2({
|
|
150
144
|
namespace: PENDING_UPLOAD_META_NAMESPACE,
|
|
151
145
|
maxEntries: PENDING_UPLOAD_META_MAX_ENTRIES
|
|
152
146
|
});
|
|
153
147
|
}
|
|
154
148
|
function createChunkStore() {
|
|
155
|
-
return require_runtime.getMSTeamsRuntime().state.
|
|
149
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStoreV2({
|
|
156
150
|
namespace: PENDING_UPLOAD_CHUNKS_NAMESPACE,
|
|
157
151
|
maxEntries: MAX_PENDING_UPLOAD_CHUNK_ROWS
|
|
158
152
|
});
|
|
@@ -166,17 +160,6 @@ function buildMetaKey(id) {
|
|
|
166
160
|
function buildChunkKey(id, index) {
|
|
167
161
|
return `${buildUploadKey(id)}:chunk:${String(index).padStart(4, "0")}`;
|
|
168
162
|
}
|
|
169
|
-
function recordToUpload(record, buffer) {
|
|
170
|
-
return {
|
|
171
|
-
id: record.id,
|
|
172
|
-
buffer,
|
|
173
|
-
filename: record.filename,
|
|
174
|
-
contentType: record.contentType,
|
|
175
|
-
conversationId: record.conversationId,
|
|
176
|
-
consentCardActivityId: record.consentCardActivityId,
|
|
177
|
-
createdAt: record.createdAt
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
163
|
async function deleteUploadRows(id, metaStore, chunkStore) {
|
|
181
164
|
const existing = await metaStore.lookup(buildMetaKey(id));
|
|
182
165
|
await metaStore.delete(buildMetaKey(id));
|
|
@@ -192,11 +175,11 @@ async function registerUploadRows(record, metaStore, chunkStore) {
|
|
|
192
175
|
await pruneUploadStore(metaStore, chunkStore, chunkCount);
|
|
193
176
|
for (let index = 0; index < chunkCount; index += 1) {
|
|
194
177
|
const chunk = buffer.subarray(index * RAW_CHUNK_BYTES, (index + 1) * RAW_CHUNK_BYTES);
|
|
195
|
-
await chunkStore.register(buildChunkKey(record.id, index),
|
|
178
|
+
await chunkStore.register(buildChunkKey(record.id, index), {
|
|
196
179
|
id: record.id,
|
|
197
180
|
index,
|
|
198
181
|
dataBase64: chunk.toString("base64")
|
|
199
|
-
})
|
|
182
|
+
});
|
|
200
183
|
}
|
|
201
184
|
await metaStore.register(buildMetaKey(record.id), require_delegated_state.toPluginJsonValue({
|
|
202
185
|
id: record.id,
|
|
@@ -213,16 +196,25 @@ async function readUploadRows(id, metaStore, chunkStore) {
|
|
|
213
196
|
const meta = await metaStore.lookup(buildMetaKey(id));
|
|
214
197
|
if (!meta) return;
|
|
215
198
|
if (!Number.isSafeInteger(meta.chunkCount) || meta.chunkCount < 1 || meta.chunkCount > MAX_CHUNKS_PER_UPLOAD) return;
|
|
216
|
-
const records = await chunkStore.lookupMany
|
|
199
|
+
const records = await chunkStore.lookupMany(Array.from({ length: meta.chunkCount }, (_, index) => buildChunkKey(id, index)));
|
|
217
200
|
const chunks = [];
|
|
218
201
|
for (let index = 0; index < meta.chunkCount; index += 1) {
|
|
219
|
-
const result = records
|
|
202
|
+
const result = records[index];
|
|
220
203
|
if (result && !result.ok) throw result.error;
|
|
221
|
-
const chunk =
|
|
204
|
+
const chunk = result?.value;
|
|
222
205
|
if (!chunk || chunk.id !== id || chunk.index !== index) return;
|
|
223
206
|
chunks.push(Buffer.from(chunk.dataBase64, "base64"));
|
|
224
207
|
}
|
|
225
|
-
|
|
208
|
+
const buffer = Buffer.concat(chunks, meta.byteLength);
|
|
209
|
+
return {
|
|
210
|
+
id: meta.id,
|
|
211
|
+
buffer,
|
|
212
|
+
filename: meta.filename,
|
|
213
|
+
contentType: meta.contentType,
|
|
214
|
+
conversationId: meta.conversationId,
|
|
215
|
+
consentCardActivityId: meta.consentCardActivityId,
|
|
216
|
+
createdAt: meta.createdAt
|
|
217
|
+
};
|
|
226
218
|
}
|
|
227
219
|
async function pruneUploadStore(metaStore, chunkStore, extraChunkRows = 0) {
|
|
228
220
|
const rows = await metaStore.entries();
|
|
@@ -290,10 +282,10 @@ async function setPendingUploadActivityIdFs(id, activityId) {
|
|
|
290
282
|
await require_delegated_state.withMSTeamsSqliteMutationLock(PENDING_UPLOAD_MUTATION_KEY, async () => {
|
|
291
283
|
const record = await metaStore.lookup(buildMetaKey(id));
|
|
292
284
|
if (!record || Date.now() - record.createdAt > PENDING_UPLOAD_TTL_MS$1) return;
|
|
293
|
-
await metaStore.register(buildMetaKey(id),
|
|
285
|
+
await metaStore.register(buildMetaKey(id), {
|
|
294
286
|
...record,
|
|
295
287
|
consentCardActivityId: activityId
|
|
296
|
-
})
|
|
288
|
+
});
|
|
297
289
|
});
|
|
298
290
|
}
|
|
299
291
|
//#endregion
|
|
@@ -305,14 +297,9 @@ async function setPendingUploadActivityIdFs(id, activityId) {
|
|
|
305
297
|
* before upload. This module stores the file data temporarily until the user
|
|
306
298
|
* accepts or declines, or until the TTL expires.
|
|
307
299
|
*/
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
pendingUploadTimers: /* @__PURE__ */ new Map()
|
|
312
|
-
}), (state) => {
|
|
313
|
-
for (const timer of state.pendingUploadTimers.values()) clearTimeout(timer);
|
|
314
|
-
state.pendingUploadTimers.clear();
|
|
315
|
-
state.pendingUploads.clear();
|
|
300
|
+
const pendingUploads = (0, openclaw_plugin_sdk_global_singleton.resolveGlobalSingleton)(Symbol.for("openclaw.msteams.pendingUploadState"), () => /* @__PURE__ */ new Map(), (state) => {
|
|
301
|
+
for (const { timer } of state.values()) clearTimeout(timer);
|
|
302
|
+
state.clear();
|
|
316
303
|
});
|
|
317
304
|
const PENDING_UPLOAD_TTL_MS = 3e5;
|
|
318
305
|
/**
|
|
@@ -326,17 +313,18 @@ function storePendingUpload(upload) {
|
|
|
326
313
|
id,
|
|
327
314
|
createdAt: Date.now()
|
|
328
315
|
};
|
|
329
|
-
pendingUploads.set(id, entry);
|
|
330
316
|
const timer = setTimeout(() => {
|
|
331
317
|
pendingUploads.delete(id);
|
|
332
|
-
pendingUploadTimers.delete(id);
|
|
333
318
|
}, PENDING_UPLOAD_TTL_MS);
|
|
334
|
-
|
|
319
|
+
pendingUploads.set(id, {
|
|
320
|
+
upload: entry,
|
|
321
|
+
timer
|
|
322
|
+
});
|
|
335
323
|
return id;
|
|
336
324
|
}
|
|
337
325
|
function getPendingUpload(id) {
|
|
338
326
|
if (!id) return;
|
|
339
|
-
const entry = pendingUploads.get(id);
|
|
327
|
+
const entry = pendingUploads.get(id)?.upload;
|
|
340
328
|
if (!entry) return;
|
|
341
329
|
if (Date.now() - entry.createdAt > PENDING_UPLOAD_TTL_MS) {
|
|
342
330
|
removePendingUpload(id);
|
|
@@ -350,16 +338,12 @@ function getPendingUpload(id) {
|
|
|
350
338
|
*/
|
|
351
339
|
function removePendingUpload(id) {
|
|
352
340
|
if (id) {
|
|
341
|
+
clearTimeout(pendingUploads.get(id)?.timer);
|
|
353
342
|
pendingUploads.delete(id);
|
|
354
|
-
const timer = pendingUploadTimers.get(id);
|
|
355
|
-
if (timer !== void 0) {
|
|
356
|
-
clearTimeout(timer);
|
|
357
|
-
pendingUploadTimers.delete(id);
|
|
358
|
-
}
|
|
359
343
|
}
|
|
360
344
|
}
|
|
361
345
|
function setPendingUploadActivityId(uploadId, activityId) {
|
|
362
|
-
const entry = pendingUploads.get(uploadId);
|
|
346
|
+
const entry = pendingUploads.get(uploadId)?.upload;
|
|
363
347
|
if (entry) entry.consentCardActivityId = activityId;
|
|
364
348
|
}
|
|
365
349
|
//#endregion
|
|
@@ -470,33 +454,6 @@ function rewriteMarkdownIR(ir, edits) {
|
|
|
470
454
|
})) } : {}
|
|
471
455
|
};
|
|
472
456
|
}
|
|
473
|
-
function prefixMSTeamsBlockquotes(ir) {
|
|
474
|
-
const rewritten = rewriteMarkdownIR(ir, ir.styles.filter((span) => span.style === "blockquote").flatMap((span) => {
|
|
475
|
-
const positions = [span.start];
|
|
476
|
-
for (let index = span.start; index < span.end; index += 1) if (ir.text[index] === "\n" && index + 1 < span.end) positions.push(index + 1);
|
|
477
|
-
return positions.map((position) => ({
|
|
478
|
-
start: position,
|
|
479
|
-
end: position,
|
|
480
|
-
text: "> "
|
|
481
|
-
}));
|
|
482
|
-
}));
|
|
483
|
-
return {
|
|
484
|
-
...rewritten,
|
|
485
|
-
styles: rewritten.styles.filter((span) => span.style !== "blockquote")
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
function longestBacktickRun(text) {
|
|
489
|
-
return Math.max(0, ...text.match(/`+/gu)?.map((run) => run.length) ?? []);
|
|
490
|
-
}
|
|
491
|
-
function renderMSTeamsCode(style, text) {
|
|
492
|
-
const marker = "`".repeat(Math.max(style === "code_block" ? 3 : 1, longestBacktickRun(text) + 1));
|
|
493
|
-
if (style === "code_block") return `${marker}\n${text}${marker}`;
|
|
494
|
-
const needsPadding = text.startsWith("`") || text.endsWith("`") || text.startsWith(" ") && text.endsWith(" ") && text.trim().length > 0;
|
|
495
|
-
return `${marker}${needsPadding ? " " : ""}${text}${needsPadding ? " " : ""}${marker}`;
|
|
496
|
-
}
|
|
497
|
-
function serializeMarkdownDestination(href) {
|
|
498
|
-
return `<${href.replace(/([\\<>])/gu, "\\$1")}>`;
|
|
499
|
-
}
|
|
500
457
|
function blankBlockEnd(text, index) {
|
|
501
458
|
if (text[index] !== "\n" && text[index] !== "\r") return;
|
|
502
459
|
const match = /^(?:\r?\n)[ \t]*(?:\r?\n)/u.exec(text.slice(index));
|
|
@@ -556,74 +513,6 @@ function protectDelimitedMarkdown(text, opener, tokenPrefix, values) {
|
|
|
556
513
|
}
|
|
557
514
|
return protectedText + text.slice(cursor);
|
|
558
515
|
}
|
|
559
|
-
function protectRawTables(text, tokenPrefix, rawTables) {
|
|
560
|
-
if (!text.includes("|")) return text;
|
|
561
|
-
const { tables } = (0, openclaw_plugin_sdk_text_chunking.markdownToIRWithMeta)(text, {
|
|
562
|
-
autolink: false,
|
|
563
|
-
linkify: false,
|
|
564
|
-
tableMode: "block"
|
|
565
|
-
});
|
|
566
|
-
let result = "";
|
|
567
|
-
let cursor = 0;
|
|
568
|
-
for (const table of tables) {
|
|
569
|
-
const source = (0, openclaw_plugin_sdk_expect_runtime.expectDefined)((0, openclaw_plugin_sdk_markdown_table_runtime.getMarkdownTableSource)(table), "Markdown table source");
|
|
570
|
-
const lineStart = Math.max(text.lastIndexOf("\n", source.start - 1), text.lastIndexOf("\r", source.start - 1)) + 1;
|
|
571
|
-
const start = lineStart + (/^(?: {0,3}>[ \t]?)*/u.exec(text.slice(lineStart, source.start))?.[0] ?? "").length;
|
|
572
|
-
const end = source.end + (text.slice(source.end, source.end + 2) === "\r\n" ? 1 : 0);
|
|
573
|
-
const index = rawTables.push(text.slice(start, end)) - 1;
|
|
574
|
-
result += text.slice(cursor, start) + `${tokenPrefix}t${index}${TOKEN_END}`;
|
|
575
|
-
cursor = end;
|
|
576
|
-
}
|
|
577
|
-
return result + text.slice(cursor);
|
|
578
|
-
}
|
|
579
|
-
function protectMSTeamsCode(ir, tokenPrefix, code, protectedValues) {
|
|
580
|
-
const codeSpans = ir.styles.filter((span) => span.style === "code" || span.style === "code_block");
|
|
581
|
-
const codeBlocks = codeSpans.filter((span) => span.style === "code_block");
|
|
582
|
-
const adjustedStyles = ir.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 rewritten = rewriteMarkdownIR({
|
|
598
|
-
...ir,
|
|
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), ir.text.slice(span.start, span.end));
|
|
603
|
-
let quoteDepth = 0;
|
|
604
|
-
let hasTrailingQuotedText = false;
|
|
605
|
-
if (codeStyle === "code_block") {
|
|
606
|
-
for (const candidate of ir.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 rendered = renderMSTeamsCode(codeStyle, source);
|
|
612
|
-
let quoted = quoteDepth > 0 ? `${"> ".repeat(quoteDepth)}${rendered.replaceAll("\n", `\n${"> ".repeat(quoteDepth)}`)}` : rendered;
|
|
613
|
-
const followedByText = codeStyle === "code_block" && span.end < ir.text.length && ir.text[span.end] !== "\n";
|
|
614
|
-
if ((hasTrailingQuotedText || followedByText) && !quoted.endsWith("\n")) quoted += "\n";
|
|
615
|
-
const index = code.push(quoted) - 1;
|
|
616
|
-
return {
|
|
617
|
-
start: span.start,
|
|
618
|
-
end: span.end,
|
|
619
|
-
text: `${tokenPrefix}c${index}${TOKEN_END}`
|
|
620
|
-
};
|
|
621
|
-
}));
|
|
622
|
-
return {
|
|
623
|
-
...rewritten,
|
|
624
|
-
styles: rewritten.styles.filter((span) => span.style !== "code" && span.style !== "code_block")
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
516
|
function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
628
517
|
if (markdown === "") return markdown;
|
|
629
518
|
const rawTables = [];
|
|
@@ -638,7 +527,27 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
638
527
|
return `${tokenPrefix}h${index}${TOKEN_END}`;
|
|
639
528
|
}), "![", `${tokenPrefix}i`, images), "@[", `${tokenPrefix}m`, mentions);
|
|
640
529
|
const tableInput = (0, openclaw_plugin_sdk_text_chunking.convertMarkdownTables)(mentionsProtected, tableMode);
|
|
641
|
-
|
|
530
|
+
let converted = tableInput;
|
|
531
|
+
if (tableMode === "off" && tableInput.includes("|")) {
|
|
532
|
+
const { tables } = (0, openclaw_plugin_sdk_text_chunking.markdownToIRWithMeta)(tableInput, {
|
|
533
|
+
autolink: false,
|
|
534
|
+
linkify: false,
|
|
535
|
+
tableMode: "block"
|
|
536
|
+
});
|
|
537
|
+
let result = "";
|
|
538
|
+
let cursor = 0;
|
|
539
|
+
for (const table of tables) {
|
|
540
|
+
const source = (0, openclaw_plugin_sdk_expect_runtime.expectDefined)((0, openclaw_plugin_sdk_markdown_table_runtime.getMarkdownTableSource)(table), "Markdown table source");
|
|
541
|
+
const lineStart = Math.max(tableInput.lastIndexOf("\n", source.start - 1), tableInput.lastIndexOf("\r", source.start - 1)) + 1;
|
|
542
|
+
const start = lineStart + (/^(?: {0,3}>[ \t]?)*/u.exec(tableInput.slice(lineStart, source.start))?.[0] ?? "").length;
|
|
543
|
+
const end = source.end + (tableInput.slice(source.end, source.end + 2) === "\r\n" ? 1 : 0);
|
|
544
|
+
const index = rawTables.push(tableInput.slice(start, end)) - 1;
|
|
545
|
+
result += tableInput.slice(cursor, start) + `${tokenPrefix}t${index}${TOKEN_END}`;
|
|
546
|
+
cursor = end;
|
|
547
|
+
}
|
|
548
|
+
converted = result + tableInput.slice(cursor);
|
|
549
|
+
}
|
|
550
|
+
const protectedMarkdown = converted.replace(ESCAPED_MARKDOWN_RE, (escaped) => {
|
|
642
551
|
const index = escapedMarkdown.push(escaped) - 1;
|
|
643
552
|
return `${tokenPrefix}e${index}${TOKEN_END}`;
|
|
644
553
|
});
|
|
@@ -672,7 +581,71 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
672
581
|
values: entities
|
|
673
582
|
}
|
|
674
583
|
];
|
|
675
|
-
const
|
|
584
|
+
const codeSpans = parsed.styles.filter((span) => span.style === "code" || span.style === "code_block");
|
|
585
|
+
const codeBlocks = codeSpans.filter((span) => span.style === "code_block");
|
|
586
|
+
const adjustedStyles = parsed.styles.flatMap((span) => {
|
|
587
|
+
if (span.style !== "blockquote") return [span];
|
|
588
|
+
let segments = [span];
|
|
589
|
+
for (const codeBlock of codeBlocks) segments = segments.flatMap((segment) => {
|
|
590
|
+
if (codeBlock.end <= segment.start || codeBlock.start >= segment.end) return [segment];
|
|
591
|
+
return [...segment.start < codeBlock.start ? [{
|
|
592
|
+
...segment,
|
|
593
|
+
end: codeBlock.start
|
|
594
|
+
}] : [], ...codeBlock.end < segment.end ? [{
|
|
595
|
+
...segment,
|
|
596
|
+
start: codeBlock.end
|
|
597
|
+
}] : []];
|
|
598
|
+
});
|
|
599
|
+
return segments;
|
|
600
|
+
});
|
|
601
|
+
const codeRewritten = rewriteMarkdownIR({
|
|
602
|
+
...parsed,
|
|
603
|
+
styles: adjustedStyles
|
|
604
|
+
}, codeSpans.map((span) => {
|
|
605
|
+
const codeStyle = span.style === "code_block" ? "code_block" : "code";
|
|
606
|
+
const source = protectedValues.reduce((text, protectedValue) => restoreTokens(text, protectedValue.prefix, protectedValue.values), parsed.text.slice(span.start, span.end));
|
|
607
|
+
let quoteDepth = 0;
|
|
608
|
+
let hasTrailingQuotedText = false;
|
|
609
|
+
if (codeStyle === "code_block") {
|
|
610
|
+
for (const candidate of parsed.styles) if (candidate.style === "blockquote" && span.start >= candidate.start) {
|
|
611
|
+
if (span.start < candidate.end) quoteDepth += 1;
|
|
612
|
+
hasTrailingQuotedText ||= candidate.end > span.end;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
const marker = "`".repeat(Math.max(codeStyle === "code_block" ? 3 : 1, Math.max(0, ...source.match(/`+/gu)?.map((run) => run.length) ?? []) + 1));
|
|
616
|
+
let rendered;
|
|
617
|
+
if (codeStyle === "code_block") rendered = `${marker}\n${source}${marker}`;
|
|
618
|
+
else {
|
|
619
|
+
const needsPadding = source.startsWith("`") || source.endsWith("`") || source.startsWith(" ") && source.endsWith(" ") && source.trim().length > 0;
|
|
620
|
+
rendered = `${marker}${needsPadding ? " " : ""}${source}${needsPadding ? " " : ""}${marker}`;
|
|
621
|
+
}
|
|
622
|
+
let quoted = quoteDepth > 0 ? `${"> ".repeat(quoteDepth)}${rendered.replaceAll("\n", `\n${"> ".repeat(quoteDepth)}`)}` : rendered;
|
|
623
|
+
const followedByText = codeStyle === "code_block" && span.end < parsed.text.length && parsed.text[span.end] !== "\n";
|
|
624
|
+
if ((hasTrailingQuotedText || followedByText) && !quoted.endsWith("\n")) quoted += "\n";
|
|
625
|
+
const index = codeRegions.push(quoted) - 1;
|
|
626
|
+
return {
|
|
627
|
+
start: span.start,
|
|
628
|
+
end: span.end,
|
|
629
|
+
text: `${tokenPrefix}c${index}${TOKEN_END}`
|
|
630
|
+
};
|
|
631
|
+
}));
|
|
632
|
+
const codeProtected = {
|
|
633
|
+
...codeRewritten,
|
|
634
|
+
styles: codeRewritten.styles.filter((span) => span.style !== "code" && span.style !== "code_block")
|
|
635
|
+
};
|
|
636
|
+
const rewritten = rewriteMarkdownIR(codeProtected, codeProtected.styles.filter((span) => span.style === "blockquote").flatMap((span) => {
|
|
637
|
+
const positions = [span.start];
|
|
638
|
+
for (let index = span.start; index < span.end; index += 1) if (codeProtected.text[index] === "\n" && index + 1 < span.end) positions.push(index + 1);
|
|
639
|
+
return positions.map((position) => ({
|
|
640
|
+
start: position,
|
|
641
|
+
end: position,
|
|
642
|
+
text: "> "
|
|
643
|
+
}));
|
|
644
|
+
}));
|
|
645
|
+
const ir = {
|
|
646
|
+
...rewritten,
|
|
647
|
+
styles: rewritten.styles.filter((span) => span.style !== "blockquote")
|
|
648
|
+
};
|
|
676
649
|
const rendered = (0, openclaw_plugin_sdk_text_chunking.renderMarkdownWithMarkers)(ir, {
|
|
677
650
|
styleMarkers: MSTEAMS_MARKERS,
|
|
678
651
|
escapeText: (text) => text,
|
|
@@ -680,7 +653,7 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
680
653
|
start: link.start,
|
|
681
654
|
end: link.end,
|
|
682
655
|
open: "[",
|
|
683
|
-
close: `](
|
|
656
|
+
close: `](<${link.href.replace(/([\\<>])/gu, "\\$1")}>)`
|
|
684
657
|
})
|
|
685
658
|
}, MSTEAMS_FORMAT_CAPABILITIES);
|
|
686
659
|
return protectedValues.reduce((text, { prefix, values }) => restoreTokens(text, prefix, values), restoreTokens(rendered, `${tokenPrefix}c`, codeRegions));
|
|
@@ -747,26 +720,6 @@ async function requestSharePointJson(params, request) {
|
|
|
747
720
|
}
|
|
748
721
|
});
|
|
749
722
|
}
|
|
750
|
-
async function uploadToSharePoint(params) {
|
|
751
|
-
const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
|
|
752
|
-
const data = await requestSharePointJson(params, {
|
|
753
|
-
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`,
|
|
754
|
-
timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
|
|
755
|
-
init: () => ({
|
|
756
|
-
method: "PUT",
|
|
757
|
-
headers: { "Content-Type": params.contentType ?? "application/octet-stream" },
|
|
758
|
-
body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)])
|
|
759
|
-
}),
|
|
760
|
-
error: "SharePoint upload failed",
|
|
761
|
-
label: "msteams.graph-upload.uploadSharePointFile"
|
|
762
|
-
});
|
|
763
|
-
if (!data.id || !data.webUrl || !data.name) throw new Error("SharePoint upload response missing required fields");
|
|
764
|
-
return {
|
|
765
|
-
id: data.id,
|
|
766
|
-
webUrl: data.webUrl,
|
|
767
|
-
name: data.name
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
723
|
async function getDriveItemProperties(params) {
|
|
771
724
|
const data = await requestSharePointJson(params, {
|
|
772
725
|
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`,
|
|
@@ -780,27 +733,44 @@ async function getDriveItemProperties(params) {
|
|
|
780
733
|
name: data.name
|
|
781
734
|
};
|
|
782
735
|
}
|
|
783
|
-
async function getChatMemberIds(params) {
|
|
784
|
-
return ((await requestSharePointJson(params, {
|
|
785
|
-
url: `${GRAPH_ROOT}/chats/${params.chatId}/members`,
|
|
786
|
-
error: (res) => res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed",
|
|
787
|
-
label: "msteams.graph-upload.getChatMembers"
|
|
788
|
-
})).value ?? []).flatMap((member) => member.userId ? [member.userId] : []);
|
|
789
|
-
}
|
|
790
736
|
/**
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
* For per-user
|
|
737
|
+
* Upload a file to SharePoint and create a sharing link.
|
|
738
|
+
*
|
|
739
|
+
* For group chats, this creates a per-user sharing link scoped to chat members.
|
|
740
|
+
* For channels, this creates an organization-wide sharing link.
|
|
794
741
|
*/
|
|
795
|
-
async function
|
|
796
|
-
const
|
|
742
|
+
async function uploadAndShareSharePoint(params) {
|
|
743
|
+
const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
|
|
744
|
+
const data = await requestSharePointJson(params, {
|
|
745
|
+
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`,
|
|
746
|
+
timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
|
|
747
|
+
init: () => ({
|
|
748
|
+
method: "PUT",
|
|
749
|
+
headers: { "Content-Type": params.contentType ?? "application/octet-stream" },
|
|
750
|
+
body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)])
|
|
751
|
+
}),
|
|
752
|
+
error: "SharePoint upload failed",
|
|
753
|
+
label: "msteams.graph-upload.uploadSharePointFile"
|
|
754
|
+
});
|
|
755
|
+
if (!data.id) throw new Error("SharePoint upload response missing required fields");
|
|
756
|
+
const itemId = data.id;
|
|
757
|
+
let recipientObjectIds;
|
|
758
|
+
if (params.usePerUserSharing && params.chatId) {
|
|
759
|
+
recipientObjectIds = ((await requestSharePointJson(params, {
|
|
760
|
+
url: `${GRAPH_ROOT}/chats/${params.chatId}/members`,
|
|
761
|
+
error: (res) => res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed",
|
|
762
|
+
label: "msteams.graph-upload.getChatMembers"
|
|
763
|
+
})).value ?? []).flatMap((member) => member.userId ? [member.userId] : []);
|
|
764
|
+
if (recipientObjectIds.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
|
|
765
|
+
}
|
|
766
|
+
const apiRoot = recipientObjectIds ? GRAPH_BETA : GRAPH_ROOT;
|
|
797
767
|
const body = {
|
|
798
768
|
type: "view",
|
|
799
|
-
scope:
|
|
769
|
+
scope: recipientObjectIds ? "users" : "organization"
|
|
800
770
|
};
|
|
801
|
-
if (
|
|
802
|
-
|
|
803
|
-
url: `${apiRoot}/sites/${params.siteId}/drive/items/${
|
|
771
|
+
if (recipientObjectIds) body.recipients = recipientObjectIds.map((id) => ({ objectId: id }));
|
|
772
|
+
await requestSharePointJson(params, {
|
|
773
|
+
url: `${apiRoot}/sites/${params.siteId}/drive/items/${itemId}/createLink`,
|
|
804
774
|
init: () => ({
|
|
805
775
|
method: "POST",
|
|
806
776
|
headers: { "Content-Type": "application/json" },
|
|
@@ -809,39 +779,7 @@ async function createSharePointSharingLink(params) {
|
|
|
809
779
|
error: "Create SharePoint sharing link failed",
|
|
810
780
|
label: "msteams.graph-upload.createSharePointSharingLink"
|
|
811
781
|
});
|
|
812
|
-
|
|
813
|
-
return data.link.webUrl;
|
|
814
|
-
}
|
|
815
|
-
/**
|
|
816
|
-
* Upload a file to SharePoint and create a sharing link.
|
|
817
|
-
*
|
|
818
|
-
* For group chats, this creates a per-user sharing link scoped to chat members.
|
|
819
|
-
* For channels, this creates an organization-wide sharing link.
|
|
820
|
-
*/
|
|
821
|
-
async function uploadAndShareSharePoint(params) {
|
|
822
|
-
const uploaded = await uploadToSharePoint(params);
|
|
823
|
-
let recipientObjectIds;
|
|
824
|
-
if (params.usePerUserSharing && params.chatId) {
|
|
825
|
-
recipientObjectIds = await getChatMemberIds({
|
|
826
|
-
chatId: params.chatId,
|
|
827
|
-
tokenProvider: params.tokenProvider,
|
|
828
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
829
|
-
});
|
|
830
|
-
if (recipientObjectIds.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
|
|
831
|
-
}
|
|
832
|
-
const shareUrl = await createSharePointSharingLink({
|
|
833
|
-
siteId: params.siteId,
|
|
834
|
-
itemId: uploaded.id,
|
|
835
|
-
tokenProvider: params.tokenProvider,
|
|
836
|
-
recipientObjectIds,
|
|
837
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
838
|
-
});
|
|
839
|
-
return {
|
|
840
|
-
itemId: uploaded.id,
|
|
841
|
-
webUrl: uploaded.webUrl,
|
|
842
|
-
shareUrl,
|
|
843
|
-
name: uploaded.name
|
|
844
|
-
};
|
|
782
|
+
return { itemId };
|
|
845
783
|
}
|
|
846
784
|
//#endregion
|
|
847
785
|
//#region extensions/msteams/src/media-helpers.ts
|
|
@@ -890,7 +828,7 @@ function extractMessageId(response) {
|
|
|
890
828
|
return typeof id === "string" && id ? id : null;
|
|
891
829
|
}
|
|
892
830
|
//#endregion
|
|
893
|
-
//#region extensions/msteams/src/
|
|
831
|
+
//#region extensions/msteams/src/message-activity.ts
|
|
894
832
|
/**
|
|
895
833
|
* Check whether an ID looks like a valid Teams user/bot identifier.
|
|
896
834
|
* Accepts:
|
|
@@ -902,39 +840,6 @@ function extractMessageId(response) {
|
|
|
902
840
|
*/
|
|
903
841
|
const TEAMS_BOT_ID_PATTERN = /^\d+:[a-z0-9._=-]+(?::[a-z0-9._=-]+)*$/i;
|
|
904
842
|
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;
|
|
905
|
-
function isValidTeamsId(id) {
|
|
906
|
-
return TEAMS_BOT_ID_PATTERN.test(id) || AAD_OBJECT_ID_PATTERN.test(id);
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* Convert @[Name](id) into matching <at> text and mention entities.
|
|
910
|
-
* Only matches where the id looks like a real Teams user/bot ID are treated
|
|
911
|
-
* as mentions. This avoids false positives from documentation or code samples
|
|
912
|
-
* embedded in the message (e.g. `@[表示名](ユーザーID)` in backticks).
|
|
913
|
-
*/
|
|
914
|
-
function parseMentions(text) {
|
|
915
|
-
const mentionPattern = /@\[((?:\\[\s\S]|[^\]\\])+)\]\(([^)]+)\)/g;
|
|
916
|
-
const entities = [];
|
|
917
|
-
return {
|
|
918
|
-
text: text.replace(mentionPattern, (match, name, id) => {
|
|
919
|
-
const trimmedId = id.trim();
|
|
920
|
-
if (!isValidTeamsId(trimmedId)) return match;
|
|
921
|
-
const trimmedName = name.replace(/\\([\\[\]])/g, "$1").trim();
|
|
922
|
-
const mentionTag = `<at>${trimmedName}</at>`;
|
|
923
|
-
entities.push({
|
|
924
|
-
type: "mention",
|
|
925
|
-
text: mentionTag,
|
|
926
|
-
mentioned: {
|
|
927
|
-
id: trimmedId,
|
|
928
|
-
name: trimmedName
|
|
929
|
-
}
|
|
930
|
-
});
|
|
931
|
-
return mentionTag;
|
|
932
|
-
}),
|
|
933
|
-
entities
|
|
934
|
-
};
|
|
935
|
-
}
|
|
936
|
-
//#endregion
|
|
937
|
-
//#region extensions/msteams/src/message-activity.ts
|
|
938
843
|
const AI_GENERATED_ENTITY = {
|
|
939
844
|
type: "https://schema.org/Message",
|
|
940
845
|
"@type": "Message",
|
|
@@ -942,13 +847,36 @@ const AI_GENERATED_ENTITY = {
|
|
|
942
847
|
"@id": "",
|
|
943
848
|
additionalType: ["AIGeneratedContent"]
|
|
944
849
|
};
|
|
850
|
+
/**
|
|
851
|
+
* Convert @[Name](id) into matching <at> text and mention entities.
|
|
852
|
+
* Only matches where the id looks like a real Teams user/bot ID are treated
|
|
853
|
+
* as mentions. This avoids false positives from documentation or code samples
|
|
854
|
+
* embedded in the message (e.g. `@[表示名](ユーザーID)` in backticks).
|
|
855
|
+
*/
|
|
945
856
|
/** Build final transport text and its matching entities after Markdown rendering. */
|
|
946
857
|
function buildMSTeamsMessageActivity(text) {
|
|
947
|
-
const
|
|
858
|
+
const sourceText = text ?? "";
|
|
859
|
+
const mentionPattern = /@\[((?:\\[\s\S]|[^\]\\])+)\]\(([^)]+)\)/g;
|
|
860
|
+
const entities = [];
|
|
861
|
+
const formattedText = sourceText.replace(mentionPattern, (match, name, id) => {
|
|
862
|
+
const trimmedId = id.trim();
|
|
863
|
+
if (!(TEAMS_BOT_ID_PATTERN.test(trimmedId) || AAD_OBJECT_ID_PATTERN.test(trimmedId))) return match;
|
|
864
|
+
const trimmedName = name.replace(/\\([\\[\]])/g, "$1").trim();
|
|
865
|
+
const mentionTag = `<at>${trimmedName}</at>`;
|
|
866
|
+
entities.push({
|
|
867
|
+
type: "mention",
|
|
868
|
+
text: mentionTag,
|
|
869
|
+
mentioned: {
|
|
870
|
+
id: trimmedId,
|
|
871
|
+
name: trimmedName
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
return mentionTag;
|
|
875
|
+
});
|
|
948
876
|
return {
|
|
949
877
|
type: "message",
|
|
950
|
-
...text === void 0 ? {} : { text:
|
|
951
|
-
entities: [...
|
|
878
|
+
...text === void 0 ? {} : { text: formattedText },
|
|
879
|
+
entities: [...entities, AI_GENERATED_ENTITY]
|
|
952
880
|
};
|
|
953
881
|
}
|
|
954
882
|
function buildMSTeamsAdaptiveCardActivity(card) {
|
|
@@ -961,17 +889,6 @@ function buildMSTeamsAdaptiveCardActivity(card) {
|
|
|
961
889
|
};
|
|
962
890
|
}
|
|
963
891
|
//#endregion
|
|
964
|
-
//#region extensions/msteams/src/revoked-context.ts
|
|
965
|
-
async function withRevokedProxyFallback(params) {
|
|
966
|
-
try {
|
|
967
|
-
return await params.run();
|
|
968
|
-
} catch (err) {
|
|
969
|
-
if (!require_channel_setup.isRevokedProxyError(err)) throw err;
|
|
970
|
-
params.onRevokedLog?.();
|
|
971
|
-
return await params.onRevoked();
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
//#endregion
|
|
975
892
|
//#region extensions/msteams/src/sent-message-cache.ts
|
|
976
893
|
const TTL_MS = 864e5;
|
|
977
894
|
const MAX_ENTRIES = 2e4;
|
|
@@ -981,7 +898,7 @@ const MSTEAMS_SENT_MESSAGES_KEY = Symbol.for("openclaw.msteamsSentMessages");
|
|
|
981
898
|
const namedAccountCaches = /* @__PURE__ */ new Map();
|
|
982
899
|
function createSentMessageCache(accountId) {
|
|
983
900
|
const isDefault = accountId === "default";
|
|
984
|
-
const accountDigest = isDefault ? void 0 : (0,
|
|
901
|
+
const accountDigest = isDefault ? void 0 : (0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(accountId);
|
|
985
902
|
return (0, openclaw_plugin_sdk_dedupe_runtime.createPersistentDedupeCache)({
|
|
986
903
|
globalKey: isDefault ? MSTEAMS_SENT_MESSAGES_KEY : Symbol.for(`openclaw.msteamsSentMessages.account.v1.${accountDigest}`),
|
|
987
904
|
ttlMs: TTL_MS,
|
|
@@ -1030,20 +947,15 @@ async function quoteMSTeamsActivity(activity, messageId) {
|
|
|
1030
947
|
if (activity.type !== "message") return activity;
|
|
1031
948
|
return MessageActivityInput.from(activity).prependQuote(messageId);
|
|
1032
949
|
}
|
|
1033
|
-
function resolveThreadedConversationId(conversationId, threadActivityId) {
|
|
1034
|
-
const baseId = conversationId.split(";")[0] ?? conversationId;
|
|
1035
|
-
return threadActivityId ? `${baseId};messageid=${threadActivityId}` : baseId;
|
|
1036
|
-
}
|
|
1037
|
-
function normalizeRequiredServiceUrl(ref) {
|
|
1038
|
-
if (!ref.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
|
|
1039
|
-
return require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(ref.serviceUrl);
|
|
1040
|
-
}
|
|
1041
950
|
function buildSdkConversationReference(source, options) {
|
|
1042
|
-
const bot = source.agent ?? source.bot
|
|
951
|
+
const bot = source.agent ?? source.bot;
|
|
1043
952
|
if (!bot?.id) throw new Error("Invalid stored reference: missing agent.id");
|
|
1044
|
-
const
|
|
953
|
+
const baseId = source.conversation.id.split(";")[0] ?? source.conversation.id;
|
|
954
|
+
const threadActivityId = options?.threadActivityId;
|
|
955
|
+
const conversationId = threadActivityId ? `${baseId};messageid=${threadActivityId}` : baseId;
|
|
1045
956
|
const tenantId = source.tenantId ?? source.conversation.tenantId;
|
|
1046
|
-
|
|
957
|
+
if (!source.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
|
|
958
|
+
const serviceUrl = require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(source.serviceUrl);
|
|
1047
959
|
if (options?.serviceUrlBoundary) require_resolve_allowlist.validateMSTeamsProactiveServiceUrlBoundary({
|
|
1048
960
|
cloud: options.serviceUrlBoundary.cloud,
|
|
1049
961
|
conversationId,
|
|
@@ -1071,74 +983,52 @@ function buildSdkConversationReference(source, options) {
|
|
|
1071
983
|
...source.aadObjectId ? { aadObjectId: source.aadObjectId } : {}
|
|
1072
984
|
};
|
|
1073
985
|
}
|
|
1074
|
-
function
|
|
1075
|
-
|
|
1076
|
-
try {
|
|
1077
|
-
return require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(left) === right;
|
|
1078
|
-
} catch {
|
|
1079
|
-
return false;
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
function stringifyReferenceFallbackActivity(activity) {
|
|
1083
|
-
if (typeof activity === "string") return activity;
|
|
1084
|
-
if (activity == null) return "";
|
|
1085
|
-
if (typeof activity === "number" || typeof activity === "boolean" || typeof activity === "bigint") return String(activity);
|
|
1086
|
-
return "";
|
|
1087
|
-
}
|
|
1088
|
-
async function getApiClientForReference(app, ref) {
|
|
1089
|
-
const api = app.api;
|
|
1090
|
-
if (sameServiceUrl(api.serviceUrl, ref.serviceUrl)) return api;
|
|
1091
|
-
const appInternals = app;
|
|
1092
|
-
const httpClient = appInternals.api?.http ?? appInternals.client;
|
|
1093
|
-
if (!httpClient) return api;
|
|
1094
|
-
const { Client } = await loadMSTeamsApiModule();
|
|
1095
|
-
return new Client(ref.serviceUrl, httpClient);
|
|
1096
|
-
}
|
|
1097
|
-
function mergeReferenceIntoActivity(activity, ref) {
|
|
1098
|
-
const source = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(activity) ?? {
|
|
1099
|
-
type: "message",
|
|
1100
|
-
text: stringifyReferenceFallbackActivity(activity)
|
|
1101
|
-
};
|
|
1102
|
-
const existingChannelData = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(source.channelData);
|
|
1103
|
-
const existingTenant = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(existingChannelData?.tenant);
|
|
1104
|
-
let channelData = existingChannelData ? { ...existingChannelData } : void 0;
|
|
1105
|
-
if (ref.tenantId) {
|
|
1106
|
-
channelData ??= {};
|
|
1107
|
-
channelData.tenant = existingTenant ? {
|
|
1108
|
-
...existingTenant,
|
|
1109
|
-
id: ref.tenantId
|
|
1110
|
-
} : { id: ref.tenantId };
|
|
1111
|
-
}
|
|
1112
|
-
return {
|
|
1113
|
-
...source,
|
|
1114
|
-
channelId: ref.channelId,
|
|
1115
|
-
from: ref.bot,
|
|
1116
|
-
recipient: ref.user,
|
|
1117
|
-
conversation: ref.conversation,
|
|
1118
|
-
...channelData ? { channelData } : {},
|
|
1119
|
-
locale: ref.locale,
|
|
1120
|
-
...ref.tenantId ? { tenantId: ref.tenantId } : {},
|
|
1121
|
-
...ref.aadObjectId ? { aadObjectId: ref.aadObjectId } : {}
|
|
1122
|
-
};
|
|
986
|
+
function getApiClientForReference(app, ref) {
|
|
987
|
+
return app.api.serviceUrl === ref.serviceUrl ? app.api : app.api.fromServiceUrl({ serviceUrl: ref.serviceUrl });
|
|
1123
988
|
}
|
|
1124
989
|
async function sendMSTeamsActivityWithReference(app, source, activity, options) {
|
|
1125
990
|
return require_resolve_allowlist.withMSTeamsConnectorHandoff(options ?? {}, async (handoff) => {
|
|
1126
991
|
require_resolve_allowlist.assertMSTeamsSendHandoff(handoff);
|
|
1127
992
|
const ref = buildSdkConversationReference(source, options);
|
|
1128
|
-
const activities =
|
|
1129
|
-
const
|
|
993
|
+
const activities = getApiClientForReference(app, ref).conversations.activities(ref.conversation.id);
|
|
994
|
+
const quotedActivity = options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity;
|
|
995
|
+
const activitySource = typeof quotedActivity === "string" ? {
|
|
996
|
+
type: "message",
|
|
997
|
+
text: quotedActivity
|
|
998
|
+
} : quotedActivity;
|
|
999
|
+
const existingChannelData = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(activitySource.channelData);
|
|
1000
|
+
const existingTenant = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(existingChannelData?.tenant);
|
|
1001
|
+
let channelData = existingChannelData ? { ...existingChannelData } : void 0;
|
|
1002
|
+
if (ref.tenantId) {
|
|
1003
|
+
channelData ??= {};
|
|
1004
|
+
channelData.tenant = existingTenant ? {
|
|
1005
|
+
...existingTenant,
|
|
1006
|
+
id: ref.tenantId
|
|
1007
|
+
} : { id: ref.tenantId };
|
|
1008
|
+
}
|
|
1009
|
+
const activityWithRef = {
|
|
1010
|
+
...activitySource,
|
|
1011
|
+
channelId: ref.channelId,
|
|
1012
|
+
from: ref.bot,
|
|
1013
|
+
recipient: ref.user,
|
|
1014
|
+
conversation: ref.conversation,
|
|
1015
|
+
...channelData ? { channelData } : {},
|
|
1016
|
+
locale: ref.locale,
|
|
1017
|
+
...ref.tenantId ? { tenantId: ref.tenantId } : {},
|
|
1018
|
+
...ref.aadObjectId ? { aadObjectId: ref.aadObjectId } : {}
|
|
1019
|
+
};
|
|
1130
1020
|
const isTargeted = activityWithRef.recipient?.isTargeted === true;
|
|
1131
1021
|
if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
|
|
1132
1022
|
const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
|
|
1133
1023
|
require_resolve_allowlist.assertMSTeamsSendHandoff(handoff);
|
|
1134
1024
|
if (activityId) {
|
|
1135
|
-
const res = isTargeted
|
|
1025
|
+
const res = isTargeted ? await activities.updateTargeted(activityId, activityWithRef) : await activities.update(activityId, activityWithRef);
|
|
1136
1026
|
return {
|
|
1137
1027
|
...activityWithRef,
|
|
1138
1028
|
...res && typeof res === "object" ? res : {}
|
|
1139
1029
|
};
|
|
1140
1030
|
}
|
|
1141
|
-
const res = isTargeted
|
|
1031
|
+
const res = isTargeted ? await activities.createTargeted(activityWithRef) : await activities.create(activityWithRef);
|
|
1142
1032
|
const conversationId = ref.conversation.id.split(";")[0] ?? ref.conversation.id;
|
|
1143
1033
|
if (res.id && activityWithRef.type === "message" && ref.conversation.conversationType === "channel" && ref.conversation.id === conversationId) recordMSTeamsSentMessage(conversationId, res.id, {
|
|
1144
1034
|
accountId: options?.accountId,
|
|
@@ -1152,11 +1042,11 @@ async function sendMSTeamsActivityWithReference(app, source, activity, options)
|
|
|
1152
1042
|
}
|
|
1153
1043
|
async function updateMSTeamsActivityWithReference(app, source, activityId, activity, options) {
|
|
1154
1044
|
const ref = buildSdkConversationReference(source, options);
|
|
1155
|
-
return
|
|
1045
|
+
return getApiClientForReference(app, ref).conversations.activities(ref.conversation.id).update(activityId, activity);
|
|
1156
1046
|
}
|
|
1157
1047
|
async function deleteMSTeamsActivityWithReference(app, source, activityId, options) {
|
|
1158
1048
|
const ref = buildSdkConversationReference(source, options);
|
|
1159
|
-
return
|
|
1049
|
+
return getApiClientForReference(app, ref).conversations.activities(ref.conversation.id).delete(activityId);
|
|
1160
1050
|
}
|
|
1161
1051
|
//#endregion
|
|
1162
1052
|
//#region extensions/msteams/src/messenger.ts
|
|
@@ -1165,7 +1055,7 @@ const MSTEAMS_SEND_RETRY_MAX_DELAY_MS = 1e4;
|
|
|
1165
1055
|
function buildConversationReference(ref) {
|
|
1166
1056
|
const conversationId = ref.conversation?.id?.trim();
|
|
1167
1057
|
if (!conversationId) throw new Error("Invalid stored reference: missing conversation.id");
|
|
1168
|
-
const agent = ref.agent ?? ref.bot
|
|
1058
|
+
const agent = ref.agent ?? ref.bot;
|
|
1169
1059
|
if (agent == null || !agent.id) throw new Error("Invalid stored reference: missing agent.id");
|
|
1170
1060
|
const user = ref.user;
|
|
1171
1061
|
if (!user?.id) throw new Error("Invalid stored reference: missing user.id");
|
|
@@ -1196,105 +1086,109 @@ function renderReplyPayloadsToMessages(replies, options) {
|
|
|
1196
1086
|
const chunkMode = options.chunkMode ?? "length";
|
|
1197
1087
|
for (const payload of replies) {
|
|
1198
1088
|
const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: formatMSTeamsMarkdown(payload.text ?? "", options.tableMode) });
|
|
1199
|
-
if (!reply.hasContent) continue;
|
|
1089
|
+
if (!reply.hasContent && !payload.presentation) continue;
|
|
1200
1090
|
if (reply.text) {
|
|
1201
1091
|
const chunks = require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(reply.text, chunkLimit, chunkMode);
|
|
1202
1092
|
for (const chunk of chunks) {
|
|
1203
1093
|
const text = chunk.trim();
|
|
1204
|
-
if (text
|
|
1094
|
+
if (text) out.push({ text });
|
|
1205
1095
|
}
|
|
1206
1096
|
}
|
|
1097
|
+
if (payload.presentation) out.push({ adaptiveCard: require_presentation.buildMSTeamsPresentationCard({ presentation: payload.presentation }) });
|
|
1207
1098
|
out.push(...reply.mediaUrls.map((mediaUrl) => ({ mediaUrl })));
|
|
1208
1099
|
}
|
|
1209
1100
|
return out;
|
|
1210
1101
|
}
|
|
1211
|
-
async function buildActivity(msg, conversationRef, tokenProvider, sharePointSiteId, mediaMaxBytes, options) {
|
|
1212
|
-
const activity = buildMSTeamsMessageActivity(msg.text);
|
|
1213
|
-
activity.channelData = { feedbackLoopEnabled: options?.feedbackLoopEnabled ?? false };
|
|
1214
|
-
if (msg.mediaUrl) {
|
|
1215
|
-
let contentUrl = msg.mediaUrl;
|
|
1216
|
-
let contentType = await getMimeType(msg.mediaUrl);
|
|
1217
|
-
let fileName = await extractFilename(msg.mediaUrl);
|
|
1218
|
-
if (isLocalPath(msg.mediaUrl)) {
|
|
1219
|
-
const maxBytes = mediaMaxBytes ?? 104857600;
|
|
1220
|
-
const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
|
|
1221
|
-
contentType = media.contentType ?? contentType;
|
|
1222
|
-
fileName = media.fileName ?? fileName;
|
|
1223
|
-
const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(conversationRef.conversation?.conversationType);
|
|
1224
|
-
const isPersonal = conversationType === "personal";
|
|
1225
|
-
const isImage = media.kind === "image";
|
|
1226
|
-
if (requiresFileConsent({
|
|
1227
|
-
conversationType,
|
|
1228
|
-
contentType,
|
|
1229
|
-
bufferSize: media.buffer.length
|
|
1230
|
-
})) {
|
|
1231
|
-
const conversationId = conversationRef.conversation?.id ?? "unknown";
|
|
1232
|
-
require_resolve_allowlist.assertMSTeamsSendHandoff(options);
|
|
1233
|
-
const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
|
|
1234
|
-
media: {
|
|
1235
|
-
buffer: media.buffer,
|
|
1236
|
-
filename: fileName,
|
|
1237
|
-
contentType
|
|
1238
|
-
},
|
|
1239
|
-
conversationId,
|
|
1240
|
-
description: msg.text || void 0
|
|
1241
|
-
});
|
|
1242
|
-
consentActivity["_pendingUploadId"] = uploadId;
|
|
1243
|
-
return consentActivity;
|
|
1244
|
-
}
|
|
1245
|
-
if (!isPersonal && !isImage) {
|
|
1246
|
-
const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
|
|
1247
|
-
if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
|
|
1248
|
-
const chatId = conversationRef.conversation?.id;
|
|
1249
|
-
const uploaded = await uploadAndShareSharePoint({
|
|
1250
|
-
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1251
|
-
buffer: media.buffer,
|
|
1252
|
-
filename: fileName,
|
|
1253
|
-
contentType,
|
|
1254
|
-
tokenProvider,
|
|
1255
|
-
siteId,
|
|
1256
|
-
chatId: chatId ?? void 0,
|
|
1257
|
-
usePerUserSharing: conversationType === "groupchat"
|
|
1258
|
-
});
|
|
1259
|
-
activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
|
|
1260
|
-
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1261
|
-
siteId,
|
|
1262
|
-
itemId: uploaded.itemId,
|
|
1263
|
-
tokenProvider
|
|
1264
|
-
}))];
|
|
1265
|
-
return activity;
|
|
1266
|
-
}
|
|
1267
|
-
const base64 = media.buffer.toString("base64");
|
|
1268
|
-
contentUrl = `data:${media.contentType};base64,${base64}`;
|
|
1269
|
-
}
|
|
1270
|
-
activity.attachments = [{
|
|
1271
|
-
name: fileName,
|
|
1272
|
-
contentType,
|
|
1273
|
-
contentUrl
|
|
1274
|
-
}];
|
|
1275
|
-
}
|
|
1276
|
-
return activity;
|
|
1277
|
-
}
|
|
1278
1102
|
async function sendMSTeamsMessages(params) {
|
|
1279
|
-
const messages = params.messages.filter((m) => m.text && m.text.trim().length > 0 || m.mediaUrl);
|
|
1103
|
+
const messages = params.messages.filter((m) => m.text && m.text.trim().length > 0 || m.mediaUrl || m.adaptiveCard);
|
|
1280
1104
|
if (messages.length === 0) return [];
|
|
1281
1105
|
let providerDispatchStarted = false;
|
|
1282
1106
|
const sendMessageInContext = async (sendFn, message, messageIndex) => {
|
|
1283
|
-
|
|
1284
|
-
|
|
1107
|
+
async function buildActivity() {
|
|
1108
|
+
const msg = message;
|
|
1109
|
+
const { conversationRef, tokenProvider, sharePointSiteId, mediaMaxBytes } = params;
|
|
1110
|
+
const options = {
|
|
1111
|
+
feedbackLoopEnabled: params.feedbackLoopEnabled,
|
|
1112
|
+
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1113
|
+
};
|
|
1114
|
+
const activity = buildMSTeamsMessageActivity(msg.text);
|
|
1115
|
+
if (msg.adaptiveCard) Object.assign(activity, buildMSTeamsAdaptiveCardActivity(msg.adaptiveCard));
|
|
1116
|
+
activity.channelData = { feedbackLoopEnabled: options?.feedbackLoopEnabled ?? false };
|
|
1117
|
+
if (msg.mediaUrl) {
|
|
1118
|
+
let contentUrl = msg.mediaUrl;
|
|
1119
|
+
let contentType = await getMimeType(msg.mediaUrl);
|
|
1120
|
+
let fileName = await extractFilename(msg.mediaUrl);
|
|
1121
|
+
if (isLocalPath(msg.mediaUrl)) {
|
|
1122
|
+
const maxBytes = mediaMaxBytes ?? 104857600;
|
|
1123
|
+
const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
|
|
1124
|
+
contentType = media.contentType ?? contentType;
|
|
1125
|
+
fileName = media.fileName ?? fileName;
|
|
1126
|
+
const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(conversationRef.conversation?.conversationType);
|
|
1127
|
+
const isPersonal = conversationType === "personal";
|
|
1128
|
+
const isImage = media.kind === "image";
|
|
1129
|
+
if (requiresFileConsent({
|
|
1130
|
+
conversationType,
|
|
1131
|
+
contentType,
|
|
1132
|
+
bufferSize: media.buffer.length
|
|
1133
|
+
})) {
|
|
1134
|
+
const conversationId = conversationRef.conversation?.id ?? "unknown";
|
|
1135
|
+
require_resolve_allowlist.assertMSTeamsSendHandoff(options);
|
|
1136
|
+
const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
|
|
1137
|
+
media: {
|
|
1138
|
+
buffer: media.buffer,
|
|
1139
|
+
filename: fileName,
|
|
1140
|
+
contentType
|
|
1141
|
+
},
|
|
1142
|
+
conversationId,
|
|
1143
|
+
description: msg.text || void 0
|
|
1144
|
+
});
|
|
1145
|
+
return {
|
|
1146
|
+
activity: consentActivity,
|
|
1147
|
+
pendingUploadId: uploadId
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
if (!isPersonal && !isImage) {
|
|
1151
|
+
const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
|
|
1152
|
+
if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
|
|
1153
|
+
const chatId = conversationRef.conversation?.id;
|
|
1154
|
+
const uploaded = await uploadAndShareSharePoint({
|
|
1155
|
+
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1156
|
+
buffer: media.buffer,
|
|
1157
|
+
filename: fileName,
|
|
1158
|
+
contentType,
|
|
1159
|
+
tokenProvider,
|
|
1160
|
+
siteId,
|
|
1161
|
+
chatId,
|
|
1162
|
+
usePerUserSharing: conversationType === "groupchat"
|
|
1163
|
+
});
|
|
1164
|
+
activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
|
|
1165
|
+
assertDirectAdapterHandoff: options?.assertDirectAdapterHandoff,
|
|
1166
|
+
siteId,
|
|
1167
|
+
itemId: uploaded.itemId,
|
|
1168
|
+
tokenProvider
|
|
1169
|
+
}))];
|
|
1170
|
+
return { activity };
|
|
1171
|
+
}
|
|
1172
|
+
const base64 = media.buffer.toString("base64");
|
|
1173
|
+
contentUrl = `data:${media.contentType};base64,${base64}`;
|
|
1174
|
+
}
|
|
1175
|
+
activity.attachments = [{
|
|
1176
|
+
name: fileName,
|
|
1177
|
+
contentType,
|
|
1178
|
+
contentUrl
|
|
1179
|
+
}];
|
|
1180
|
+
}
|
|
1181
|
+
return { activity };
|
|
1182
|
+
}
|
|
1183
|
+
let prepared;
|
|
1285
1184
|
let response;
|
|
1286
1185
|
try {
|
|
1287
1186
|
response = await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(async () => {
|
|
1288
1187
|
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
1289
|
-
|
|
1290
|
-
feedbackLoopEnabled: params.feedbackLoopEnabled,
|
|
1291
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1292
|
-
});
|
|
1293
|
-
pendingUploadId ??= typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
|
|
1294
|
-
delete activity["_pendingUploadId"];
|
|
1188
|
+
prepared ??= await buildActivity();
|
|
1295
1189
|
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
1296
1190
|
providerDispatchStarted = true;
|
|
1297
|
-
return await sendFn(activity);
|
|
1191
|
+
return await sendFn(prepared.activity);
|
|
1298
1192
|
}, {
|
|
1299
1193
|
attempts: MSTEAMS_SEND_ATTEMPTS,
|
|
1300
1194
|
minDelayMs: 0,
|
|
@@ -1323,54 +1217,33 @@ async function sendMSTeamsMessages(params) {
|
|
|
1323
1217
|
}
|
|
1324
1218
|
const messageId = extractMessageId(response) ?? "unknown";
|
|
1325
1219
|
await params.onMessageSent?.(messageId, messageIndex);
|
|
1220
|
+
const pendingUploadId = prepared?.pendingUploadId;
|
|
1326
1221
|
if (pendingUploadId && messageId !== "unknown") setPendingUploadActivityId(pendingUploadId, messageId);
|
|
1327
1222
|
return messageId;
|
|
1328
1223
|
};
|
|
1329
|
-
|
|
1224
|
+
let sendFn;
|
|
1225
|
+
const ctx = params.replyStyle === "thread" ? params.context : void 0;
|
|
1226
|
+
if (ctx) sendFn = (activity) => require_resolve_allowlist.withMSTeamsConnectorHandoff(params, () => ctx.sendActivity(activity));
|
|
1227
|
+
else {
|
|
1330
1228
|
let baseRef;
|
|
1331
1229
|
try {
|
|
1332
1230
|
baseRef = buildConversationReference(params.conversationRef);
|
|
1333
1231
|
} catch (error) {
|
|
1334
|
-
if (providerDispatchStarted) throw error;
|
|
1335
1232
|
throw new openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError(error instanceof Error ? error.message : "Teams conversation preparation failed", { cause: error });
|
|
1336
1233
|
}
|
|
1337
1234
|
const isChannel = params.conversationRef.conversation?.conversationType === "channel";
|
|
1338
|
-
const
|
|
1235
|
+
const threadActivityId = params.replyStyle === "thread" && isChannel ? params.conversationRef.threadId ?? params.conversationRef.activityId : void 0;
|
|
1236
|
+
sendFn = (activity) => sendMSTeamsActivityWithReference(params.app, baseRef, activity, {
|
|
1339
1237
|
accountId: params.accountId,
|
|
1340
1238
|
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
|
|
1341
1239
|
onPlatformSendDispatch: params.onPlatformSendDispatch,
|
|
1342
|
-
threadActivityId
|
|
1240
|
+
threadActivityId,
|
|
1343
1241
|
serviceUrlBoundary: params.serviceUrlBoundary
|
|
1344
1242
|
});
|
|
1345
|
-
const messageIds = [];
|
|
1346
|
-
for (const [idx, message] of batch.entries()) messageIds.push(await sendMessageInContext(sendFn, message, startIndex + idx));
|
|
1347
|
-
return messageIds;
|
|
1348
|
-
};
|
|
1349
|
-
const resolvedThreadId = params.conversationRef.threadId ?? params.conversationRef.activityId;
|
|
1350
|
-
if (params.replyStyle === "thread") {
|
|
1351
|
-
const ctx = params.context;
|
|
1352
|
-
if (!ctx) return await sendProactively(messages, 0, resolvedThreadId);
|
|
1353
|
-
const sendFn = (activity) => require_resolve_allowlist.withMSTeamsConnectorHandoff(params, () => ctx.sendActivity(activity));
|
|
1354
|
-
const messageIds = [];
|
|
1355
|
-
for (const [idx, message] of messages.entries()) {
|
|
1356
|
-
const result = await withRevokedProxyFallback({
|
|
1357
|
-
run: async () => ({
|
|
1358
|
-
ids: [await sendMessageInContext(sendFn, message, idx)],
|
|
1359
|
-
fellBack: false
|
|
1360
|
-
}),
|
|
1361
|
-
onRevoked: async () => {
|
|
1362
|
-
return {
|
|
1363
|
-
ids: await sendProactively(messages.slice(idx), idx, resolvedThreadId),
|
|
1364
|
-
fellBack: true
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
});
|
|
1368
|
-
messageIds.push(...result.ids);
|
|
1369
|
-
if (result.fellBack) return messageIds;
|
|
1370
|
-
}
|
|
1371
|
-
return messageIds;
|
|
1372
1243
|
}
|
|
1373
|
-
|
|
1244
|
+
const messageIds = [];
|
|
1245
|
+
for (const [idx, message] of messages.entries()) messageIds.push(await sendMessageInContext(sendFn, message, idx));
|
|
1246
|
+
return messageIds;
|
|
1374
1247
|
}
|
|
1375
1248
|
//#endregion
|
|
1376
1249
|
//#region extensions/msteams/src/polls.ts
|
|
@@ -1445,57 +1318,51 @@ function extractMSTeamsPollVote(activity) {
|
|
|
1445
1318
|
}
|
|
1446
1319
|
function buildMSTeamsPollCard(params) {
|
|
1447
1320
|
const pollId = node_crypto.default.randomUUID();
|
|
1448
|
-
const maxSelections =
|
|
1321
|
+
const maxSelections = params.maxSelections !== void 0 && params.maxSelections > 1 ? Math.floor(params.maxSelections) : 1;
|
|
1449
1322
|
const cappedMaxSelections = Math.min(Math.max(1, maxSelections), params.options.length);
|
|
1450
1323
|
const choices = params.options.map((option, index) => ({
|
|
1451
1324
|
title: option,
|
|
1452
1325
|
value: String(index)
|
|
1453
1326
|
}));
|
|
1454
1327
|
const hint = cappedMaxSelections > 1 ? `Select up to ${cappedMaxSelections} options.` : "Select one option.";
|
|
1455
|
-
const card = {
|
|
1456
|
-
type: "AdaptiveCard",
|
|
1457
|
-
version: "1.5",
|
|
1458
|
-
body: [
|
|
1459
|
-
{
|
|
1460
|
-
type: "TextBlock",
|
|
1461
|
-
text: params.question,
|
|
1462
|
-
wrap: true,
|
|
1463
|
-
weight: "Bolder",
|
|
1464
|
-
size: "Medium"
|
|
1465
|
-
},
|
|
1466
|
-
{
|
|
1467
|
-
type: "Input.ChoiceSet",
|
|
1468
|
-
id: "choices",
|
|
1469
|
-
isMultiSelect: cappedMaxSelections > 1,
|
|
1470
|
-
style: "expanded",
|
|
1471
|
-
choices
|
|
1472
|
-
},
|
|
1473
|
-
{
|
|
1474
|
-
type: "TextBlock",
|
|
1475
|
-
text: hint,
|
|
1476
|
-
wrap: true,
|
|
1477
|
-
isSubtle: true,
|
|
1478
|
-
spacing: "Small"
|
|
1479
|
-
}
|
|
1480
|
-
],
|
|
1481
|
-
actions: [{
|
|
1482
|
-
type: "Action.Execute",
|
|
1483
|
-
title: "Vote",
|
|
1484
|
-
verb: "openclaw.poll.vote",
|
|
1485
|
-
data: {
|
|
1486
|
-
openclawPollId: pollId,
|
|
1487
|
-
pollId
|
|
1488
|
-
}
|
|
1489
|
-
}]
|
|
1490
|
-
};
|
|
1491
|
-
const fallbackLines = [`Poll: ${params.question}`, ...params.options.map((option, index) => `${index + 1}. ${option}`)];
|
|
1492
1328
|
return {
|
|
1493
1329
|
pollId,
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1330
|
+
card: {
|
|
1331
|
+
type: "AdaptiveCard",
|
|
1332
|
+
version: "1.5",
|
|
1333
|
+
body: [
|
|
1334
|
+
{
|
|
1335
|
+
type: "TextBlock",
|
|
1336
|
+
text: params.question,
|
|
1337
|
+
wrap: true,
|
|
1338
|
+
weight: "Bolder",
|
|
1339
|
+
size: "Medium"
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
type: "Input.ChoiceSet",
|
|
1343
|
+
id: "choices",
|
|
1344
|
+
isMultiSelect: cappedMaxSelections > 1,
|
|
1345
|
+
style: "expanded",
|
|
1346
|
+
choices
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
type: "TextBlock",
|
|
1350
|
+
text: hint,
|
|
1351
|
+
wrap: true,
|
|
1352
|
+
isSubtle: true,
|
|
1353
|
+
spacing: "Small"
|
|
1354
|
+
}
|
|
1355
|
+
],
|
|
1356
|
+
actions: [{
|
|
1357
|
+
type: "Action.Execute",
|
|
1358
|
+
title: "Vote",
|
|
1359
|
+
verb: "openclaw.poll.vote",
|
|
1360
|
+
data: {
|
|
1361
|
+
openclawPollId: pollId,
|
|
1362
|
+
pollId
|
|
1363
|
+
}
|
|
1364
|
+
}]
|
|
1365
|
+
}
|
|
1499
1366
|
};
|
|
1500
1367
|
}
|
|
1501
1368
|
function isPollExpired(poll) {
|
|
@@ -1530,59 +1397,12 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1530
1397
|
namespace: require_delegated_state.resolveMSTeamsAccountStateNamespace(MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE, params?.accountId),
|
|
1531
1398
|
maxEntries: MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS
|
|
1532
1399
|
});
|
|
1533
|
-
const readPollVotes = async (pollId) => {
|
|
1534
|
-
const votes = {};
|
|
1535
|
-
for (const row of await voteBucketStore.entries()) if (row.value.pollId === pollId) Object.assign(votes, row.value.votes);
|
|
1536
|
-
return votes;
|
|
1537
|
-
};
|
|
1538
1400
|
const deletePollVotes = async (pollId, cachedRows) => {
|
|
1539
1401
|
for (const row of cachedRows?.values() ?? await voteBucketStore.entries()) if (row.value.pollId === pollId) {
|
|
1540
1402
|
await voteBucketStore.delete(row.key);
|
|
1541
1403
|
cachedRows?.delete(row.key);
|
|
1542
1404
|
}
|
|
1543
1405
|
};
|
|
1544
|
-
const registerPollVotes = async (pollId, votes, updatedAt) => {
|
|
1545
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
1546
|
-
for (const [voterId, selections] of Object.entries(votes)) {
|
|
1547
|
-
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1548
|
-
const bucketVotes = buckets.get(bucket) ?? {};
|
|
1549
|
-
bucketVotes[voterId] = selections;
|
|
1550
|
-
buckets.set(bucket, bucketVotes);
|
|
1551
|
-
}
|
|
1552
|
-
for (const [bucket, bucketVotes] of buckets) {
|
|
1553
|
-
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1554
|
-
const existing = await voteBucketStore.lookup(key);
|
|
1555
|
-
await voteBucketStore.register(key, require_delegated_state.toPluginJsonValue({
|
|
1556
|
-
pollId,
|
|
1557
|
-
bucket,
|
|
1558
|
-
votes: {
|
|
1559
|
-
...bucketVotes,
|
|
1560
|
-
...existing?.votes
|
|
1561
|
-
},
|
|
1562
|
-
updatedAt
|
|
1563
|
-
}));
|
|
1564
|
-
}
|
|
1565
|
-
};
|
|
1566
|
-
const registerPollVote = async (pollId, voterId, selections, updatedAt) => {
|
|
1567
|
-
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1568
|
-
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1569
|
-
const existing = await voteBucketStore.lookup(key);
|
|
1570
|
-
await voteBucketStore.register(key, require_delegated_state.toPluginJsonValue({
|
|
1571
|
-
pollId,
|
|
1572
|
-
bucket,
|
|
1573
|
-
votes: {
|
|
1574
|
-
...existing?.votes,
|
|
1575
|
-
[voterId]: selections
|
|
1576
|
-
},
|
|
1577
|
-
updatedAt
|
|
1578
|
-
}));
|
|
1579
|
-
};
|
|
1580
|
-
const reconstructPoll = async (metadata) => {
|
|
1581
|
-
return {
|
|
1582
|
-
...metadata,
|
|
1583
|
-
votes: await readPollVotes(metadata.id)
|
|
1584
|
-
};
|
|
1585
|
-
};
|
|
1586
1406
|
const prunePollStoreToLimit = async () => {
|
|
1587
1407
|
let voteRows;
|
|
1588
1408
|
const deletePrunedPollVotes = async (pollId) => {
|
|
@@ -1609,10 +1429,8 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1609
1429
|
};
|
|
1610
1430
|
const createPoll = async (poll) => {
|
|
1611
1431
|
await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
1612
|
-
|
|
1613
|
-
await pollStore.register(buildMSTeamsPollStateKey(poll.id), require_delegated_state.toPluginJsonValue(metadata));
|
|
1432
|
+
await pollStore.register(buildMSTeamsPollStateKey(poll.id), require_delegated_state.toPluginJsonValue(poll));
|
|
1614
1433
|
await deletePollVotes(poll.id);
|
|
1615
|
-
await registerPollVotes(poll.id, votes, poll.updatedAt ?? poll.createdAt);
|
|
1616
1434
|
await prunePollStoreToLimit();
|
|
1617
1435
|
});
|
|
1618
1436
|
};
|
|
@@ -1620,7 +1438,7 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1620
1438
|
const poll = await pollStore.lookup(buildMSTeamsPollStateKey(pollId));
|
|
1621
1439
|
if (!poll) return null;
|
|
1622
1440
|
if (isPollExpired(poll)) return null;
|
|
1623
|
-
return
|
|
1441
|
+
return poll;
|
|
1624
1442
|
};
|
|
1625
1443
|
const recordVote = async (vote) => {
|
|
1626
1444
|
return await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
@@ -1632,13 +1450,26 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1632
1450
|
await deletePollVotes(vote.pollId);
|
|
1633
1451
|
return null;
|
|
1634
1452
|
}
|
|
1635
|
-
const normalized = normalizeMSTeamsPollSelections(
|
|
1453
|
+
const normalized = normalizeMSTeamsPollSelections(poll, vote.selections);
|
|
1636
1454
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1637
1455
|
poll.updatedAt = updatedAt;
|
|
1638
|
-
await pollStore.register(pollKey,
|
|
1639
|
-
|
|
1456
|
+
await pollStore.register(pollKey, poll);
|
|
1457
|
+
const pollId = vote.pollId;
|
|
1458
|
+
const voterId = vote.voterId;
|
|
1459
|
+
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1460
|
+
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1461
|
+
const existing = await voteBucketStore.lookup(key);
|
|
1462
|
+
await voteBucketStore.register(key, {
|
|
1463
|
+
pollId,
|
|
1464
|
+
bucket,
|
|
1465
|
+
votes: {
|
|
1466
|
+
...existing?.votes,
|
|
1467
|
+
[voterId]: normalized
|
|
1468
|
+
},
|
|
1469
|
+
updatedAt
|
|
1470
|
+
});
|
|
1640
1471
|
await prunePollStoreToLimit();
|
|
1641
|
-
return
|
|
1472
|
+
return true;
|
|
1642
1473
|
});
|
|
1643
1474
|
};
|
|
1644
1475
|
return {
|
|
@@ -1648,45 +1479,11 @@ function createMSTeamsPollStoreState(params) {
|
|
|
1648
1479
|
};
|
|
1649
1480
|
}
|
|
1650
1481
|
//#endregion
|
|
1651
|
-
//#region extensions/msteams/src/conversation-store-helpers.ts
|
|
1652
|
-
function mergeStoredConversationReference(existing, incoming, nowIso) {
|
|
1653
|
-
return {
|
|
1654
|
-
...existing?.timezone && !incoming.timezone ? { timezone: existing.timezone } : {},
|
|
1655
|
-
...existing?.tenantId && !incoming.tenantId ? { tenantId: existing.tenantId } : {},
|
|
1656
|
-
...existing?.aadObjectId && !incoming.aadObjectId ? { aadObjectId: existing.aadObjectId } : {},
|
|
1657
|
-
...incoming,
|
|
1658
|
-
lastSeenAt: nowIso
|
|
1659
|
-
};
|
|
1660
|
-
}
|
|
1661
|
-
function findPreferredDmConversationByUserId(entries, id) {
|
|
1662
|
-
const target = id.trim();
|
|
1663
|
-
if (!target) return null;
|
|
1664
|
-
let preferred = null;
|
|
1665
|
-
let preferredIsPersonal = false;
|
|
1666
|
-
let preferredTimestamp = 0;
|
|
1667
|
-
for (const entry of entries) {
|
|
1668
|
-
if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
|
|
1669
|
-
const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType);
|
|
1670
|
-
if (convType === "channel" || convType === "groupchat") continue;
|
|
1671
|
-
const isPersonal = convType === "personal";
|
|
1672
|
-
const timestamp = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(entry.reference.lastSeenAt) ?? 0;
|
|
1673
|
-
if (!preferred || isPersonal && !preferredIsPersonal || isPersonal === preferredIsPersonal && timestamp > preferredTimestamp) {
|
|
1674
|
-
preferred = entry;
|
|
1675
|
-
preferredIsPersonal = isPersonal;
|
|
1676
|
-
preferredTimestamp = timestamp;
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
return preferred;
|
|
1680
|
-
}
|
|
1681
|
-
//#endregion
|
|
1682
1482
|
//#region extensions/msteams/src/conversation-store-state.ts
|
|
1683
1483
|
const MSTEAMS_CONVERSATIONS_NAMESPACE = "conversations";
|
|
1684
1484
|
const MSTEAMS_MAX_CONVERSATIONS = 1e3;
|
|
1685
1485
|
const MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS = 2e3;
|
|
1686
1486
|
const MSTEAMS_CONVERSATION_TTL_MS = 31536e6;
|
|
1687
|
-
function buildMSTeamsConversationStateKey(conversationId) {
|
|
1688
|
-
return node_crypto.default.createHash("sha256").update(conversationId).digest("hex");
|
|
1689
|
-
}
|
|
1690
1487
|
function getStoredConversationId(reference) {
|
|
1691
1488
|
const rawId = reference.conversation?.id;
|
|
1692
1489
|
return rawId ? require_resolve_allowlist.normalizeMSTeamsConversationId(rawId) : null;
|
|
@@ -1703,7 +1500,7 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1703
1500
|
};
|
|
1704
1501
|
const lookupStored = async (conversationId) => {
|
|
1705
1502
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1706
|
-
const value = await conversationStore.lookup(
|
|
1503
|
+
const value = await conversationStore.lookup((0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(normalizedId));
|
|
1707
1504
|
return value && !isExpired(value) ? value : null;
|
|
1708
1505
|
};
|
|
1709
1506
|
const list = async () => {
|
|
@@ -1721,7 +1518,7 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1721
1518
|
};
|
|
1722
1519
|
const register = async (conversationId, reference) => {
|
|
1723
1520
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1724
|
-
await conversationStore.register(
|
|
1521
|
+
await conversationStore.register((0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(normalizedId), require_delegated_state.toPluginJsonValue({
|
|
1725
1522
|
...reference,
|
|
1726
1523
|
conversation: {
|
|
1727
1524
|
...reference.conversation,
|
|
@@ -1737,29 +1534,54 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1737
1534
|
rows.push(row);
|
|
1738
1535
|
}
|
|
1739
1536
|
if (rows.length <= MSTEAMS_MAX_CONVERSATIONS) return;
|
|
1740
|
-
|
|
1537
|
+
rows.sort((a, b) => {
|
|
1741
1538
|
const aTs = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(a.value.lastSeenAt) ?? 0;
|
|
1742
1539
|
const bTs = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(b.value.lastSeenAt) ?? 0;
|
|
1743
1540
|
const aId = getStoredConversationId(a.value) ?? a.key;
|
|
1744
1541
|
const bId = getStoredConversationId(b.value) ?? b.key;
|
|
1745
1542
|
return aTs - bTs || aId.localeCompare(bId);
|
|
1746
1543
|
});
|
|
1747
|
-
for (const row of
|
|
1544
|
+
for (const row of rows.slice(0, rows.length - MSTEAMS_MAX_CONVERSATIONS)) await conversationStore.delete(row.key);
|
|
1748
1545
|
};
|
|
1749
1546
|
const findPreferredDmByUserId = async (id) => {
|
|
1750
|
-
|
|
1547
|
+
const entries = await list();
|
|
1548
|
+
const target = id.trim();
|
|
1549
|
+
if (!target) return null;
|
|
1550
|
+
let preferred = null;
|
|
1551
|
+
let preferredIsPersonal = false;
|
|
1552
|
+
let preferredTimestamp = 0;
|
|
1553
|
+
for (const entry of entries) {
|
|
1554
|
+
if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
|
|
1555
|
+
const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType);
|
|
1556
|
+
if (convType === "channel" || convType === "groupchat") continue;
|
|
1557
|
+
const isPersonal = convType === "personal";
|
|
1558
|
+
const timestamp = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(entry.reference.lastSeenAt) ?? 0;
|
|
1559
|
+
if (!preferred || isPersonal && !preferredIsPersonal || isPersonal === preferredIsPersonal && timestamp > preferredTimestamp) {
|
|
1560
|
+
preferred = entry;
|
|
1561
|
+
preferredIsPersonal = isPersonal;
|
|
1562
|
+
preferredTimestamp = timestamp;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return preferred;
|
|
1751
1566
|
};
|
|
1752
1567
|
const upsert = async (conversationId, reference) => {
|
|
1753
1568
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1754
1569
|
await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
1755
|
-
const
|
|
1756
|
-
|
|
1570
|
+
const previous = await lookupStored(normalizedId) ?? void 0;
|
|
1571
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
1572
|
+
await register(normalizedId, {
|
|
1573
|
+
...previous?.timezone && !reference.timezone ? { timezone: previous.timezone } : {},
|
|
1574
|
+
...previous?.tenantId && !reference.tenantId ? { tenantId: previous.tenantId } : {},
|
|
1575
|
+
...previous?.aadObjectId && !reference.aadObjectId ? { aadObjectId: previous.aadObjectId } : {},
|
|
1576
|
+
...reference,
|
|
1577
|
+
lastSeenAt: nowIso
|
|
1578
|
+
});
|
|
1757
1579
|
});
|
|
1758
1580
|
};
|
|
1759
1581
|
const remove = async (conversationId) => {
|
|
1760
1582
|
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1761
1583
|
return await require_delegated_state.withMSTeamsSqliteMutationLock(namespace, async () => {
|
|
1762
|
-
return await conversationStore.delete(
|
|
1584
|
+
return await conversationStore.delete((0, openclaw_plugin_sdk_node_crypto_runtime.sha256Hex)(normalizedId));
|
|
1763
1585
|
});
|
|
1764
1586
|
};
|
|
1765
1587
|
return {
|
|
@@ -1771,12 +1593,6 @@ function createMSTeamsConversationStoreState(params) {
|
|
|
1771
1593
|
};
|
|
1772
1594
|
}
|
|
1773
1595
|
//#endregion
|
|
1774
|
-
Object.defineProperty(exports, "FILE_CONSENT_THRESHOLD_BYTES", {
|
|
1775
|
-
enumerable: true,
|
|
1776
|
-
get: function() {
|
|
1777
|
-
return FILE_CONSENT_THRESHOLD_BYTES;
|
|
1778
|
-
}
|
|
1779
|
-
});
|
|
1780
1596
|
Object.defineProperty(exports, "MSTEAMS_MAX_MEDIA_BYTES", {
|
|
1781
1597
|
enumerable: true,
|
|
1782
1598
|
get: function() {
|
|
@@ -1975,9 +1791,3 @@ Object.defineProperty(exports, "wasMSTeamsMessageSentWithPersistence", {
|
|
|
1975
1791
|
return wasMSTeamsMessageSentWithPersistence;
|
|
1976
1792
|
}
|
|
1977
1793
|
});
|
|
1978
|
-
Object.defineProperty(exports, "withRevokedProxyFallback", {
|
|
1979
|
-
enumerable: true,
|
|
1980
|
-
get: function() {
|
|
1981
|
-
return withRevokedProxyFallback;
|
|
1982
|
-
}
|
|
1983
|
-
});
|