@openclaw/msteams 2026.10.1 → 2026.10.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-D0HYByze.cjs → adapter.runtime-JoPydWqP.cjs} +1 -1
- package/dist/.setup/{approval-handler.runtime-C-RJ3wXc.cjs → approval-handler.runtime-bUN9icMr.cjs} +3 -3
- package/dist/.setup/{bot-framework-service-url-BUhTe8F3.cjs → bot-framework-service-url-CPp4d-Q6.cjs} +1 -5
- package/dist/.setup/{channel-BFhXodl2.cjs → channel-Cifn9fsv.cjs} +230 -430
- package/dist/.setup/{channel.runtime-D9jrw2SN.cjs → channel.runtime-DWRAolil.cjs} +70 -44
- package/dist/.setup/{channel.setup-ss0TO-ap.cjs → channel.setup-BjbHugkL.cjs} +5 -7
- package/dist/.setup/{config-schema-0KoBzb0t.cjs → config-schema-Dk0mRIam.cjs} +1 -1
- package/dist/.setup/{conversation-store-state-f7V8CVNy.cjs → conversation-store-state-DprmOfl7.cjs} +103 -236
- package/dist/.setup/{monitor-DfSPCRkk.cjs → monitor-C9x_CJhY.cjs} +173 -322
- package/dist/.setup/oauth-CWJ85AMw.cjs +55 -0
- package/dist/.setup/{reaction-types-B-GEv57k.cjs → reaction-types-Ig9sQJuR.cjs} +3 -3
- package/dist/.setup/{resolve-allowlist-Ct9yxQUw.cjs → resolve-allowlist-DdDBVCzl.cjs} +77 -174
- package/dist/.setup/{send-7VV1iCai.cjs → send-rJpcVtRp.cjs} +8 -9
- package/dist/.setup/{setup-plugin-api-B0OFG32J.cjs → setup-plugin-api-DfoVOqMJ.cjs} +1 -1
- package/dist/.setup/{thread-session-ClI-lSyG.cjs → thread-session-B74FC1Id.cjs} +1 -1
- package/dist/.setup/{token-config-DOt3XwVa.cjs → token-config-CqIh8z7Q.cjs} +6 -7
- 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 +2 -2
- package/dist/doctor-contract-api.cjs +1 -1
- package/dist/qa-runner-api.cjs +9 -10
- package/dist/setup-entry.cjs +1 -1
- package/dist/setup-plugin-api.cjs +1 -1
- package/package.json +4 -4
- package/dist/.setup/oauth-CYxMYIOQ.cjs +0 -102
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-BloeesfJ.cjs");
|
|
2
2
|
const require_runtime = require("./runtime-gZTAuFux.cjs");
|
|
3
3
|
require("../runtime-api.cjs");
|
|
4
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
5
|
-
const require_bot_framework_service_url = require("./bot-framework-service-url-
|
|
6
|
-
const require_token_config = require("./token-config-
|
|
7
|
-
const require_channel = require("./channel-
|
|
8
|
-
const require_thread_session = require("./thread-session-
|
|
9
|
-
const require_channel_setup = require("./channel.setup-
|
|
4
|
+
const require_resolve_allowlist = require("./resolve-allowlist-DdDBVCzl.cjs");
|
|
5
|
+
const require_bot_framework_service_url = require("./bot-framework-service-url-CPp4d-Q6.cjs");
|
|
6
|
+
const require_token_config = require("./token-config-CqIh8z7Q.cjs");
|
|
7
|
+
const require_channel = require("./channel-Cifn9fsv.cjs");
|
|
8
|
+
const require_thread_session = require("./thread-session-B74FC1Id.cjs");
|
|
9
|
+
const require_channel_setup = require("./channel.setup-BjbHugkL.cjs");
|
|
10
10
|
const require_approval_card = require("./approval-card-DWPDItvq.cjs");
|
|
11
|
-
const require_conversation_store_state = require("./conversation-store-state-
|
|
12
|
-
const require_reaction_types = require("./reaction-types-
|
|
11
|
+
const require_conversation_store_state = require("./conversation-store-state-DprmOfl7.cjs");
|
|
12
|
+
const require_reaction_types = require("./reaction-types-Ig9sQJuR.cjs");
|
|
13
13
|
let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
|
|
14
14
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
15
15
|
let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
|
|
@@ -17,6 +17,7 @@ let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-ht
|
|
|
17
17
|
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
18
18
|
let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
|
|
19
19
|
let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
|
|
20
|
+
let node_dns_promises = require("node:dns/promises");
|
|
20
21
|
let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
|
|
21
22
|
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
22
23
|
let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
|
|
@@ -50,13 +51,6 @@ const MAX_LEARNING_ENTRIES = 1e4;
|
|
|
50
51
|
function learningStoreKey(storePath, sessionKey) {
|
|
51
52
|
return node_crypto.default.createHash("sha256").update(`${storePath}\0${sessionKey}`, "utf8").digest("hex");
|
|
52
53
|
}
|
|
53
|
-
function appendFeedbackLearning(current, prepared) {
|
|
54
|
-
return {
|
|
55
|
-
sessionKey: prepared.sessionKey,
|
|
56
|
-
learnings: [...current?.learnings ?? [], prepared.learning].slice(-10),
|
|
57
|
-
updatedAt: prepared.updatedAt
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
54
|
async function storeSessionLearning(params) {
|
|
61
55
|
const store = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
62
56
|
namespace: LEARNINGS_NAMESPACE,
|
|
@@ -74,7 +68,11 @@ async function storeSessionLearning(params) {
|
|
|
74
68
|
const result = await store.compareAndApply(key, observed.comparison, {
|
|
75
69
|
operation: "update",
|
|
76
70
|
action: "set",
|
|
77
|
-
value:
|
|
71
|
+
value: {
|
|
72
|
+
sessionKey: prepared.sessionKey,
|
|
73
|
+
learnings: [...observed.value?.learnings ?? [], prepared.learning].slice(-10),
|
|
74
|
+
updatedAt: prepared.updatedAt
|
|
75
|
+
}
|
|
78
76
|
});
|
|
79
77
|
if (result.status !== "conflict") return;
|
|
80
78
|
observed = result.current;
|
|
@@ -99,7 +97,6 @@ async function runFeedbackReflection(params) {
|
|
|
99
97
|
sessionKey,
|
|
100
98
|
conversationId: params.conversationId,
|
|
101
99
|
conversationKind: params.conversationKind,
|
|
102
|
-
thumbedDownResponse: params.thumbedDownResponse,
|
|
103
100
|
userComment: params.userComment,
|
|
104
101
|
cooldownMs,
|
|
105
102
|
onRecordError: (err) => log.debug?.("reflection session record failed", { error: require_channel_setup.formatUnknownError(err) }),
|
|
@@ -427,6 +424,14 @@ async function admitMSTeamsMessage(params) {
|
|
|
427
424
|
const { dmPolicy, senderId, senderName, pairing, isDirectMessage, hasConflictingConversationScope, channelGate, senderAccess, commandAccess, allowNameMatching, groupPolicy, msteamsCfg } = access;
|
|
428
425
|
const effectiveDmAllowFrom = senderAccess.effectiveAllowFrom;
|
|
429
426
|
const effectiveGroupAllowFrom = senderAccess.effectiveGroupAllowFrom;
|
|
427
|
+
const saveConversationReference = () => params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
|
|
428
|
+
params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
|
|
429
|
+
});
|
|
430
|
+
const dropGroupMessage = (reason, details) => {
|
|
431
|
+
params.log.info(reason, details);
|
|
432
|
+
params.log.debug?.(reason, details);
|
|
433
|
+
return null;
|
|
434
|
+
};
|
|
430
435
|
if (hasConflictingConversationScope) {
|
|
431
436
|
params.log.info("dropping message (conflicting conversation scope)", { conversationId: params.conversationId });
|
|
432
437
|
params.log.debug?.("dropping message (conflicting conversation scope)");
|
|
@@ -448,9 +453,7 @@ async function admitMSTeamsMessage(params) {
|
|
|
448
453
|
allowNameMatching
|
|
449
454
|
});
|
|
450
455
|
if (senderAccess.decision === "pairing") {
|
|
451
|
-
|
|
452
|
-
params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
|
|
453
|
-
});
|
|
456
|
+
saveConversationReference();
|
|
454
457
|
if (await pairing.upsertPairingRequest({
|
|
455
458
|
id: senderId,
|
|
456
459
|
meta: { name: senderName }
|
|
@@ -478,33 +481,15 @@ async function admitMSTeamsMessage(params) {
|
|
|
478
481
|
return null;
|
|
479
482
|
}
|
|
480
483
|
if (!isDirectMessage && msteamsCfg) {
|
|
481
|
-
if (channelGate.allowlistConfigured && !channelGate.allowed) {
|
|
482
|
-
params.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
conversationId: params.conversationId,
|
|
491
|
-
teamKey: channelGate.teamKey ?? "none",
|
|
492
|
-
channelKey: channelGate.channelKey ?? "none",
|
|
493
|
-
channelMatchKey: channelGate.channelMatchKey ?? "none",
|
|
494
|
-
channelMatchSource: channelGate.channelMatchSource ?? "none"
|
|
495
|
-
});
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
if (!senderAccess.allowed && senderAccess.reasonCode === "group_policy_disabled") {
|
|
499
|
-
params.log.info("dropping group message (groupPolicy: disabled)", { conversationId: params.conversationId });
|
|
500
|
-
params.log.debug?.("dropping group message (groupPolicy: disabled)", { conversationId: params.conversationId });
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
if (!senderAccess.allowed && (senderAccess.reasonCode === "group_policy_empty_allowlist" || senderAccess.reasonCode === "route_sender_empty")) {
|
|
504
|
-
params.log.info("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
|
|
505
|
-
params.log.debug?.("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
|
|
506
|
-
return null;
|
|
507
|
-
}
|
|
484
|
+
if (channelGate.allowlistConfigured && !channelGate.allowed) return dropGroupMessage("dropping group message (not in team/channel allowlist)", {
|
|
485
|
+
conversationId: params.conversationId,
|
|
486
|
+
teamKey: channelGate.teamKey ?? "none",
|
|
487
|
+
channelKey: channelGate.channelKey ?? "none",
|
|
488
|
+
channelMatchKey: channelGate.channelMatchKey ?? "none",
|
|
489
|
+
channelMatchSource: channelGate.channelMatchSource ?? "none"
|
|
490
|
+
});
|
|
491
|
+
if (!senderAccess.allowed && senderAccess.reasonCode === "group_policy_disabled") return dropGroupMessage("dropping group message (groupPolicy: disabled)", { conversationId: params.conversationId });
|
|
492
|
+
if (!senderAccess.allowed && (senderAccess.reasonCode === "group_policy_empty_allowlist" || senderAccess.reasonCode === "route_sender_empty")) return dropGroupMessage("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
|
|
508
493
|
if (!senderAccess.allowed) {
|
|
509
494
|
const allowMatch = (0, openclaw_plugin_sdk_allow_from.resolveAllowlistMatchSimple)({
|
|
510
495
|
allowFrom: effectiveGroupAllowFrom,
|
|
@@ -534,9 +519,7 @@ async function admitMSTeamsMessage(params) {
|
|
|
534
519
|
});
|
|
535
520
|
return null;
|
|
536
521
|
}
|
|
537
|
-
|
|
538
|
-
params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
|
|
539
|
-
});
|
|
522
|
+
saveConversationReference();
|
|
540
523
|
return {
|
|
541
524
|
...access,
|
|
542
525
|
allowTextCommands,
|
|
@@ -587,9 +570,7 @@ async function fetchBotFrameworkAttachment(params, kind) {
|
|
|
587
570
|
response = await require_resolve_allowlist.safeFetchWithPolicy({
|
|
588
571
|
url: params.url,
|
|
589
572
|
policy: params.policy,
|
|
590
|
-
|
|
591
|
-
fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
|
|
592
|
-
resolveFn: params.resolveFn,
|
|
573
|
+
resolveFn: node_dns_promises.lookup,
|
|
593
574
|
requestInit: { headers },
|
|
594
575
|
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
595
576
|
});
|
|
@@ -635,8 +616,7 @@ async function saveBotFrameworkAttachmentView(params) {
|
|
|
635
616
|
filePathHint: params.fileNameHint,
|
|
636
617
|
maxBytes: params.maxBytes,
|
|
637
618
|
fallbackContentType: params.contentTypeHint,
|
|
638
|
-
subdir: "inbound"
|
|
639
|
-
originalFilename: params.preserveFilenames ? params.fileNameHint : void 0
|
|
619
|
+
subdir: "inbound"
|
|
640
620
|
});
|
|
641
621
|
} catch (err) {
|
|
642
622
|
params.logger?.warn?.("msteams botFramework attachmentView save failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
@@ -670,9 +650,6 @@ async function downloadMSTeamsBotFrameworkAttachment(params) {
|
|
|
670
650
|
url: baseUrl,
|
|
671
651
|
accessToken,
|
|
672
652
|
policy,
|
|
673
|
-
fetchFn: params.fetchFn,
|
|
674
|
-
fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
|
|
675
|
-
resolveFn: params.resolveFn,
|
|
676
653
|
logger: params.logger,
|
|
677
654
|
deadline: params.deadline
|
|
678
655
|
};
|
|
@@ -683,15 +660,14 @@ async function downloadMSTeamsBotFrameworkAttachment(params) {
|
|
|
683
660
|
const viewId = typeof candidateView?.viewId === "string" && candidateView.viewId ? candidateView.viewId : void 0;
|
|
684
661
|
if (!viewId) return;
|
|
685
662
|
if (typeof candidateView?.size === "number" && candidateView.size > 0 && candidateView.size > params.maxBytes) return;
|
|
686
|
-
const fileNameHint = typeof
|
|
687
|
-
const contentTypeHint = typeof
|
|
663
|
+
const fileNameHint = typeof info.name === "string" && info.name || void 0;
|
|
664
|
+
const contentTypeHint = typeof info.type === "string" && info.type || void 0;
|
|
688
665
|
const saved = await saveBotFrameworkAttachmentView({
|
|
689
666
|
...request,
|
|
690
667
|
url: `${baseUrl}/views/${encodeURIComponent(viewId)}`,
|
|
691
668
|
maxBytes: params.maxBytes,
|
|
692
669
|
fileNameHint,
|
|
693
|
-
contentTypeHint
|
|
694
|
-
preserveFilenames: params.preserveFilenames
|
|
670
|
+
contentTypeHint
|
|
695
671
|
});
|
|
696
672
|
if (!saved) return;
|
|
697
673
|
return {
|
|
@@ -869,12 +845,6 @@ async function downloadAndStoreMSTeamsRemoteMedia(params) {
|
|
|
869
845
|
}
|
|
870
846
|
//#endregion
|
|
871
847
|
//#region extensions/msteams/src/attachments/download.ts
|
|
872
|
-
function withSourceId(media, sourceId) {
|
|
873
|
-
return sourceId ? {
|
|
874
|
-
...media,
|
|
875
|
-
sourceId
|
|
876
|
-
} : media;
|
|
877
|
-
}
|
|
878
848
|
function resolveDownloadCandidate(att) {
|
|
879
849
|
const contentType = require_resolve_allowlist.normalizeContentType(att.contentType);
|
|
880
850
|
const name = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(att.name) ?? "";
|
|
@@ -917,12 +887,8 @@ function resolveDownloadCandidate(att) {
|
|
|
917
887
|
};
|
|
918
888
|
}
|
|
919
889
|
function scopeCandidatesForUrl(url) {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
return host.endsWith("graph.microsoft.com") || host.endsWith("sharepoint.com") || host.endsWith("1drv.ms") || host.includes("sharepoint") ? ["https://graph.microsoft.com", "https://api.botframework.com"] : ["https://api.botframework.com", "https://graph.microsoft.com"];
|
|
923
|
-
} catch {
|
|
924
|
-
return ["https://api.botframework.com", "https://graph.microsoft.com"];
|
|
925
|
-
}
|
|
890
|
+
const host = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(URL.parse(url)?.hostname);
|
|
891
|
+
return host.endsWith("graph.microsoft.com") || host.endsWith("sharepoint.com") || host.endsWith("1drv.ms") || host.includes("sharepoint") ? ["https://graph.microsoft.com", "https://api.botframework.com"] : ["https://api.botframework.com", "https://graph.microsoft.com"];
|
|
926
892
|
}
|
|
927
893
|
function canonicalizeInlineBase64Payload(value) {
|
|
928
894
|
let cleaned = "";
|
|
@@ -957,15 +923,15 @@ async function resolveInlineDataImageMime(inline) {
|
|
|
957
923
|
return mime?.startsWith("image/") ? mime : void 0;
|
|
958
924
|
}
|
|
959
925
|
async function fetchWithAuthFallback(params) {
|
|
960
|
-
const
|
|
926
|
+
const fetchAttempt = (fetchFn, requestInit) => require_resolve_allowlist.safeFetchWithPolicy({
|
|
961
927
|
url: params.url,
|
|
962
928
|
policy: params.policy,
|
|
963
|
-
fetchFn
|
|
964
|
-
|
|
965
|
-
requestInit: params.requestInit,
|
|
929
|
+
fetchFn,
|
|
930
|
+
requestInit,
|
|
966
931
|
resolveFn: params.resolveFn,
|
|
967
932
|
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
968
933
|
});
|
|
934
|
+
const firstAttempt = await fetchAttempt(params.fetchFn, params.requestInit);
|
|
969
935
|
if (firstAttempt.ok) return firstAttempt;
|
|
970
936
|
if (!params.tokenProvider) return firstAttempt;
|
|
971
937
|
const tokenProvider = params.tokenProvider;
|
|
@@ -982,17 +948,9 @@ async function fetchWithAuthFallback(params) {
|
|
|
982
948
|
});
|
|
983
949
|
const authHeaders = new Headers(params.requestInit?.headers);
|
|
984
950
|
authHeaders.set("Authorization", `Bearer ${token}`);
|
|
985
|
-
const authAttempt = await
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
fetchFn,
|
|
989
|
-
fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
|
|
990
|
-
requestInit: {
|
|
991
|
-
...params.requestInit,
|
|
992
|
-
headers: authHeaders
|
|
993
|
-
},
|
|
994
|
-
resolveFn: params.resolveFn,
|
|
995
|
-
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
951
|
+
const authAttempt = await fetchAttempt(fetchFn, {
|
|
952
|
+
...params.requestInit,
|
|
953
|
+
headers: authHeaders
|
|
996
954
|
});
|
|
997
955
|
await fallbackAttempt.body?.cancel().catch(() => void 0);
|
|
998
956
|
if (authAttempt.ok || require_resolve_allowlist.isRedirectStatus(authAttempt.status)) return authAttempt;
|
|
@@ -1020,12 +978,6 @@ async function downloadMSTeamsAttachments(params) {
|
|
|
1020
978
|
});
|
|
1021
979
|
const maxInlineBytes = params.maxBytes;
|
|
1022
980
|
candidates.push(...require_resolve_allowlist.extractInlineImageReferences(list).map((candidate) => {
|
|
1023
|
-
if (candidate.kind === "data") return {
|
|
1024
|
-
kind: "data",
|
|
1025
|
-
mediaKind: "image",
|
|
1026
|
-
src: candidate.src,
|
|
1027
|
-
sourceId: candidate.sourceId
|
|
1028
|
-
};
|
|
1029
981
|
if (candidate.kind === "url") return {
|
|
1030
982
|
kind: "remote",
|
|
1031
983
|
mediaKind: "image",
|
|
@@ -1034,11 +986,7 @@ async function downloadMSTeamsAttachments(params) {
|
|
|
1034
986
|
contentTypeHint: candidate.contentType,
|
|
1035
987
|
sourceId: candidate.sourceId
|
|
1036
988
|
};
|
|
1037
|
-
return {
|
|
1038
|
-
kind: "unavailable",
|
|
1039
|
-
mediaKind: "image",
|
|
1040
|
-
sourceId: candidate.sourceId
|
|
1041
|
-
};
|
|
989
|
+
return Object.assign(candidate, { mediaKind: "image" });
|
|
1042
990
|
}));
|
|
1043
991
|
for (const sourceId of resolveUnrepresentedHtmlAttachmentIds(list)) candidates.push({
|
|
1044
992
|
kind: "unavailable",
|
|
@@ -1046,44 +994,30 @@ async function downloadMSTeamsAttachments(params) {
|
|
|
1046
994
|
sourceId
|
|
1047
995
|
});
|
|
1048
996
|
if (candidates.length === 0) return [];
|
|
1049
|
-
const out = [];
|
|
1050
997
|
let totalInlineBytes = 0;
|
|
1051
|
-
|
|
1052
|
-
if (candidate.kind === "unavailable")
|
|
1053
|
-
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1054
|
-
continue;
|
|
1055
|
-
}
|
|
998
|
+
const downloadCandidate = async (candidate) => {
|
|
999
|
+
if (candidate.kind === "unavailable") return;
|
|
1056
1000
|
if (candidate.kind === "data") {
|
|
1057
1001
|
const decoded = decodeInlineDataImage(candidate.src, maxInlineBytes, totalInlineBytes);
|
|
1058
|
-
if (!decoded)
|
|
1059
|
-
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1060
|
-
continue;
|
|
1061
|
-
}
|
|
1002
|
+
if (!decoded) return;
|
|
1062
1003
|
totalInlineBytes += decoded.estimatedBytes;
|
|
1063
1004
|
try {
|
|
1064
1005
|
const contentType = await resolveInlineDataImageMime(decoded);
|
|
1065
|
-
if (!contentType)
|
|
1066
|
-
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1067
|
-
continue;
|
|
1068
|
-
}
|
|
1006
|
+
if (!contentType) return;
|
|
1069
1007
|
const saved = await require_runtime.getMSTeamsRuntime().channel.media.saveMediaBuffer(decoded.data, contentType, "inbound", params.maxBytes);
|
|
1070
|
-
|
|
1008
|
+
return {
|
|
1071
1009
|
path: saved.path,
|
|
1072
1010
|
contentType: saved.contentType,
|
|
1073
1011
|
kind: "image"
|
|
1074
|
-
}
|
|
1012
|
+
};
|
|
1075
1013
|
} catch (err) {
|
|
1076
|
-
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1077
1014
|
params.logger?.warn?.("msteams inline attachment decode failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1078
1015
|
}
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(candidate.url, allowHosts)) {
|
|
1082
|
-
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1083
|
-
continue;
|
|
1016
|
+
return;
|
|
1084
1017
|
}
|
|
1018
|
+
if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(candidate.url, allowHosts)) return;
|
|
1085
1019
|
try {
|
|
1086
|
-
|
|
1020
|
+
return await downloadAndStoreMSTeamsRemoteMedia({
|
|
1087
1021
|
url: candidate.url,
|
|
1088
1022
|
filePathHint: candidate.fileHint ?? candidate.url,
|
|
1089
1023
|
maxBytes: params.maxBytes,
|
|
@@ -1094,28 +1028,29 @@ async function downloadMSTeamsAttachments(params) {
|
|
|
1094
1028
|
url: (0, openclaw_plugin_sdk_request_url.resolveRequestUrl)(input),
|
|
1095
1029
|
tokenProvider: params.tokenProvider,
|
|
1096
1030
|
fetchFn: params.fetchFn,
|
|
1097
|
-
fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
|
|
1098
1031
|
requestInit: init,
|
|
1099
1032
|
resolveFn: params.resolveFn,
|
|
1100
1033
|
policy,
|
|
1101
1034
|
deadline: params.deadline
|
|
1102
1035
|
})
|
|
1103
1036
|
});
|
|
1104
|
-
out.push(withSourceId(media, candidate.sourceId));
|
|
1105
1037
|
} catch (err) {
|
|
1106
|
-
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1107
1038
|
const msg = (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err);
|
|
1108
1039
|
params.logger?.warn?.(`msteams attachment download failed host=${safeHostForLog(candidate.url)} error=${msg}`);
|
|
1109
1040
|
}
|
|
1041
|
+
};
|
|
1042
|
+
const out = [];
|
|
1043
|
+
for (const candidate of candidates) {
|
|
1044
|
+
const media = await downloadCandidate(candidate) ?? { kind: candidate.mediaKind };
|
|
1045
|
+
out.push(candidate.sourceId ? {
|
|
1046
|
+
...media,
|
|
1047
|
+
sourceId: candidate.sourceId
|
|
1048
|
+
} : media);
|
|
1110
1049
|
}
|
|
1111
1050
|
return out;
|
|
1112
1051
|
}
|
|
1113
1052
|
function safeHostForLog(url) {
|
|
1114
|
-
|
|
1115
|
-
return new URL(url).host;
|
|
1116
|
-
} catch {
|
|
1117
|
-
return "invalid-url";
|
|
1118
|
-
}
|
|
1053
|
+
return URL.parse(url)?.host ?? "invalid-url";
|
|
1119
1054
|
}
|
|
1120
1055
|
//#endregion
|
|
1121
1056
|
//#region extensions/msteams/src/attachments/graph.ts
|
|
@@ -1143,21 +1078,24 @@ function buildMSTeamsGraphMessageUrl(params) {
|
|
|
1143
1078
|
if (!chatId) return;
|
|
1144
1079
|
return `${require_resolve_allowlist.GRAPH_ROOT}/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
|
|
1145
1080
|
}
|
|
1146
|
-
async function
|
|
1147
|
-
if (!response.bodyUsed) response.body?.cancel().catch(() => void 0);
|
|
1148
|
-
await release();
|
|
1149
|
-
}
|
|
1150
|
-
async function fetchGraphCollection(params) {
|
|
1151
|
-
const fetchFn = params.fetchFn ?? fetch;
|
|
1081
|
+
async function withGraphMediaResponse(params, url, kind, read) {
|
|
1152
1082
|
const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
1153
|
-
url
|
|
1154
|
-
fetchImpl: fetchFn,
|
|
1083
|
+
url,
|
|
1084
|
+
fetchImpl: params.fetchFn ?? fetch,
|
|
1155
1085
|
init: { headers: require_resolve_allowlist.ensureUserAgentHeader({ Authorization: `Bearer ${params.accessToken}` }) },
|
|
1156
1086
|
policy: params.ssrfPolicy,
|
|
1157
|
-
auditContext:
|
|
1087
|
+
auditContext: `msteams.graph.${kind}`,
|
|
1158
1088
|
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
1159
1089
|
});
|
|
1160
1090
|
try {
|
|
1091
|
+
return await read(response);
|
|
1092
|
+
} finally {
|
|
1093
|
+
if (!response.bodyUsed) response.body?.cancel().catch(() => void 0);
|
|
1094
|
+
await release();
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
async function fetchGraphCollection(params) {
|
|
1098
|
+
return withGraphMediaResponse(params, params.url, "collection", async (response) => {
|
|
1161
1099
|
const status = response.status;
|
|
1162
1100
|
if (!response.ok) return {
|
|
1163
1101
|
status,
|
|
@@ -1174,9 +1112,7 @@ async function fetchGraphCollection(params) {
|
|
|
1174
1112
|
items: []
|
|
1175
1113
|
};
|
|
1176
1114
|
}
|
|
1177
|
-
}
|
|
1178
|
-
await releaseGraphResponse(response, release);
|
|
1179
|
-
}
|
|
1115
|
+
});
|
|
1180
1116
|
}
|
|
1181
1117
|
function normalizeGraphAttachment(att) {
|
|
1182
1118
|
let content = att.content;
|
|
@@ -1196,11 +1132,8 @@ async function downloadGraphHostedContent(params) {
|
|
|
1196
1132
|
let hosted;
|
|
1197
1133
|
try {
|
|
1198
1134
|
hosted = await fetchGraphCollection({
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
fetchFn: params.fetchFn,
|
|
1202
|
-
ssrfPolicy: params.ssrfPolicy,
|
|
1203
|
-
deadline: params.deadline
|
|
1135
|
+
...params,
|
|
1136
|
+
url: `${params.messageUrl}/hostedContents`
|
|
1204
1137
|
});
|
|
1205
1138
|
} catch (err) {
|
|
1206
1139
|
params.logger?.warn?.("msteams graph hostedContents fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
@@ -1221,19 +1154,12 @@ async function downloadGraphHostedContent(params) {
|
|
|
1221
1154
|
continue;
|
|
1222
1155
|
}
|
|
1223
1156
|
try {
|
|
1224
|
-
const
|
|
1225
|
-
const
|
|
1226
|
-
|
|
1227
|
-
fetchImpl: params.fetchFn ?? fetch,
|
|
1228
|
-
init: { headers: require_resolve_allowlist.ensureUserAgentHeader({ Authorization: `Bearer ${params.accessToken}` }) },
|
|
1229
|
-
policy: params.ssrfPolicy,
|
|
1230
|
-
auditContext: "msteams.graph.hostedContent.value",
|
|
1231
|
-
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
1232
|
-
});
|
|
1233
|
-
try {
|
|
1157
|
+
const sourceId = item.id;
|
|
1158
|
+
const valueUrl = `${params.messageUrl}/hostedContents/${encodeURIComponent(sourceId)}/$value`;
|
|
1159
|
+
await withGraphMediaResponse(params, valueUrl, "hostedContent.value", async (valRes) => {
|
|
1234
1160
|
if (!valRes.ok) {
|
|
1235
1161
|
out.push(createGraphHostedContentFact(item));
|
|
1236
|
-
|
|
1162
|
+
return;
|
|
1237
1163
|
}
|
|
1238
1164
|
const saved = await require_runtime.getMSTeamsRuntime().channel.media.saveResponseMedia(valRes, {
|
|
1239
1165
|
sourceUrl: valueUrl,
|
|
@@ -1245,11 +1171,9 @@ async function downloadGraphHostedContent(params) {
|
|
|
1245
1171
|
path: saved.path,
|
|
1246
1172
|
contentType: saved.contentType,
|
|
1247
1173
|
kind: require_resolve_allowlist.resolveMSTeamsMediaKind({ contentType: saved.contentType }),
|
|
1248
|
-
sourceId
|
|
1174
|
+
sourceId
|
|
1249
1175
|
});
|
|
1250
|
-
}
|
|
1251
|
-
await releaseGraphResponse(valRes, release);
|
|
1252
|
-
}
|
|
1176
|
+
});
|
|
1253
1177
|
} catch (err) {
|
|
1254
1178
|
out.push(createGraphHostedContentFact(item));
|
|
1255
1179
|
params.logger?.warn?.("msteams graph hostedContent value fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
@@ -1271,6 +1195,16 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1271
1195
|
});
|
|
1272
1196
|
const ssrfPolicy = (0, openclaw_plugin_sdk_ssrf_policy.buildHostnameAllowlistPolicyFromSuffixAllowlist)(policy.allowHosts);
|
|
1273
1197
|
const messageUrl = params.messageUrl;
|
|
1198
|
+
const logGraphFailure = (phase, err) => {
|
|
1199
|
+
params.logger?.debug?.(`graph media ${phase} failed`, {
|
|
1200
|
+
messageUrl,
|
|
1201
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1202
|
+
});
|
|
1203
|
+
params.logger?.warn?.(`msteams graph ${phase} failed`, {
|
|
1204
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
|
|
1205
|
+
...phase === "message parse" ? { messageUrl } : {}
|
|
1206
|
+
});
|
|
1207
|
+
};
|
|
1274
1208
|
let accessToken;
|
|
1275
1209
|
try {
|
|
1276
1210
|
accessToken = await require_resolve_allowlist.withMSTeamsRequestDeadline({
|
|
@@ -1279,11 +1213,7 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1279
1213
|
work: () => tokenProvider.getAccessToken("https://graph.microsoft.com")
|
|
1280
1214
|
});
|
|
1281
1215
|
} catch (err) {
|
|
1282
|
-
|
|
1283
|
-
messageUrl,
|
|
1284
|
-
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1285
|
-
});
|
|
1286
|
-
params.logger?.warn?.("msteams graph token acquisition failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1216
|
+
logGraphFailure("token acquisition", err);
|
|
1287
1217
|
return {
|
|
1288
1218
|
media: [],
|
|
1289
1219
|
messageUrl,
|
|
@@ -1297,29 +1227,18 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1297
1227
|
let referenceAttachments = [];
|
|
1298
1228
|
let messageStatus;
|
|
1299
1229
|
try {
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
auditContext: "msteams.graph.message",
|
|
1306
|
-
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
1307
|
-
});
|
|
1308
|
-
try {
|
|
1230
|
+
await withGraphMediaResponse({
|
|
1231
|
+
...params,
|
|
1232
|
+
accessToken,
|
|
1233
|
+
ssrfPolicy
|
|
1234
|
+
}, messageUrl, "message", async (msgRes) => {
|
|
1309
1235
|
messageStatus = msgRes.status;
|
|
1310
1236
|
if (msgRes.ok) {
|
|
1311
1237
|
let msgData;
|
|
1312
1238
|
try {
|
|
1313
1239
|
msgData = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(msgRes, "MS Teams Graph message");
|
|
1314
1240
|
} catch (err) {
|
|
1315
|
-
|
|
1316
|
-
messageUrl,
|
|
1317
|
-
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1318
|
-
});
|
|
1319
|
-
params.logger?.warn?.("msteams graph message parse failed", {
|
|
1320
|
-
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
|
|
1321
|
-
messageUrl
|
|
1322
|
-
});
|
|
1241
|
+
logGraphFailure("message parse", err);
|
|
1323
1242
|
msgData = {};
|
|
1324
1243
|
}
|
|
1325
1244
|
messageAttachments = Array.isArray(msgData.attachments) ? msgData.attachments : [];
|
|
@@ -1328,15 +1247,9 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1328
1247
|
messageUrl,
|
|
1329
1248
|
status: messageStatus
|
|
1330
1249
|
});
|
|
1331
|
-
} finally {
|
|
1332
|
-
await releaseGraphResponse(msgRes, release);
|
|
1333
|
-
}
|
|
1334
|
-
} catch (err) {
|
|
1335
|
-
params.logger?.debug?.("graph media message fetch failed", {
|
|
1336
|
-
messageUrl,
|
|
1337
|
-
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1338
1250
|
});
|
|
1339
|
-
|
|
1251
|
+
} catch (err) {
|
|
1252
|
+
logGraphFailure("message fetch", err);
|
|
1340
1253
|
}
|
|
1341
1254
|
for (const att of referenceAttachments) {
|
|
1342
1255
|
const name = att.name ?? "file";
|
|
@@ -1383,7 +1296,6 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1383
1296
|
url: requestUrl,
|
|
1384
1297
|
policy,
|
|
1385
1298
|
fetchFn,
|
|
1386
|
-
fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
|
|
1387
1299
|
requestInit: {
|
|
1388
1300
|
...init,
|
|
1389
1301
|
headers
|
|
@@ -1415,12 +1327,7 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1415
1327
|
deadline: params.deadline
|
|
1416
1328
|
});
|
|
1417
1329
|
const normalizedAttachments = messageAttachments.map(normalizeGraphAttachment);
|
|
1418
|
-
const filteredAttachments = sharePointMedia.length > 0 ? normalizedAttachments.filter((att) =>
|
|
1419
|
-
if ((0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(att.contentType) !== "reference") return true;
|
|
1420
|
-
const url = typeof att.contentUrl === "string" ? att.contentUrl : "";
|
|
1421
|
-
if (!url) return true;
|
|
1422
|
-
return !downloadedReferenceUrls.has(url);
|
|
1423
|
-
}) : normalizedAttachments;
|
|
1330
|
+
const filteredAttachments = sharePointMedia.length > 0 ? normalizedAttachments.filter((att) => att.contentType !== "reference" || typeof att.contentUrl !== "string" || !att.contentUrl || !downloadedReferenceUrls.has(att.contentUrl)) : normalizedAttachments;
|
|
1424
1331
|
let attachmentMedia = [];
|
|
1425
1332
|
try {
|
|
1426
1333
|
attachmentMedia = await downloadMSTeamsAttachments({
|
|
@@ -1430,7 +1337,6 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1430
1337
|
allowHosts: policy.allowHosts,
|
|
1431
1338
|
authAllowHosts: policy.authAllowHosts,
|
|
1432
1339
|
fetchFn: params.fetchFn,
|
|
1433
|
-
fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
|
|
1434
1340
|
resolveFn: params.resolveFn,
|
|
1435
1341
|
deadline: params.deadline,
|
|
1436
1342
|
preserveFilenames: params.preserveFilenames,
|
|
@@ -1506,14 +1412,13 @@ function hasMaterializedMedia(media) {
|
|
|
1506
1412
|
return media.some((entry) => Boolean(entry.path));
|
|
1507
1413
|
}
|
|
1508
1414
|
async function resolveMSTeamsInboundMedia(params) {
|
|
1509
|
-
const { attachments, htmlSummary, maxBytes, tokenProvider, allowHosts, conversationType, conversationId, conversationMessageId, teamAadGroupId, serviceUrl, activity, log
|
|
1415
|
+
const { attachments, htmlSummary, maxBytes, tokenProvider, allowHosts, conversationType, conversationId, conversationMessageId, teamAadGroupId, serviceUrl, activity, log } = params;
|
|
1510
1416
|
let mediaList = await downloadMSTeamsAttachments({
|
|
1511
1417
|
attachments,
|
|
1512
1418
|
maxBytes,
|
|
1513
1419
|
tokenProvider,
|
|
1514
1420
|
allowHosts,
|
|
1515
1421
|
authAllowHosts: params.authAllowHosts,
|
|
1516
|
-
preserveFilenames,
|
|
1517
1422
|
deadline: params.deadline,
|
|
1518
1423
|
logger: log
|
|
1519
1424
|
});
|
|
@@ -1540,7 +1445,6 @@ async function resolveMSTeamsInboundMedia(params) {
|
|
|
1540
1445
|
maxBytes,
|
|
1541
1446
|
allowHosts,
|
|
1542
1447
|
authAllowHosts: params.authAllowHosts,
|
|
1543
|
-
preserveFilenames,
|
|
1544
1448
|
deadline: params.deadline
|
|
1545
1449
|
});
|
|
1546
1450
|
if (bfMedia.media.length > 0) mediaList = mergeMSTeamsMediaFacts(mediaList, bfMedia.media, { positionallyAligned: false });
|
|
@@ -1573,7 +1477,6 @@ async function resolveMSTeamsInboundMedia(params) {
|
|
|
1573
1477
|
maxBytes,
|
|
1574
1478
|
allowHosts,
|
|
1575
1479
|
authAllowHosts: params.authAllowHosts,
|
|
1576
|
-
preserveFilenames,
|
|
1577
1480
|
deadline: params.deadline,
|
|
1578
1481
|
logger: log
|
|
1579
1482
|
});
|
|
@@ -1638,8 +1541,7 @@ async function prepareMSTeamsInboundContent(params) {
|
|
|
1638
1541
|
channelData: activity.channelData
|
|
1639
1542
|
},
|
|
1640
1543
|
log: params.log,
|
|
1641
|
-
deadline: params.deadline
|
|
1642
|
-
preserveFilenames: false
|
|
1544
|
+
deadline: params.deadline
|
|
1643
1545
|
})
|
|
1644
1546
|
});
|
|
1645
1547
|
} catch (err) {
|
|
@@ -1741,26 +1643,19 @@ function createTeamsReplyStreamController(params) {
|
|
|
1741
1643
|
const deferredReplacementLogicalContent = () => {
|
|
1742
1644
|
return deferredReplacementEntries.map((entry) => entry.payload.text).filter((text) => Boolean(text)).join("\n") || void 0;
|
|
1743
1645
|
};
|
|
1744
|
-
const
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
});
|
|
1755
|
-
deferredReplacementEntries = [];
|
|
1756
|
-
return payloads;
|
|
1757
|
-
};
|
|
1646
|
+
const deferredReplacementPayloads = (replacementFallback) => deferredReplacementEntries.flatMap((entry) => {
|
|
1647
|
+
if (entry.kind === "payload") return [entry.payload];
|
|
1648
|
+
const hasMedia = Boolean(entry.payload.mediaUrl || entry.payload.mediaUrls?.length);
|
|
1649
|
+
const text = replacementFallback?.text;
|
|
1650
|
+
if (!text && !hasMedia) return [];
|
|
1651
|
+
return [{
|
|
1652
|
+
...entry.payload,
|
|
1653
|
+
text: text || void 0
|
|
1654
|
+
}];
|
|
1655
|
+
});
|
|
1758
1656
|
const finalizeWithoutReceipt = (logicalContent, canceled = false) => {
|
|
1759
|
-
const
|
|
1760
|
-
|
|
1761
|
-
const fallback = pending && !canceled ? fallbackPayloadAfterAcknowledgedText(pending) : void 0;
|
|
1762
|
-
const postNativePayloads = replacementSettlementPending && !canceled ? takeDeferredReplacementPayloads(fallback) : [];
|
|
1763
|
-
if (canceled) deferredReplacementEntries = [];
|
|
1657
|
+
const fallback = pendingFinalPayload && !canceled ? fallbackPayloadAfterAcknowledgedText(pendingFinalPayload) : void 0;
|
|
1658
|
+
const postNativePayloads = replacementSettlementPending && !canceled ? deferredReplacementPayloads(fallback) : [];
|
|
1764
1659
|
return {
|
|
1765
1660
|
...acknowledgedNativeDelivery(),
|
|
1766
1661
|
...!canceled && logicalContent ? { logicalContent } : {},
|
|
@@ -1920,13 +1815,7 @@ function createTeamsReplyStreamController(params) {
|
|
|
1920
1815
|
}
|
|
1921
1816
|
let logicalContent;
|
|
1922
1817
|
try {
|
|
1923
|
-
if (wasCanceled())
|
|
1924
|
-
pendingFinalPayload = void 0;
|
|
1925
|
-
deferredReplacementEntries = [];
|
|
1926
|
-
streamFinalizationPending = false;
|
|
1927
|
-
return acknowledgedNativeDelivery();
|
|
1928
|
-
}
|
|
1929
|
-
if (!streamFinalizationPending) return acknowledgedNativeDelivery();
|
|
1818
|
+
if (wasCanceled() || !streamFinalizationPending) return acknowledgedNativeDelivery();
|
|
1930
1819
|
if (replacementSettlementPending && replacementFinalPending && pendingFinalPayload?.text) {
|
|
1931
1820
|
replacementFinalPending = false;
|
|
1932
1821
|
deferredReplacementEntries.push({
|
|
@@ -1962,12 +1851,10 @@ function createTeamsReplyStreamController(params) {
|
|
|
1962
1851
|
});
|
|
1963
1852
|
}
|
|
1964
1853
|
const result = await stream.close();
|
|
1965
|
-
streamFinalizationPending = false;
|
|
1966
1854
|
if (!result) return finalizeWithoutReceipt(logicalContent, wasCanceled());
|
|
1967
1855
|
const replacementFallback = replacementSettlementPending && replacementEmitFailed && pendingFinalPayload ? fallbackPayloadAfterAcknowledgedText(pendingFinalPayload) : void 0;
|
|
1968
|
-
pendingFinalPayload = void 0;
|
|
1969
1856
|
const messageId = require_conversation_store_state.extractMessageId(result) ?? acknowledgedStreamId;
|
|
1970
|
-
const postNativePayloads = replacementSettlementPending ?
|
|
1857
|
+
const postNativePayloads = replacementSettlementPending ? deferredReplacementPayloads(replacementFallback) : [];
|
|
1971
1858
|
const nativeContent = replacementEmitFailed ? acknowledgedText || void 0 : content;
|
|
1972
1859
|
return {
|
|
1973
1860
|
visibleReplySent: replacementEmitFailed ? Boolean(nativeContent) : true,
|
|
@@ -1979,16 +1866,14 @@ function createTeamsReplyStreamController(params) {
|
|
|
1979
1866
|
} catch (err) {
|
|
1980
1867
|
if (isStreamCancelledError(err)) {
|
|
1981
1868
|
canceledLocally = true;
|
|
1982
|
-
pendingFinalPayload = void 0;
|
|
1983
|
-
deferredReplacementEntries = [];
|
|
1984
|
-
streamFinalizationPending = false;
|
|
1985
1869
|
return acknowledgedNativeDelivery();
|
|
1986
1870
|
}
|
|
1987
1871
|
streamFailed = true;
|
|
1988
|
-
streamFinalizationPending = false;
|
|
1989
1872
|
params.log?.warn?.(`msteams stream finalize failed: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
|
|
1990
1873
|
return finalizeWithoutReceipt(logicalContent);
|
|
1991
1874
|
} finally {
|
|
1875
|
+
pendingFinalPayload = void 0;
|
|
1876
|
+
streamFinalizationPending = false;
|
|
1992
1877
|
failedSegmentFallbackPrepared = true;
|
|
1993
1878
|
queuedFinalActivity = void 0;
|
|
1994
1879
|
replacementEmitFailed = false;
|
|
@@ -2077,29 +1962,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2077
1962
|
const typingIndicatorEnabled = typeof msteamsCfg?.typingIndicator === "boolean" ? msteamsCfg.typingIndicator : true;
|
|
2078
1963
|
const pendingDeliveries = [];
|
|
2079
1964
|
let pendingSettlement;
|
|
2080
|
-
const findPendingNativeDelivery = () => pendingDeliveries.find((candidate) =>
|
|
2081
|
-
const joinAcceptedContents = (contents) => contents.filter((content) => Boolean(content)).join("\n");
|
|
2082
|
-
const sendMessages = async (messages) => {
|
|
2083
|
-
return require_conversation_store_state.sendMSTeamsMessages({
|
|
2084
|
-
replyStyle: params.replyStyle,
|
|
2085
|
-
app: params.app,
|
|
2086
|
-
conversationRef: params.conversationRef,
|
|
2087
|
-
context: params.context,
|
|
2088
|
-
messages,
|
|
2089
|
-
retry: {},
|
|
2090
|
-
onRetry: (event) => {
|
|
2091
|
-
params.log.debug?.("retrying send", {
|
|
2092
|
-
replyStyle: params.replyStyle,
|
|
2093
|
-
...event
|
|
2094
|
-
});
|
|
2095
|
-
},
|
|
2096
|
-
tokenProvider: params.tokenProvider,
|
|
2097
|
-
sharePointSiteId: params.sharePointSiteId,
|
|
2098
|
-
mediaMaxBytes,
|
|
2099
|
-
feedbackLoopEnabled,
|
|
2100
|
-
serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(msteamsCfg)
|
|
2101
|
-
});
|
|
2102
|
-
};
|
|
1965
|
+
const findPendingNativeDelivery = () => pendingDeliveries.find((candidate) => !candidate.nativeSettled);
|
|
2103
1966
|
const queueDeliveryFailureSystemEvent = (failure) => {
|
|
2104
1967
|
const classification = require_channel_setup.classifyMSTeamsSendError(failure.error);
|
|
2105
1968
|
const errorText = require_channel_setup.formatUnknownError(failure.error);
|
|
@@ -2120,26 +1983,21 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2120
1983
|
const renderReplyPayload = (payload) => {
|
|
2121
1984
|
return require_conversation_store_state.renderReplyPayloadsToMessages([payload], {
|
|
2122
1985
|
textChunkLimit: params.textLimit,
|
|
2123
|
-
chunkText: true,
|
|
2124
|
-
mediaMode: "split",
|
|
2125
1986
|
tableMode,
|
|
2126
1987
|
chunkMode
|
|
2127
1988
|
});
|
|
2128
1989
|
};
|
|
2129
|
-
const
|
|
1990
|
+
const settlePendingDelivery = (delivery) => {
|
|
1991
|
+
if (delivery.settled || !delivery.blockSettled || !delivery.nativeSettled) return;
|
|
1992
|
+
delivery.settled = true;
|
|
2130
1993
|
const acceptedParts = [...delivery.nativeResult ? [delivery.nativeResult] : [], ...delivery.blockResults];
|
|
2131
1994
|
const messageIds = acceptedParts.flatMap((part) => part.messageIds);
|
|
2132
|
-
const content = delivery.errors.length > 0 ?
|
|
2133
|
-
|
|
1995
|
+
const content = delivery.errors.length > 0 ? acceptedParts.map((part) => part.content).filter(Boolean).join("\n") : delivery.content;
|
|
1996
|
+
const outcome = {
|
|
2134
1997
|
visibleReplySent: acceptedParts.length > 0,
|
|
2135
1998
|
...messageIds.length > 0 ? { messageIds } : {},
|
|
2136
1999
|
...acceptedParts.length > 0 && content !== void 0 ? { content } : {}
|
|
2137
2000
|
};
|
|
2138
|
-
};
|
|
2139
|
-
const settlePendingDelivery = (delivery) => {
|
|
2140
|
-
if (delivery.settled || !delivery.blockSettled || delivery.native && !delivery.nativeSettled) return;
|
|
2141
|
-
delivery.settled = true;
|
|
2142
|
-
const outcome = deliveryOutcome(delivery);
|
|
2143
2001
|
if (delivery.errors.length === 0) {
|
|
2144
2002
|
delivery.finalization.resolve(outcome);
|
|
2145
2003
|
return;
|
|
@@ -2150,21 +2008,6 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2150
2008
|
visibleReplySent: true
|
|
2151
2009
|
}) : error);
|
|
2152
2010
|
};
|
|
2153
|
-
const queueReplyPayload = (payload, messages, native) => {
|
|
2154
|
-
const delivery = {
|
|
2155
|
-
messages,
|
|
2156
|
-
finalization: (0, openclaw_plugin_sdk_extension_shared.createDeferred)(),
|
|
2157
|
-
content: payload.text,
|
|
2158
|
-
blockResults: [],
|
|
2159
|
-
native,
|
|
2160
|
-
nativeSettled: !native,
|
|
2161
|
-
blockSettled: messages.length === 0,
|
|
2162
|
-
settled: false,
|
|
2163
|
-
errors: []
|
|
2164
|
-
};
|
|
2165
|
-
pendingDeliveries.push(delivery);
|
|
2166
|
-
return delivery;
|
|
2167
|
-
};
|
|
2168
2011
|
const flushPendingMessages = async () => {
|
|
2169
2012
|
for (const delivery of pendingDeliveries) {
|
|
2170
2013
|
if (delivery.blockSettled) continue;
|
|
@@ -2174,7 +2017,24 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2174
2017
|
let lastFailedError;
|
|
2175
2018
|
const sentIds = [];
|
|
2176
2019
|
for (const msg of toSend) try {
|
|
2177
|
-
const msgIds = await
|
|
2020
|
+
const msgIds = await require_conversation_store_state.sendMSTeamsMessages({
|
|
2021
|
+
replyStyle: params.replyStyle,
|
|
2022
|
+
app: params.app,
|
|
2023
|
+
conversationRef: params.conversationRef,
|
|
2024
|
+
context: params.context,
|
|
2025
|
+
messages: [msg],
|
|
2026
|
+
onRetry: (event) => {
|
|
2027
|
+
params.log.debug?.("retrying send", {
|
|
2028
|
+
replyStyle: params.replyStyle,
|
|
2029
|
+
...event
|
|
2030
|
+
});
|
|
2031
|
+
},
|
|
2032
|
+
tokenProvider: params.tokenProvider,
|
|
2033
|
+
sharePointSiteId: params.sharePointSiteId,
|
|
2034
|
+
mediaMaxBytes,
|
|
2035
|
+
feedbackLoopEnabled,
|
|
2036
|
+
serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(msteamsCfg)
|
|
2037
|
+
});
|
|
2178
2038
|
const validIds = msgIds.filter((id) => id.trim() && id !== "unknown");
|
|
2179
2039
|
if (msgIds.length > 0) delivery.blockResults.push({
|
|
2180
2040
|
messageIds: validIds,
|
|
@@ -2227,7 +2087,17 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2227
2087
|
visibleReplySent: false,
|
|
2228
2088
|
suppression: { reason: "no_visible_result" }
|
|
2229
2089
|
};
|
|
2230
|
-
const pending =
|
|
2090
|
+
const pending = {
|
|
2091
|
+
messages,
|
|
2092
|
+
finalization: (0, openclaw_plugin_sdk_extension_shared.createDeferred)(),
|
|
2093
|
+
content: payload.text,
|
|
2094
|
+
blockResults: [],
|
|
2095
|
+
nativeSettled: !native,
|
|
2096
|
+
blockSettled: messages.length === 0,
|
|
2097
|
+
settled: false,
|
|
2098
|
+
errors: []
|
|
2099
|
+
};
|
|
2100
|
+
pendingDeliveries.push(pending);
|
|
2231
2101
|
if (blockStreamingEnabled) await flushPendingMessages();
|
|
2232
2102
|
settlePendingDelivery(pending);
|
|
2233
2103
|
return {
|
|
@@ -2290,8 +2160,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2290
2160
|
const shouldSuppressDefaultToolProgressMessages = streamController.hasStream() && teamsStreamMode === "progress";
|
|
2291
2161
|
const progressCallbacks = streamController.hasStream() ? {
|
|
2292
2162
|
onReasoningStream: async (payload) => {
|
|
2293
|
-
|
|
2294
|
-
await streamController.pushReasoningProgress(text, { snapshot: payload?.isReasoningSnapshot === true });
|
|
2163
|
+
await streamController.pushReasoningProgress(payload.text, { snapshot: payload.isReasoningSnapshot === true });
|
|
2295
2164
|
return false;
|
|
2296
2165
|
},
|
|
2297
2166
|
onReasoningEnd: () => {
|
|
@@ -2301,22 +2170,12 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2301
2170
|
onToolStart: streamController.pushToolEvent,
|
|
2302
2171
|
onItemEvent: streamController.pushItemEvent,
|
|
2303
2172
|
onPlanUpdate: async (payload) => {
|
|
2304
|
-
if (payload
|
|
2305
|
-
await streamController.pushPlanProgress(
|
|
2306
|
-
explanation: typeof payload.explanation === "string" ? payload.explanation : void 0,
|
|
2307
|
-
explanationFormat: payload.explanationFormat === "plain" ? "plain" : void 0
|
|
2308
|
-
});
|
|
2173
|
+
if (payload.phase !== "update") return false;
|
|
2174
|
+
await streamController.pushPlanProgress(payload.steps, payload);
|
|
2309
2175
|
return false;
|
|
2310
2176
|
},
|
|
2311
2177
|
onApprovalEvent: async (payload) => {
|
|
2312
|
-
await streamController.pushApprovalEvent(
|
|
2313
|
-
...typeof payload?.phase === "string" ? { phase: payload.phase } : {},
|
|
2314
|
-
...typeof payload?.approvalId === "string" ? { approvalId: payload.approvalId } : {},
|
|
2315
|
-
...typeof payload?.title === "string" ? { title: payload.title } : {},
|
|
2316
|
-
...typeof payload?.command === "string" ? { command: payload.command } : {},
|
|
2317
|
-
...typeof payload?.reason === "string" ? { reason: payload.reason } : {},
|
|
2318
|
-
...typeof payload?.message === "string" ? { message: payload.message } : {}
|
|
2319
|
-
});
|
|
2178
|
+
await streamController.pushApprovalEvent(payload);
|
|
2320
2179
|
return false;
|
|
2321
2180
|
}
|
|
2322
2181
|
} : {};
|
|
@@ -2354,7 +2213,7 @@ async function dispatchMSTeamsInboundTurn(params) {
|
|
|
2354
2213
|
const teamsFrom = isDirectMessage ? `msteams:${senderId}` : isChannel ? `msteams:channel:${conversationId}` : `msteams:group:${conversationId}`;
|
|
2355
2214
|
const teamsTo = isDirectMessage ? `user:${senderId}` : `conversation:${conversationId}`;
|
|
2356
2215
|
const envelopeFrom = isDirectMessage ? senderName : conversationType;
|
|
2357
|
-
const buildEnvelope = (0, openclaw_plugin_sdk_channel_inbound.
|
|
2216
|
+
const buildEnvelope = await (0, openclaw_plugin_sdk_channel_inbound.createChannelInboundEnvelopeBuilderAsync)({
|
|
2358
2217
|
cfg,
|
|
2359
2218
|
route
|
|
2360
2219
|
});
|
|
@@ -2719,7 +2578,7 @@ function resolveParentCacheExpiresAt(nowRaw) {
|
|
|
2719
2578
|
const nowMs = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(nowRaw);
|
|
2720
2579
|
return nowMs === void 0 ? void 0 : (0, openclaw_plugin_sdk_number_runtime.resolveExpiresAtMsFromDurationMs)(PARENT_CACHE_TTL_MS, { nowMs });
|
|
2721
2580
|
}
|
|
2722
|
-
async function fetchParentMessageCached(token, groupId, channelId, parentId,
|
|
2581
|
+
async function fetchParentMessageCached(token, groupId, channelId, parentId, deadline) {
|
|
2723
2582
|
const key = buildParentCacheKey(groupId, channelId, parentId);
|
|
2724
2583
|
const now = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(Date.now());
|
|
2725
2584
|
const cached = parentCache.get(key);
|
|
@@ -2730,7 +2589,7 @@ async function fetchParentMessageCached(token, groupId, channelId, parentId, fet
|
|
|
2730
2589
|
return cached.message;
|
|
2731
2590
|
}
|
|
2732
2591
|
if (cached) parentCache.delete(key);
|
|
2733
|
-
const message = await
|
|
2592
|
+
const message = await require_reaction_types.fetchChannelMessage(token, groupId, channelId, parentId, deadline);
|
|
2734
2593
|
const expiresAt = resolveParentCacheExpiresAt(Date.now());
|
|
2735
2594
|
if (expiresAt !== void 0) touchLru(parentCache, key, {
|
|
2736
2595
|
message,
|
|
@@ -2840,7 +2699,7 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
2840
2699
|
const [parentResult, repliesResult] = await require_resolve_allowlist.withMSTeamsRequestDeadline({
|
|
2841
2700
|
deadline,
|
|
2842
2701
|
label: "MS Teams thread history",
|
|
2843
|
-
work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId,
|
|
2702
|
+
work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, deadline), require_reaction_types.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, deadline)])
|
|
2844
2703
|
});
|
|
2845
2704
|
const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
|
|
2846
2705
|
const replies = repliesResult.status === "fulfilled" ? repliesResult.value : [];
|
|
@@ -3540,9 +3399,6 @@ async function runMSTeamsFeedbackInvokeHandler(context, deps) {
|
|
|
3540
3399
|
}
|
|
3541
3400
|
//#endregion
|
|
3542
3401
|
//#region extensions/msteams/src/file-consent-invoke.ts
|
|
3543
|
-
/**
|
|
3544
|
-
* Handle fileConsent/invoke activities for large file uploads.
|
|
3545
|
-
*/
|
|
3546
3402
|
async function handleMSTeamsFileConsentInvoke(context, log) {
|
|
3547
3403
|
const expiredUploadMessage = "The file upload request has expired. Please try sending the file again.";
|
|
3548
3404
|
const activity = context.activity;
|
|
@@ -3634,7 +3490,7 @@ async function handleMSTeamsFileConsentInvoke(context, log) {
|
|
|
3634
3490
|
async function runMSTeamsFileConsentInvokeHandler(context, log) {
|
|
3635
3491
|
try {
|
|
3636
3492
|
await require_conversation_store_state.withRevokedProxyFallback({
|
|
3637
|
-
run:
|
|
3493
|
+
run: () => handleMSTeamsFileConsentInvoke(context, log),
|
|
3638
3494
|
onRevoked: async () => true,
|
|
3639
3495
|
onRevokedLog: () => {
|
|
3640
3496
|
log.debug?.("turn context revoked during file consent invoke; skipping delayed response");
|
|
@@ -3849,23 +3705,22 @@ const STORE_KEY_VERSION_PREFIX = "v2:";
|
|
|
3849
3705
|
function makeMSTeamsSsoTokenStoreKey(connectionName, userId) {
|
|
3850
3706
|
return `${STORE_KEY_VERSION_PREFIX}${(0, node_crypto.createHash)("sha256").update(JSON.stringify([connectionName, userId])).digest("hex")}`;
|
|
3851
3707
|
}
|
|
3852
|
-
function createMSTeamsSsoTokenStoreFs(
|
|
3708
|
+
function createMSTeamsSsoTokenStoreFs() {
|
|
3853
3709
|
const tokenStore = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
3854
3710
|
namespace: MSTEAMS_SSO_TOKENS_NAMESPACE,
|
|
3855
|
-
maxEntries: MSTEAMS_MAX_SSO_TOKENS
|
|
3856
|
-
env: require_conversation_store_state.resolveMSTeamsSqliteStateEnv(params)
|
|
3711
|
+
maxEntries: MSTEAMS_MAX_SSO_TOKENS
|
|
3857
3712
|
});
|
|
3858
3713
|
return {
|
|
3859
3714
|
async get({ connectionName, userId }) {
|
|
3860
3715
|
return await tokenStore.lookup(makeMSTeamsSsoTokenStoreKey(connectionName, userId)) ?? null;
|
|
3861
3716
|
},
|
|
3862
3717
|
async save(token) {
|
|
3863
|
-
await require_conversation_store_state.withMSTeamsSqliteMutationLock(
|
|
3718
|
+
await require_conversation_store_state.withMSTeamsSqliteMutationLock(SSO_TOKEN_MUTATION_KEY, async () => {
|
|
3864
3719
|
await tokenStore.register(makeMSTeamsSsoTokenStoreKey(token.connectionName, token.userId), require_conversation_store_state.toPluginJsonValue({ ...token }));
|
|
3865
3720
|
});
|
|
3866
3721
|
},
|
|
3867
3722
|
async remove({ connectionName, userId }) {
|
|
3868
|
-
return require_conversation_store_state.withMSTeamsSqliteMutationLock(
|
|
3723
|
+
return require_conversation_store_state.withMSTeamsSqliteMutationLock(SSO_TOKEN_MUTATION_KEY, () => tokenStore.delete(makeMSTeamsSsoTokenStoreKey(connectionName, userId)));
|
|
3869
3724
|
}
|
|
3870
3725
|
};
|
|
3871
3726
|
}
|
|
@@ -3959,10 +3814,6 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3959
3814
|
const cleanAllowEntries = (entries) => entries?.map((entry) => cleanAllowEntry(entry)).filter((entry) => entry && entry !== "*") ?? [];
|
|
3960
3815
|
const isMutableUserEntry = (entry) => !isStableUserId(entry) && !/^accessGroup:/i.test(entry) && !require_resolve_allowlist.looksLikeMSTeamsConversationId(require_resolve_allowlist.normalizeMSTeamsConversationId(entry));
|
|
3961
3816
|
const resolveAllowlistUsers = async (label, entries) => {
|
|
3962
|
-
if (entries.length === 0) return {
|
|
3963
|
-
additions: [],
|
|
3964
|
-
unresolved: []
|
|
3965
|
-
};
|
|
3966
3817
|
const resolved = await require_resolve_allowlist.resolveMSTeamsUserAllowlist({
|
|
3967
3818
|
cfg,
|
|
3968
3819
|
entries
|