@openclaw/msteams 2026.7.2-beta.7 → 2026.8.1-beta.3
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/adapter.runtime-8g-MOPfb.cjs +311 -0
- package/dist/api.cjs +6 -6
- package/dist/{channel-C7QxRjBW.cjs → channel-KpWENcgK.cjs} +222 -265
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/{channel.runtime-DjY6d_hd.cjs → channel.runtime-Bkzj8jZ0.cjs} +131 -88
- package/dist/{setup-surface-ByWjaXEn.cjs → channel.setup-mOFtsfYz.cjs} +91 -50
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +18 -17
- package/dist/{messenger-DTiaLTDO.cjs → messenger-IISPSOvj.cjs} +61 -46
- package/dist/{oauth-CW6jVGp8.cjs → oauth-C9So7uld.cjs} +13 -26
- package/dist/{polls-BWKNpBSg.cjs → polls-DvuJvaDG.cjs} +6 -39
- package/dist/qa-runner-api.cjs +36 -0
- package/dist/{resolve-allowlist-CEj9sABO.cjs → resolve-allowlist-CIfWUwuc.cjs} +182 -118
- package/dist/rolldown-runtime-D6vf50IK.cjs +28 -0
- package/dist/runtime-api.cjs +1 -1
- package/dist/secret-contract-api.cjs +6 -30
- package/dist/setup-plugin-api.cjs +2 -37
- package/dist/{src-B_BdEvcr.cjs → src-C127-DcQ.cjs} +439 -269
- package/dist/{sso-token-store-TKYk_Ms7.cjs → sso-token-store-ChhO1f4i.cjs} +1 -1
- package/openclaw.plugin.json +34 -8
- package/package.json +4 -5
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.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_channel = require("./channel-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
4
|
+
const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
|
|
5
|
+
const require_channel = require("./channel-KpWENcgK.cjs");
|
|
6
|
+
const require_channel_setup = require("./channel.setup-mOFtsfYz.cjs");
|
|
7
|
+
const require_polls = require("./polls-DvuJvaDG.cjs");
|
|
8
|
+
const require_sso_token_store = require("./sso-token-store-ChhO1f4i.cjs");
|
|
9
|
+
const require_messenger = require("./messenger-IISPSOvj.cjs");
|
|
9
10
|
let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
|
|
10
11
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
11
12
|
let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
|
|
13
|
+
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
12
14
|
let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
|
|
13
15
|
let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
|
|
14
|
-
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
15
16
|
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
16
17
|
let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
|
|
17
18
|
let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
|
|
18
19
|
let node_crypto = require("node:crypto");
|
|
19
|
-
node_crypto =
|
|
20
|
+
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
20
21
|
let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
|
|
21
22
|
let openclaw_plugin_sdk_channel_inbound = require("openclaw/plugin-sdk/channel-inbound");
|
|
22
23
|
let openclaw_plugin_sdk_channel_ingress_runtime = require("openclaw/plugin-sdk/channel-ingress-runtime");
|
|
@@ -26,7 +27,9 @@ let openclaw_plugin_sdk_agent_runtime = require("openclaw/plugin-sdk/agent-runti
|
|
|
26
27
|
let openclaw_plugin_sdk_extension_shared = require("openclaw/plugin-sdk/extension-shared");
|
|
27
28
|
let openclaw_plugin_sdk_plugin_runtime = require("openclaw/plugin-sdk/plugin-runtime");
|
|
28
29
|
let openclaw_plugin_sdk_dedupe_runtime = require("openclaw/plugin-sdk/dedupe-runtime");
|
|
30
|
+
let openclaw_plugin_sdk_plugin_state_runtime = require("openclaw/plugin-sdk/plugin-state-runtime");
|
|
29
31
|
let openclaw_plugin_sdk_collection_runtime = require("openclaw/plugin-sdk/collection-runtime");
|
|
32
|
+
let openclaw_plugin_sdk_gateway_runtime = require("openclaw/plugin-sdk/gateway-runtime");
|
|
30
33
|
let openclaw_plugin_sdk_channel_pairing = require("openclaw/plugin-sdk/channel-pairing");
|
|
31
34
|
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
32
35
|
let openclaw_plugin_sdk_runtime_group_policy = require("openclaw/plugin-sdk/runtime-group-policy");
|
|
@@ -86,11 +89,11 @@ async function runFeedbackReflection(params) {
|
|
|
86
89
|
thumbedDownResponse: params.thumbedDownResponse,
|
|
87
90
|
userComment: params.userComment,
|
|
88
91
|
cooldownMs,
|
|
89
|
-
onRecordError: (err) => log.debug?.("reflection session record failed", { error:
|
|
90
|
-
onDispatchError: (err) => log.debug?.("reflection reply error", { error:
|
|
92
|
+
onRecordError: (err) => log.debug?.("reflection session record failed", { error: require_channel_setup.formatUnknownError(err) }),
|
|
93
|
+
onDispatchError: (err) => log.debug?.("reflection reply error", { error: require_channel_setup.formatUnknownError(err) })
|
|
91
94
|
});
|
|
92
95
|
} catch (err) {
|
|
93
|
-
log.error("reflection dispatch failed", { error:
|
|
96
|
+
log.error("reflection dispatch failed", { error: require_channel_setup.formatUnknownError(err) });
|
|
94
97
|
return;
|
|
95
98
|
}
|
|
96
99
|
if (reflection.status === "cooldown") {
|
|
@@ -113,7 +116,7 @@ async function runFeedbackReflection(params) {
|
|
|
113
116
|
learning: reflection.learning
|
|
114
117
|
});
|
|
115
118
|
} catch (err) {
|
|
116
|
-
log.debug?.("failed to store reflection learning", { error:
|
|
119
|
+
log.debug?.("failed to store reflection learning", { error: require_channel_setup.formatUnknownError(err) });
|
|
117
120
|
}
|
|
118
121
|
const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(params.conversationRef.conversation?.conversationType);
|
|
119
122
|
if (!(conversationType === "personal" && reflection.followUp && Boolean(reflection.userMessage))) {
|
|
@@ -130,7 +133,7 @@ async function runFeedbackReflection(params) {
|
|
|
130
133
|
}, { serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(cfg.channels?.msteams) });
|
|
131
134
|
log.info("sent reflection follow-up", { sessionKey });
|
|
132
135
|
} catch (err) {
|
|
133
|
-
log.debug?.("failed to send reflection follow-up", { error:
|
|
136
|
+
log.debug?.("failed to send reflection follow-up", { error: require_channel_setup.formatUnknownError(err) });
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
139
|
//#endregion
|
|
@@ -237,50 +240,53 @@ async function resolveMSTeamsSenderAccess(params) {
|
|
|
237
240
|
channelName: activity.channelData?.channel?.name,
|
|
238
241
|
allowNameMatching
|
|
239
242
|
});
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
...!isDirectMessage ? { "conversation-id": conversationId } : {}
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
conversation: {
|
|
255
|
-
kind: isDirectMessage ? "direct" : convType === "channel" ? "channel" : "group",
|
|
256
|
-
id: conversationId,
|
|
257
|
-
parentId: activity.channelData?.team?.id
|
|
258
|
-
},
|
|
259
|
-
route: (0, openclaw_plugin_sdk_channel_ingress_runtime.channelIngressRoutes)(!isDirectMessage && channelGate.allowlistConfigured && {
|
|
260
|
-
id: "msteams:team-channel",
|
|
261
|
-
kind: "nestedAllowlist",
|
|
262
|
-
allowed: channelGate.allowed,
|
|
263
|
-
precedence: 0,
|
|
264
|
-
matchId: "msteams-route",
|
|
265
|
-
...channelGate.allowed && groupPolicy === "allowlist" ? {
|
|
266
|
-
senderPolicy: "deny-when-empty",
|
|
267
|
-
senderAllowFromSource: "effective-group"
|
|
268
|
-
} : {}
|
|
269
|
-
}),
|
|
270
|
-
dmPolicy,
|
|
271
|
-
groupPolicy,
|
|
272
|
-
policy: {
|
|
273
|
-
groupAllowFromFallbackToAllowFrom: true,
|
|
274
|
-
mutableIdentifierMatching: allowNameMatching ? "enabled" : "disabled"
|
|
275
|
-
},
|
|
276
|
-
allowFrom: configuredDmAllowFrom,
|
|
277
|
-
groupAllowFrom,
|
|
278
|
-
command: {
|
|
279
|
-
allowTextCommands: true,
|
|
280
|
-
hasControlCommand: params.hasControlCommand === true,
|
|
281
|
-
directGroupAllowFrom: isDirectMessage ? "effective" : "none"
|
|
243
|
+
const resolved = await (0, openclaw_plugin_sdk_channel_ingress_runtime.resolveStableChannelMessageIngress)({
|
|
244
|
+
channelId: "msteams",
|
|
245
|
+
accountId: pairing.accountId,
|
|
246
|
+
identity: msteamsIngressIdentity,
|
|
247
|
+
cfg: params.cfg,
|
|
248
|
+
readStoreAllowFrom: pairing.readAllowFromStore,
|
|
249
|
+
subject: {
|
|
250
|
+
stableId: senderId,
|
|
251
|
+
aliases: {
|
|
252
|
+
"sender-name": senderName,
|
|
253
|
+
...!isDirectMessage ? { "conversation-id": conversationId } : {}
|
|
282
254
|
}
|
|
255
|
+
},
|
|
256
|
+
conversation: {
|
|
257
|
+
kind: isDirectMessage ? "direct" : convType === "channel" ? "channel" : "group",
|
|
258
|
+
id: conversationId,
|
|
259
|
+
threadId: params.conversationThreadId
|
|
260
|
+
},
|
|
261
|
+
...params.contextBinding ? { contextBinding: params.contextBinding } : {},
|
|
262
|
+
route: (0, openclaw_plugin_sdk_channel_ingress_runtime.channelIngressRoutes)(!isDirectMessage && channelGate.allowlistConfigured && {
|
|
263
|
+
id: "msteams:team-channel",
|
|
264
|
+
kind: "nestedAllowlist",
|
|
265
|
+
allowed: channelGate.allowed,
|
|
266
|
+
precedence: 0,
|
|
267
|
+
matchId: "msteams-route",
|
|
268
|
+
...channelGate.allowed && groupPolicy === "allowlist" ? {
|
|
269
|
+
senderPolicy: "deny-when-empty",
|
|
270
|
+
senderAllowFromSource: "effective-group"
|
|
271
|
+
} : {}
|
|
283
272
|
}),
|
|
273
|
+
dmPolicy,
|
|
274
|
+
groupPolicy,
|
|
275
|
+
policy: {
|
|
276
|
+
groupAllowFromFallbackToAllowFrom: true,
|
|
277
|
+
mutableIdentifierMatching: allowNameMatching ? "enabled" : "disabled"
|
|
278
|
+
},
|
|
279
|
+
allowFrom: configuredDmAllowFrom,
|
|
280
|
+
groupAllowFrom,
|
|
281
|
+
command: {
|
|
282
|
+
allowTextCommands: true,
|
|
283
|
+
hasControlCommand: params.hasControlCommand === true,
|
|
284
|
+
directGroupAllowFrom: isDirectMessage ? "effective" : "none"
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
return {
|
|
288
|
+
...resolved,
|
|
289
|
+
channelIngress: resolved,
|
|
284
290
|
pairing,
|
|
285
291
|
isDirectMessage,
|
|
286
292
|
conversationId,
|
|
@@ -325,7 +331,7 @@ async function admitMSTeamsMessage(params) {
|
|
|
325
331
|
});
|
|
326
332
|
if (senderAccess.decision === "pairing") {
|
|
327
333
|
params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
|
|
328
|
-
params.log.debug?.("failed to save conversation reference", { error:
|
|
334
|
+
params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
|
|
329
335
|
});
|
|
330
336
|
if (await pairing.upsertPairingRequest({
|
|
331
337
|
id: senderId,
|
|
@@ -381,7 +387,7 @@ async function admitMSTeamsMessage(params) {
|
|
|
381
387
|
params.log.debug?.("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
|
|
382
388
|
return null;
|
|
383
389
|
}
|
|
384
|
-
if (!senderAccess.allowed
|
|
390
|
+
if (!senderAccess.allowed) {
|
|
385
391
|
const allowMatch = require_channel.resolveMSTeamsAllowlistMatch({
|
|
386
392
|
allowFrom: effectiveGroupAllowFrom,
|
|
387
393
|
senderId,
|
|
@@ -411,7 +417,7 @@ async function admitMSTeamsMessage(params) {
|
|
|
411
417
|
return null;
|
|
412
418
|
}
|
|
413
419
|
params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
|
|
414
|
-
params.log.debug?.("failed to save conversation reference", { error:
|
|
420
|
+
params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
|
|
415
421
|
});
|
|
416
422
|
return {
|
|
417
423
|
...access,
|
|
@@ -473,7 +479,7 @@ async function fetchBotFrameworkAttachmentInfo(params) {
|
|
|
473
479
|
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
474
480
|
});
|
|
475
481
|
} catch (err) {
|
|
476
|
-
params.logger?.warn?.("msteams botFramework attachmentInfo fetch failed", { error:
|
|
482
|
+
params.logger?.warn?.("msteams botFramework attachmentInfo fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
477
483
|
return;
|
|
478
484
|
}
|
|
479
485
|
if (!response.ok) {
|
|
@@ -484,7 +490,7 @@ async function fetchBotFrameworkAttachmentInfo(params) {
|
|
|
484
490
|
try {
|
|
485
491
|
return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, "msteams botFramework attachmentInfo");
|
|
486
492
|
} catch (err) {
|
|
487
|
-
params.logger?.warn?.("msteams botFramework attachmentInfo parse failed", { error:
|
|
493
|
+
params.logger?.warn?.("msteams botFramework attachmentInfo parse failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
488
494
|
return;
|
|
489
495
|
}
|
|
490
496
|
}
|
|
@@ -506,7 +512,7 @@ async function saveBotFrameworkAttachmentView(params) {
|
|
|
506
512
|
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
507
513
|
});
|
|
508
514
|
} catch (err) {
|
|
509
|
-
params.logger?.warn?.("msteams botFramework attachmentView fetch failed", { error:
|
|
515
|
+
params.logger?.warn?.("msteams botFramework attachmentView fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
510
516
|
return;
|
|
511
517
|
}
|
|
512
518
|
if (!response.ok) {
|
|
@@ -519,7 +525,7 @@ async function saveBotFrameworkAttachmentView(params) {
|
|
|
519
525
|
contentLength = (0, openclaw_plugin_sdk_media_runtime.parseMediaContentLength)(response.headers.get("content-length"));
|
|
520
526
|
} catch (err) {
|
|
521
527
|
await response.body?.cancel().catch(() => void 0);
|
|
522
|
-
params.logger?.warn?.("msteams botFramework attachmentView invalid content-length", { error:
|
|
528
|
+
params.logger?.warn?.("msteams botFramework attachmentView invalid content-length", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
523
529
|
return;
|
|
524
530
|
}
|
|
525
531
|
if (contentLength !== null && contentLength > params.maxBytes) {
|
|
@@ -536,7 +542,7 @@ async function saveBotFrameworkAttachmentView(params) {
|
|
|
536
542
|
originalFilename: params.preserveFilenames ? params.fileNameHint : void 0
|
|
537
543
|
});
|
|
538
544
|
} catch (err) {
|
|
539
|
-
params.logger?.warn?.("msteams botFramework attachmentView save failed", { error:
|
|
545
|
+
params.logger?.warn?.("msteams botFramework attachmentView save failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
540
546
|
return;
|
|
541
547
|
} finally {
|
|
542
548
|
await response.body?.cancel().catch(() => void 0);
|
|
@@ -564,7 +570,7 @@ async function downloadMSTeamsBotFrameworkAttachment(params) {
|
|
|
564
570
|
work: () => tokenProvider.getAccessToken(BOT_FRAMEWORK_SCOPE)
|
|
565
571
|
});
|
|
566
572
|
} catch (err) {
|
|
567
|
-
params.logger?.warn?.("msteams botFramework token acquisition failed", { error:
|
|
573
|
+
params.logger?.warn?.("msteams botFramework token acquisition failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
568
574
|
return;
|
|
569
575
|
}
|
|
570
576
|
if (!accessToken) return;
|
|
@@ -665,7 +671,7 @@ async function downloadMSTeamsBotFrameworkAttachments(params) {
|
|
|
665
671
|
sourceId: attachmentId
|
|
666
672
|
});
|
|
667
673
|
params.logger?.warn?.("msteams botFramework attachment download failed", {
|
|
668
|
-
error:
|
|
674
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
|
|
669
675
|
attachmentId
|
|
670
676
|
});
|
|
671
677
|
}
|
|
@@ -878,9 +884,6 @@ function scopeCandidatesForUrl(url) {
|
|
|
878
884
|
return ["https://api.botframework.com", "https://graph.microsoft.com"];
|
|
879
885
|
}
|
|
880
886
|
}
|
|
881
|
-
function isRedirectStatus(status) {
|
|
882
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
883
|
-
}
|
|
884
887
|
async function resolveInlineDataImageMime(inline) {
|
|
885
888
|
const mime = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(await require_runtime.getMSTeamsRuntime().media.detectMime({
|
|
886
889
|
buffer: inline.data,
|
|
@@ -903,7 +906,7 @@ async function fetchWithAuthFallback(params) {
|
|
|
903
906
|
const tokenProvider = params.tokenProvider;
|
|
904
907
|
if (firstAttempt.status !== 401 && firstAttempt.status !== 403) return firstAttempt;
|
|
905
908
|
if (!require_resolve_allowlist.isUrlAllowed(params.url, params.policy.authAllowHosts)) return firstAttempt;
|
|
906
|
-
|
|
909
|
+
let fallbackAttempt = firstAttempt;
|
|
907
910
|
const scopes = scopeCandidatesForUrl(params.url);
|
|
908
911
|
const fetchFn = params.fetchFn ?? fetch;
|
|
909
912
|
for (const scope of scopes) try {
|
|
@@ -926,15 +929,11 @@ async function fetchWithAuthFallback(params) {
|
|
|
926
929
|
resolveFn: params.resolveFn,
|
|
927
930
|
timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
|
|
928
931
|
});
|
|
929
|
-
|
|
930
|
-
if (isRedirectStatus(authAttempt.status)) return authAttempt;
|
|
931
|
-
|
|
932
|
-
await authAttempt.body?.cancel();
|
|
933
|
-
continue;
|
|
934
|
-
}
|
|
935
|
-
await authAttempt.body?.cancel();
|
|
932
|
+
await fallbackAttempt.body?.cancel().catch(() => void 0);
|
|
933
|
+
if (authAttempt.ok || require_resolve_allowlist.isRedirectStatus(authAttempt.status)) return authAttempt;
|
|
934
|
+
fallbackAttempt = authAttempt;
|
|
936
935
|
} catch {}
|
|
937
|
-
return
|
|
936
|
+
return fallbackAttempt;
|
|
938
937
|
}
|
|
939
938
|
/**
|
|
940
939
|
* Download all file attachments from a Teams message (images, documents, etc.).
|
|
@@ -1015,7 +1014,7 @@ async function downloadMSTeamsAttachments(params) {
|
|
|
1015
1014
|
}, candidate.sourceId));
|
|
1016
1015
|
} catch (err) {
|
|
1017
1016
|
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1018
|
-
params.logger?.warn?.("msteams inline attachment decode failed", { error:
|
|
1017
|
+
params.logger?.warn?.("msteams inline attachment decode failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1019
1018
|
}
|
|
1020
1019
|
continue;
|
|
1021
1020
|
}
|
|
@@ -1047,7 +1046,7 @@ async function downloadMSTeamsAttachments(params) {
|
|
|
1047
1046
|
out.push(withSourceId(media, candidate.sourceId));
|
|
1048
1047
|
} catch (err) {
|
|
1049
1048
|
out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
|
|
1050
|
-
const msg =
|
|
1049
|
+
const msg = (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err);
|
|
1051
1050
|
params.logger?.warn?.(`msteams attachment download failed host=${safeHostForLog(candidate.url)} error=${msg}`);
|
|
1052
1051
|
}
|
|
1053
1052
|
}
|
|
@@ -1086,6 +1085,10 @@ function buildMSTeamsGraphMessageUrl(params) {
|
|
|
1086
1085
|
if (!chatId) return;
|
|
1087
1086
|
return `${require_resolve_allowlist.GRAPH_ROOT}/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
|
|
1088
1087
|
}
|
|
1088
|
+
async function releaseGraphResponse(response, release) {
|
|
1089
|
+
if (!response.bodyUsed) response.body?.cancel().catch(() => void 0);
|
|
1090
|
+
await release();
|
|
1091
|
+
}
|
|
1089
1092
|
async function fetchGraphCollection(params) {
|
|
1090
1093
|
const fetchFn = params.fetchFn ?? fetch;
|
|
1091
1094
|
const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
@@ -1098,13 +1101,10 @@ async function fetchGraphCollection(params) {
|
|
|
1098
1101
|
});
|
|
1099
1102
|
try {
|
|
1100
1103
|
const status = response.status;
|
|
1101
|
-
if (!response.ok) {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
items: []
|
|
1106
|
-
};
|
|
1107
|
-
}
|
|
1104
|
+
if (!response.ok) return {
|
|
1105
|
+
status,
|
|
1106
|
+
items: []
|
|
1107
|
+
};
|
|
1108
1108
|
try {
|
|
1109
1109
|
return {
|
|
1110
1110
|
status,
|
|
@@ -1117,7 +1117,7 @@ async function fetchGraphCollection(params) {
|
|
|
1117
1117
|
};
|
|
1118
1118
|
}
|
|
1119
1119
|
} finally {
|
|
1120
|
-
await release
|
|
1120
|
+
await releaseGraphResponse(response, release);
|
|
1121
1121
|
}
|
|
1122
1122
|
}
|
|
1123
1123
|
function normalizeGraphAttachment(att) {
|
|
@@ -1149,7 +1149,7 @@ async function downloadGraphHostedContent(params) {
|
|
|
1149
1149
|
deadline: params.deadline
|
|
1150
1150
|
});
|
|
1151
1151
|
} catch (err) {
|
|
1152
|
-
params.logger?.warn?.("msteams graph hostedContents fetch failed", { error:
|
|
1152
|
+
params.logger?.warn?.("msteams graph hostedContents fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1153
1153
|
return {
|
|
1154
1154
|
media: [],
|
|
1155
1155
|
count: 0
|
|
@@ -1194,11 +1194,11 @@ async function downloadGraphHostedContent(params) {
|
|
|
1194
1194
|
sourceId: item.id
|
|
1195
1195
|
});
|
|
1196
1196
|
} finally {
|
|
1197
|
-
await release
|
|
1197
|
+
await releaseGraphResponse(valRes, release);
|
|
1198
1198
|
}
|
|
1199
1199
|
} catch (err) {
|
|
1200
1200
|
out.push(createGraphHostedContentFact(item));
|
|
1201
|
-
params.logger?.warn?.("msteams graph hostedContent value fetch failed", { error:
|
|
1201
|
+
params.logger?.warn?.("msteams graph hostedContent value fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1202
1202
|
continue;
|
|
1203
1203
|
}
|
|
1204
1204
|
}
|
|
@@ -1227,9 +1227,9 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1227
1227
|
} catch (err) {
|
|
1228
1228
|
params.logger?.debug?.("graph media token acquisition failed", {
|
|
1229
1229
|
messageUrl,
|
|
1230
|
-
error:
|
|
1230
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1231
1231
|
});
|
|
1232
|
-
params.logger?.warn?.("msteams graph token acquisition failed", { error:
|
|
1232
|
+
params.logger?.warn?.("msteams graph token acquisition failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1233
1233
|
return {
|
|
1234
1234
|
media: [],
|
|
1235
1235
|
messageUrl,
|
|
@@ -1260,10 +1260,10 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1260
1260
|
} catch (err) {
|
|
1261
1261
|
params.logger?.debug?.("graph media message parse failed", {
|
|
1262
1262
|
messageUrl,
|
|
1263
|
-
error:
|
|
1263
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1264
1264
|
});
|
|
1265
1265
|
params.logger?.warn?.("msteams graph message parse failed", {
|
|
1266
|
-
error:
|
|
1266
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
|
|
1267
1267
|
messageUrl
|
|
1268
1268
|
});
|
|
1269
1269
|
msgData = {};
|
|
@@ -1275,14 +1275,14 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1275
1275
|
status: messageStatus
|
|
1276
1276
|
});
|
|
1277
1277
|
} finally {
|
|
1278
|
-
await release
|
|
1278
|
+
await releaseGraphResponse(msgRes, release);
|
|
1279
1279
|
}
|
|
1280
1280
|
} catch (err) {
|
|
1281
1281
|
params.logger?.debug?.("graph media message fetch failed", {
|
|
1282
1282
|
messageUrl,
|
|
1283
|
-
error:
|
|
1283
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
|
|
1284
1284
|
});
|
|
1285
|
-
params.logger?.warn?.("msteams graph message fetch failed", { error:
|
|
1285
|
+
params.logger?.warn?.("msteams graph message fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
|
|
1286
1286
|
}
|
|
1287
1287
|
for (const att of referenceAttachments) {
|
|
1288
1288
|
const name = att.name ?? "file";
|
|
@@ -1348,7 +1348,7 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1348
1348
|
} catch (err) {
|
|
1349
1349
|
sharePointMedia.push(unavailableMedia);
|
|
1350
1350
|
params.logger?.warn?.("msteams SharePoint reference download failed", {
|
|
1351
|
-
error:
|
|
1351
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
|
|
1352
1352
|
name
|
|
1353
1353
|
});
|
|
1354
1354
|
}
|
|
@@ -1387,7 +1387,7 @@ async function downloadMSTeamsGraphMedia(params) {
|
|
|
1387
1387
|
});
|
|
1388
1388
|
} catch (err) {
|
|
1389
1389
|
params.logger?.warn?.("msteams graph attachment download failed", {
|
|
1390
|
-
error:
|
|
1390
|
+
error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
|
|
1391
1391
|
messageUrl
|
|
1392
1392
|
});
|
|
1393
1393
|
}
|
|
@@ -1593,7 +1593,7 @@ async function prepareMSTeamsInboundContent(params) {
|
|
|
1593
1593
|
})
|
|
1594
1594
|
});
|
|
1595
1595
|
} catch (err) {
|
|
1596
|
-
params.log.debug?.("failed to resolve inbound Teams media", { error:
|
|
1596
|
+
params.log.debug?.("failed to resolve inbound Teams media", { error: require_channel_setup.formatUnknownError(err) });
|
|
1597
1597
|
}
|
|
1598
1598
|
const inboundMedia = mergeMSTeamsMediaFacts(params.advertisedMedia, mediaList);
|
|
1599
1599
|
const nativeMediaForComparison = [...params.advertisedMedia, ...mediaList.slice(params.advertisedMedia.length).map((media) => ({
|
|
@@ -1654,12 +1654,22 @@ function createTeamsReplyStreamController(params) {
|
|
|
1654
1654
|
let emittedText = "";
|
|
1655
1655
|
let acknowledgedText = "";
|
|
1656
1656
|
let acknowledgedStreamId;
|
|
1657
|
+
let replacementFinalPending = false;
|
|
1658
|
+
let replacementEmitFailed = false;
|
|
1659
|
+
let replacementSettlementPending = false;
|
|
1660
|
+
let replacementTextAwaitingAcknowledgement;
|
|
1661
|
+
let deferredReplacementEntries = [];
|
|
1662
|
+
let finalMetadataQueued = false;
|
|
1663
|
+
let failedSegmentFallbackPrepared = false;
|
|
1657
1664
|
const streamEvents = stream?.events;
|
|
1658
1665
|
let streamChunkSubscription;
|
|
1659
1666
|
if (typeof streamEvents?.on === "function" && typeof streamEvents.off === "function") streamChunkSubscription = streamEvents.on("chunk", (activity) => {
|
|
1660
|
-
|
|
1667
|
+
const replacementAcknowledgementPending = replacementTextAwaitingAcknowledgement !== void 0;
|
|
1668
|
+
const replacementAcknowledgement = typeof activity.text === "string" && replacementAcknowledgementPending && activity.text === replacementTextAwaitingAcknowledgement;
|
|
1669
|
+
if (activity.type !== "typing" || activity.channelData?.streamType !== "streaming" || !activity.id || !activity.text || acknowledgedStreamId !== void 0 && activity.id !== acknowledgedStreamId || (replacementAcknowledgementPending ? !replacementAcknowledgement : !activity.text.startsWith(acknowledgedText)) || !emittedText.startsWith(activity.text)) return;
|
|
1661
1670
|
acknowledgedStreamId = activity.id;
|
|
1662
1671
|
acknowledgedText = activity.text;
|
|
1672
|
+
if (activity.text === replacementTextAwaitingAcknowledgement) replacementTextAwaitingAcknowledgement = void 0;
|
|
1663
1673
|
});
|
|
1664
1674
|
const wasCanceled = () => canceledLocally || Boolean(stream?.canceled);
|
|
1665
1675
|
const releaseStreamChunkSubscription = () => {
|
|
@@ -1667,6 +1677,14 @@ function createTeamsReplyStreamController(params) {
|
|
|
1667
1677
|
streamEvents?.off(streamChunkSubscription);
|
|
1668
1678
|
streamChunkSubscription = void 0;
|
|
1669
1679
|
};
|
|
1680
|
+
const acknowledgedNativeDelivery = () => {
|
|
1681
|
+
if (!acknowledgedStreamId || !acknowledgedText) return { visibleReplySent: false };
|
|
1682
|
+
return {
|
|
1683
|
+
visibleReplySent: true,
|
|
1684
|
+
content: acknowledgedText,
|
|
1685
|
+
messageId: acknowledgedStreamId
|
|
1686
|
+
};
|
|
1687
|
+
};
|
|
1670
1688
|
const fallbackPayloadAfterAcknowledgedText = (payload) => {
|
|
1671
1689
|
if (!acknowledgedText || typeof payload.text !== "string" || !payload.text.startsWith(acknowledgedText)) return payload;
|
|
1672
1690
|
const remainingText = payload.text.slice(acknowledgedText.length);
|
|
@@ -1684,6 +1702,35 @@ function createTeamsReplyStreamController(params) {
|
|
|
1684
1702
|
mediaUrls: void 0
|
|
1685
1703
|
} : payload;
|
|
1686
1704
|
};
|
|
1705
|
+
const finalStreamActivity = (text) => ({
|
|
1706
|
+
type: "message",
|
|
1707
|
+
...text ? { text } : {},
|
|
1708
|
+
entities: [{
|
|
1709
|
+
type: "https://schema.org/Message",
|
|
1710
|
+
"@type": "Message",
|
|
1711
|
+
"@context": "https://schema.org",
|
|
1712
|
+
"@id": "",
|
|
1713
|
+
additionalType: ["AIGeneratedContent"]
|
|
1714
|
+
}],
|
|
1715
|
+
channelData: params.feedbackLoopEnabled ? { feedbackLoopEnabled: true } : {}
|
|
1716
|
+
});
|
|
1717
|
+
const deferredReplacementLogicalContent = () => {
|
|
1718
|
+
return deferredReplacementEntries.map((entry) => entry.payload.text).filter((text) => Boolean(text)).join("\n") || void 0;
|
|
1719
|
+
};
|
|
1720
|
+
const takeDeferredReplacementPayloads = (replacementFallback) => {
|
|
1721
|
+
const payloads = deferredReplacementEntries.flatMap((entry) => {
|
|
1722
|
+
if (entry.kind === "payload") return [entry.payload];
|
|
1723
|
+
const hasMedia = Boolean(entry.payload.mediaUrl || entry.payload.mediaUrls?.length);
|
|
1724
|
+
const text = replacementFallback?.text;
|
|
1725
|
+
if (!text && !hasMedia) return [];
|
|
1726
|
+
return [{
|
|
1727
|
+
...entry.payload,
|
|
1728
|
+
text: text || void 0
|
|
1729
|
+
}];
|
|
1730
|
+
});
|
|
1731
|
+
deferredReplacementEntries = [];
|
|
1732
|
+
return payloads;
|
|
1733
|
+
};
|
|
1687
1734
|
/**
|
|
1688
1735
|
* Render the current informative status line into the streaming card. Pulls
|
|
1689
1736
|
* the rotating "Thinking..." label from msteams config (or the plugin-sdk
|
|
@@ -1708,14 +1755,19 @@ function createTeamsReplyStreamController(params) {
|
|
|
1708
1755
|
canceledLocally = true;
|
|
1709
1756
|
return;
|
|
1710
1757
|
}
|
|
1711
|
-
params.log?.debug?.(`stream informative update failed: ${
|
|
1758
|
+
params.log?.debug?.(`stream informative update failed: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
|
|
1712
1759
|
}
|
|
1713
1760
|
};
|
|
1714
1761
|
const progressDraftGate = (0, openclaw_plugin_sdk_channel_outbound.createChannelProgressDraftGate)({ onStart: renderInformativeUpdate });
|
|
1715
1762
|
return {
|
|
1716
1763
|
async onReplyStart() {},
|
|
1717
1764
|
onPartialReply(payload) {
|
|
1718
|
-
if (!stream || !payload.text || wasCanceled() || streamMode !== "partial"
|
|
1765
|
+
if (!stream || !payload.text || wasCanceled() || streamMode !== "partial") return;
|
|
1766
|
+
if (replacementSettlementPending && replacementFinalPending) {
|
|
1767
|
+
pendingFinalPayload = { text: payload.text };
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
if (streamFinalizationPending) return;
|
|
1719
1771
|
const fullText = payload.text;
|
|
1720
1772
|
let prefixLength = 0;
|
|
1721
1773
|
while (prefixLength < emittedText.length && prefixLength < fullText.length && emittedText[prefixLength] === fullText[prefixLength]) prefixLength += 1;
|
|
@@ -1724,7 +1776,13 @@ function createTeamsReplyStreamController(params) {
|
|
|
1724
1776
|
if (!delta) return;
|
|
1725
1777
|
if (previousRemainder.trim()) {
|
|
1726
1778
|
stream.clearText();
|
|
1727
|
-
streamFailed
|
|
1779
|
+
if (streamFailed) {
|
|
1780
|
+
streamFinalizationPending = true;
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
replacementFinalPending = true;
|
|
1784
|
+
replacementSettlementPending = true;
|
|
1785
|
+
pendingFinalPayload = { text: fullText };
|
|
1728
1786
|
streamFinalizationPending = true;
|
|
1729
1787
|
return;
|
|
1730
1788
|
}
|
|
@@ -1739,7 +1797,7 @@ function createTeamsReplyStreamController(params) {
|
|
|
1739
1797
|
return;
|
|
1740
1798
|
}
|
|
1741
1799
|
streamFailed = true;
|
|
1742
|
-
params.log?.warn?.(`msteams stream emit failed, falling back to block delivery: ${
|
|
1800
|
+
params.log?.warn?.(`msteams stream emit failed, falling back to block delivery: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
|
|
1743
1801
|
}
|
|
1744
1802
|
},
|
|
1745
1803
|
/**
|
|
@@ -1781,6 +1839,49 @@ function createTeamsReplyStreamController(params) {
|
|
|
1781
1839
|
preparePayload(payload) {
|
|
1782
1840
|
if (!stream) return payload;
|
|
1783
1841
|
if (wasCanceled()) return;
|
|
1842
|
+
if (replacementSettlementPending) {
|
|
1843
|
+
if (!replacementFinalPending) {
|
|
1844
|
+
deferredReplacementEntries.push({
|
|
1845
|
+
kind: "payload",
|
|
1846
|
+
payload
|
|
1847
|
+
});
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
if (!payload.text) {
|
|
1851
|
+
deferredReplacementEntries.push({
|
|
1852
|
+
kind: "payload",
|
|
1853
|
+
payload
|
|
1854
|
+
});
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
replacementFinalPending = false;
|
|
1858
|
+
deferredReplacementEntries.push({
|
|
1859
|
+
kind: "replacement",
|
|
1860
|
+
payload
|
|
1861
|
+
});
|
|
1862
|
+
pendingFinalPayload = fallbackPayloadForSuppressedFinal(payload);
|
|
1863
|
+
try {
|
|
1864
|
+
replacementTextAwaitingAcknowledgement = payload.text;
|
|
1865
|
+
stream.emit(finalStreamActivity(payload.text));
|
|
1866
|
+
finalMetadataQueued = true;
|
|
1867
|
+
emittedText = payload.text;
|
|
1868
|
+
tokensEmitted = false;
|
|
1869
|
+
return;
|
|
1870
|
+
} catch (err) {
|
|
1871
|
+
replacementTextAwaitingAcknowledgement = void 0;
|
|
1872
|
+
tokensEmitted = false;
|
|
1873
|
+
if (isStreamCancelledError(err)) {
|
|
1874
|
+
canceledLocally = true;
|
|
1875
|
+
pendingFinalPayload = void 0;
|
|
1876
|
+
deferredReplacementEntries = [];
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
streamFailed = true;
|
|
1880
|
+
replacementEmitFailed = true;
|
|
1881
|
+
params.log?.warn?.(`msteams stream replacement failed, falling back to block delivery: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1784
1885
|
if (tokensEmitted && !streamFailed) {
|
|
1785
1886
|
const hasMedia = Boolean(payload.mediaUrl || payload.mediaUrls?.length);
|
|
1786
1887
|
pendingFinalPayload = fallbackPayloadForSuppressedFinal(payload);
|
|
@@ -1792,11 +1893,9 @@ function createTeamsReplyStreamController(params) {
|
|
|
1792
1893
|
} : void 0;
|
|
1793
1894
|
}
|
|
1794
1895
|
if (streamFailed) {
|
|
1795
|
-
const fallback = fallbackPayloadAfterAcknowledgedText(payload);
|
|
1896
|
+
const fallback = failedSegmentFallbackPrepared ? payload : fallbackPayloadAfterAcknowledgedText(payload);
|
|
1897
|
+
failedSegmentFallbackPrepared = true;
|
|
1796
1898
|
pendingFinalPayload = void 0;
|
|
1797
|
-
acknowledgedText = "";
|
|
1798
|
-
acknowledgedStreamId = void 0;
|
|
1799
|
-
releaseStreamChunkSubscription();
|
|
1800
1899
|
return fallback;
|
|
1801
1900
|
}
|
|
1802
1901
|
if (streamMode === "progress" && payload.text) try {
|
|
@@ -1813,7 +1912,7 @@ function createTeamsReplyStreamController(params) {
|
|
|
1813
1912
|
canceledLocally = true;
|
|
1814
1913
|
return;
|
|
1815
1914
|
}
|
|
1816
|
-
params.log?.debug?.(`progress-mode finalize failed: ${
|
|
1915
|
+
params.log?.debug?.(`progress-mode finalize failed: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
|
|
1817
1916
|
}
|
|
1818
1917
|
return payload;
|
|
1819
1918
|
},
|
|
@@ -1828,74 +1927,88 @@ function createTeamsReplyStreamController(params) {
|
|
|
1828
1927
|
releaseStreamChunkSubscription();
|
|
1829
1928
|
return { visibleReplySent: false };
|
|
1830
1929
|
}
|
|
1831
|
-
|
|
1930
|
+
let logicalContent;
|
|
1832
1931
|
try {
|
|
1833
1932
|
if (wasCanceled()) {
|
|
1834
1933
|
pendingFinalPayload = void 0;
|
|
1934
|
+
deferredReplacementEntries = [];
|
|
1835
1935
|
streamFinalizationPending = false;
|
|
1836
|
-
return
|
|
1837
|
-
visibleReplySent: content !== void 0,
|
|
1838
|
-
...content === void 0 ? {} : { content }
|
|
1839
|
-
};
|
|
1936
|
+
return acknowledgedNativeDelivery();
|
|
1840
1937
|
}
|
|
1841
|
-
if (!streamFinalizationPending) return
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
});
|
|
1938
|
+
if (!streamFinalizationPending) return acknowledgedNativeDelivery();
|
|
1939
|
+
if (replacementSettlementPending && replacementFinalPending && pendingFinalPayload?.text) {
|
|
1940
|
+
replacementFinalPending = false;
|
|
1941
|
+
deferredReplacementEntries.push({
|
|
1942
|
+
kind: "replacement",
|
|
1943
|
+
payload: pendingFinalPayload
|
|
1944
|
+
});
|
|
1945
|
+
replacementTextAwaitingAcknowledgement = pendingFinalPayload.text;
|
|
1946
|
+
logicalContent = deferredReplacementLogicalContent();
|
|
1947
|
+
stream.emit(finalStreamActivity(pendingFinalPayload.text));
|
|
1948
|
+
finalMetadataQueued = true;
|
|
1949
|
+
emittedText = pendingFinalPayload.text;
|
|
1950
|
+
}
|
|
1951
|
+
logicalContent ??= replacementSettlementPending ? deferredReplacementLogicalContent() : void 0;
|
|
1952
|
+
const content = pendingFinalPayload?.text ?? (emittedText || void 0);
|
|
1953
|
+
if (!finalMetadataQueued) stream.emit(finalStreamActivity());
|
|
1858
1954
|
const result = await stream.close();
|
|
1859
1955
|
streamFinalizationPending = false;
|
|
1860
1956
|
if (!result) {
|
|
1861
1957
|
const fallback = pendingFinalPayload;
|
|
1862
1958
|
pendingFinalPayload = void 0;
|
|
1863
|
-
const
|
|
1959
|
+
const canceled = wasCanceled();
|
|
1960
|
+
const replacementFallback = replacementSettlementPending && fallback && !canceled ? fallbackPayloadAfterAcknowledgedText(fallback) : void 0;
|
|
1961
|
+
const fallbackPayload = !replacementSettlementPending && fallback && !canceled ? fallbackPayloadAfterAcknowledgedText(fallback) : void 0;
|
|
1962
|
+
const postNativePayloads = replacementSettlementPending && !canceled ? takeDeferredReplacementPayloads(replacementFallback) : [];
|
|
1963
|
+
if (canceled) deferredReplacementEntries = [];
|
|
1864
1964
|
return {
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
...fallbackPayload ? { fallbackPayload } : {}
|
|
1965
|
+
...acknowledgedNativeDelivery(),
|
|
1966
|
+
...!canceled && logicalContent ? { logicalContent } : {},
|
|
1967
|
+
...fallbackPayload ? { fallbackPayload } : {},
|
|
1968
|
+
...postNativePayloads.length > 0 ? { postNativePayloads } : {}
|
|
1868
1969
|
};
|
|
1869
1970
|
}
|
|
1971
|
+
const replacementFallback = replacementSettlementPending && replacementEmitFailed && pendingFinalPayload ? fallbackPayloadAfterAcknowledgedText(pendingFinalPayload) : void 0;
|
|
1870
1972
|
pendingFinalPayload = void 0;
|
|
1871
|
-
const messageId = require_messenger.extractMessageId(result) ??
|
|
1973
|
+
const messageId = require_messenger.extractMessageId(result) ?? acknowledgedStreamId;
|
|
1974
|
+
const postNativePayloads = replacementSettlementPending ? takeDeferredReplacementPayloads(replacementFallback) : [];
|
|
1975
|
+
const nativeContent = replacementEmitFailed ? acknowledgedText || void 0 : content;
|
|
1872
1976
|
return {
|
|
1873
|
-
visibleReplySent: true,
|
|
1874
|
-
...
|
|
1875
|
-
...
|
|
1977
|
+
visibleReplySent: replacementEmitFailed ? Boolean(nativeContent) : true,
|
|
1978
|
+
...nativeContent === void 0 ? {} : { content: nativeContent },
|
|
1979
|
+
...logicalContent ? { logicalContent } : {},
|
|
1980
|
+
...messageId && (!replacementEmitFailed || nativeContent) ? { messageId } : {},
|
|
1981
|
+
...postNativePayloads.length > 0 ? { postNativePayloads } : {}
|
|
1876
1982
|
};
|
|
1877
1983
|
} catch (err) {
|
|
1878
1984
|
if (isStreamCancelledError(err)) {
|
|
1879
1985
|
canceledLocally = true;
|
|
1880
1986
|
pendingFinalPayload = void 0;
|
|
1987
|
+
deferredReplacementEntries = [];
|
|
1881
1988
|
streamFinalizationPending = false;
|
|
1882
|
-
return
|
|
1883
|
-
visibleReplySent: true,
|
|
1884
|
-
...content === void 0 ? {} : { content }
|
|
1885
|
-
};
|
|
1989
|
+
return acknowledgedNativeDelivery();
|
|
1886
1990
|
}
|
|
1887
1991
|
streamFailed = true;
|
|
1888
1992
|
streamFinalizationPending = false;
|
|
1889
|
-
params.log?.warn?.(`msteams stream finalize failed: ${
|
|
1993
|
+
params.log?.warn?.(`msteams stream finalize failed: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
|
|
1890
1994
|
const fallback = pendingFinalPayload;
|
|
1891
1995
|
pendingFinalPayload = void 0;
|
|
1892
|
-
const
|
|
1996
|
+
const replacementFallback = replacementSettlementPending && fallback ? fallbackPayloadAfterAcknowledgedText(fallback) : void 0;
|
|
1997
|
+
const fallbackPayload = !replacementSettlementPending && fallback ? fallbackPayloadAfterAcknowledgedText(fallback) : void 0;
|
|
1998
|
+
const postNativePayloads = replacementSettlementPending ? takeDeferredReplacementPayloads(replacementFallback) : [];
|
|
1893
1999
|
return {
|
|
1894
|
-
|
|
1895
|
-
...
|
|
1896
|
-
...fallbackPayload ? { fallbackPayload } : {}
|
|
2000
|
+
...acknowledgedNativeDelivery(),
|
|
2001
|
+
...logicalContent ? { logicalContent } : {},
|
|
2002
|
+
...fallbackPayload ? { fallbackPayload } : {},
|
|
2003
|
+
...postNativePayloads.length > 0 ? { postNativePayloads } : {}
|
|
1897
2004
|
};
|
|
1898
2005
|
} finally {
|
|
2006
|
+
finalMetadataQueued = false;
|
|
2007
|
+
replacementEmitFailed = false;
|
|
2008
|
+
replacementFinalPending = false;
|
|
2009
|
+
replacementSettlementPending = false;
|
|
2010
|
+
replacementTextAwaitingAcknowledgement = void 0;
|
|
2011
|
+
deferredReplacementEntries = [];
|
|
1899
2012
|
releaseStreamChunkSubscription();
|
|
1900
2013
|
}
|
|
1901
2014
|
},
|
|
@@ -1998,6 +2111,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
1998
2111
|
const blockStreamingEnabled = blockStreamingResolved ?? false;
|
|
1999
2112
|
const typingIndicatorEnabled = typeof msteamsCfg?.typingIndicator === "boolean" ? msteamsCfg.typingIndicator : true;
|
|
2000
2113
|
const pendingDeliveries = [];
|
|
2114
|
+
const joinAcceptedContents = (contents) => contents.filter((content) => Boolean(content)).join("\n");
|
|
2001
2115
|
const sendMessages = async (messages) => {
|
|
2002
2116
|
return require_messenger.sendMSTeamsMessages({
|
|
2003
2117
|
replyStyle: params.replyStyle,
|
|
@@ -2021,15 +2135,16 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2021
2135
|
});
|
|
2022
2136
|
};
|
|
2023
2137
|
const queueDeliveryFailureSystemEvent = (failure) => {
|
|
2024
|
-
const classification =
|
|
2025
|
-
const errorText =
|
|
2138
|
+
const classification = require_channel_setup.classifyMSTeamsSendError(failure.error);
|
|
2139
|
+
const errorText = require_channel_setup.formatUnknownError(failure.error);
|
|
2026
2140
|
const failedAll = failure.failed >= failure.total;
|
|
2141
|
+
const ambiguous = classification.kind === "ambiguous";
|
|
2027
2142
|
const sentences = [
|
|
2028
|
-
`Microsoft Teams delivery failed: ${failedAll ? "the previous reply was not delivered" : `${failure.failed} of ${failure.total} message blocks were not delivered`}.`,
|
|
2029
|
-
`The user may not have received ${failedAll ? "that reply" : "the full reply"}.`,
|
|
2143
|
+
`Microsoft Teams delivery failed: ${ambiguous ? failedAll ? "the delivery outcome is unknown for the previous reply" : `the delivery outcome is unknown for ${failure.failed} of ${failure.total} message blocks` : failedAll ? "the previous reply was not delivered" : `${failure.failed} of ${failure.total} message blocks were not delivered`}.`,
|
|
2144
|
+
ambiguous ? void 0 : `The user may not have received ${failedAll ? "that reply" : "the full reply"}.`,
|
|
2030
2145
|
`Error: ${errorText}.`,
|
|
2031
2146
|
classification.statusCode != null ? `Status: ${classification.statusCode}.` : void 0,
|
|
2032
|
-
|
|
2147
|
+
require_channel_setup.formatMSTeamsDeliveryFailureGuidance(classification)
|
|
2033
2148
|
].filter(Boolean);
|
|
2034
2149
|
core.system.enqueueSystemEvent(sentences.join(" "), {
|
|
2035
2150
|
sessionKey: params.sessionKey,
|
|
@@ -2046,11 +2161,13 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2046
2161
|
});
|
|
2047
2162
|
};
|
|
2048
2163
|
const deliveryOutcome = (delivery) => {
|
|
2049
|
-
const
|
|
2164
|
+
const acceptedParts = [...delivery.nativeResult ? [delivery.nativeResult] : [], ...delivery.blockResults];
|
|
2165
|
+
const messageIds = acceptedParts.flatMap((part) => part.messageIds);
|
|
2166
|
+
const content = delivery.errors.length > 0 ? joinAcceptedContents(acceptedParts.map((part) => part.content)) : delivery.content;
|
|
2050
2167
|
return {
|
|
2051
|
-
visibleReplySent:
|
|
2168
|
+
visibleReplySent: acceptedParts.length > 0,
|
|
2052
2169
|
...messageIds.length > 0 ? { messageIds } : {},
|
|
2053
|
-
...
|
|
2170
|
+
...acceptedParts.length > 0 && content !== void 0 ? { content } : {}
|
|
2054
2171
|
};
|
|
2055
2172
|
};
|
|
2056
2173
|
const settlePendingDelivery = (delivery) => {
|
|
@@ -2062,7 +2179,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2062
2179
|
return;
|
|
2063
2180
|
}
|
|
2064
2181
|
const error = delivery.errors.find((candidate) => !(candidate instanceof openclaw_plugin_sdk_error_runtime.PlatformMessageNotDispatchedError)) ?? delivery.errors[0];
|
|
2065
|
-
delivery.finalization.reject(
|
|
2182
|
+
delivery.finalization.reject(outcome.visibleReplySent ? (0, openclaw_plugin_sdk_channel_inbound.createChannelPartialDeliveryError)(error, {
|
|
2066
2183
|
...outcome,
|
|
2067
2184
|
visibleReplySent: true
|
|
2068
2185
|
}) : error);
|
|
@@ -2072,12 +2189,11 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2072
2189
|
messages,
|
|
2073
2190
|
finalization: (0, openclaw_plugin_sdk_extension_shared.createDeferred)(),
|
|
2074
2191
|
content: payload.text,
|
|
2192
|
+
blockResults: [],
|
|
2075
2193
|
native,
|
|
2076
2194
|
nativeSettled: !native,
|
|
2077
2195
|
blockSettled: messages.length === 0,
|
|
2078
2196
|
settled: false,
|
|
2079
|
-
visibleReplySent: false,
|
|
2080
|
-
messageIds: [],
|
|
2081
2197
|
errors: []
|
|
2082
2198
|
};
|
|
2083
2199
|
pendingDeliveries.push(delivery);
|
|
@@ -2093,9 +2209,11 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2093
2209
|
const sentIds = [];
|
|
2094
2210
|
for (const msg of toSend) try {
|
|
2095
2211
|
const msgIds = await sendMessages([msg]);
|
|
2096
|
-
delivery.visibleReplySent ||= msgIds.length > 0;
|
|
2097
2212
|
const validIds = msgIds.filter((id) => id.trim() && id !== "unknown");
|
|
2098
|
-
delivery.
|
|
2213
|
+
if (msgIds.length > 0) delivery.blockResults.push({
|
|
2214
|
+
messageIds: validIds,
|
|
2215
|
+
...msg.text ? { content: msg.text } : {}
|
|
2216
|
+
});
|
|
2099
2217
|
sentIds.push(...validIds);
|
|
2100
2218
|
} catch (msgError) {
|
|
2101
2219
|
failed += 1;
|
|
@@ -2119,7 +2237,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2119
2237
|
if (sentIds.length > 0) try {
|
|
2120
2238
|
params.onSentMessageIds?.(sentIds);
|
|
2121
2239
|
} catch (error) {
|
|
2122
|
-
params.log.warn?.("failed to record sent Teams message ids", { error:
|
|
2240
|
+
params.log.warn?.("failed to record sent Teams message ids", { error: require_channel_setup.formatUnknownError(error) });
|
|
2123
2241
|
}
|
|
2124
2242
|
}
|
|
2125
2243
|
};
|
|
@@ -2151,9 +2269,9 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2151
2269
|
};
|
|
2152
2270
|
},
|
|
2153
2271
|
onError: (err, info) => {
|
|
2154
|
-
const errMsg =
|
|
2155
|
-
const classification =
|
|
2156
|
-
const hint =
|
|
2272
|
+
const errMsg = require_channel_setup.formatUnknownError(err);
|
|
2273
|
+
const classification = require_channel_setup.classifyMSTeamsSendError(err);
|
|
2274
|
+
const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
|
|
2157
2275
|
params.runtime.error?.(`msteams ${info.kind} reply failed: ${errMsg}${hint ? ` (${hint})` : ""}`);
|
|
2158
2276
|
params.log.error("reply failed", {
|
|
2159
2277
|
kind: info.kind,
|
|
@@ -2179,11 +2297,16 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2179
2297
|
settlePendingDelivery(nativeDelivery);
|
|
2180
2298
|
return;
|
|
2181
2299
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2300
|
+
if (nativeResult.visibleReplySent) nativeDelivery.nativeResult = {
|
|
2301
|
+
messageIds: nativeResult.messageId ? [nativeResult.messageId] : [],
|
|
2302
|
+
...nativeResult.content !== void 0 ? { content: nativeResult.content } : {}
|
|
2303
|
+
};
|
|
2304
|
+
const hasPostNativePayloads = Boolean(nativeResult.postNativePayloads?.length);
|
|
2305
|
+
if (nativeResult.logicalContent !== void 0) nativeDelivery.content = nativeResult.logicalContent;
|
|
2306
|
+
else if (nativeResult.content !== void 0 && (!nativeResult.fallbackPayload && !hasPostNativePayloads || nativeDelivery.content === void 0)) nativeDelivery.content = nativeResult.content;
|
|
2307
|
+
const afterNativePayloads = [...nativeResult.fallbackPayload ? [nativeResult.fallbackPayload] : [], ...nativeResult.postNativePayloads ?? []];
|
|
2308
|
+
if (afterNativePayloads.length > 0) {
|
|
2309
|
+
nativeDelivery.messages.push(...afterNativePayloads.flatMap((payload) => renderReplyPayload(payload)));
|
|
2187
2310
|
nativeDelivery.blockSettled = nativeDelivery.messages.length === 0;
|
|
2188
2311
|
}
|
|
2189
2312
|
nativeDelivery.nativeSettled = true;
|
|
@@ -2192,7 +2315,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2192
2315
|
if (nativeResult.messageId) try {
|
|
2193
2316
|
params.onSentMessageIds?.([nativeResult.messageId]);
|
|
2194
2317
|
} catch (error) {
|
|
2195
|
-
params.log.warn?.("failed to record sent Teams message id", { error:
|
|
2318
|
+
params.log.warn?.("failed to record sent Teams message id", { error: require_channel_setup.formatUnknownError(error) });
|
|
2196
2319
|
}
|
|
2197
2320
|
};
|
|
2198
2321
|
const previewToolProgressEnabled = (0, openclaw_plugin_sdk_channel_outbound.resolveChannelStreamingPreviewToolProgress)(msteamsCfg, true, teamsStreamMode);
|
|
@@ -2201,10 +2324,10 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2201
2324
|
const progressCallbacks = streamController.hasStream() ? {
|
|
2202
2325
|
onReasoningStream: async (payload) => {
|
|
2203
2326
|
const text = typeof payload?.text === "string" ? payload.text : void 0;
|
|
2204
|
-
if (!text) return;
|
|
2327
|
+
if (!text) return false;
|
|
2205
2328
|
if (payload?.isReasoningSnapshot !== true) {
|
|
2206
2329
|
await streamController.pushProgressLine(text);
|
|
2207
|
-
return;
|
|
2330
|
+
return false;
|
|
2208
2331
|
}
|
|
2209
2332
|
await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLine)({
|
|
2210
2333
|
event: "item",
|
|
@@ -2213,6 +2336,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2213
2336
|
title: "Reasoning",
|
|
2214
2337
|
progressText: text
|
|
2215
2338
|
}));
|
|
2339
|
+
return false;
|
|
2216
2340
|
},
|
|
2217
2341
|
onToolStart: async (payload) => {
|
|
2218
2342
|
const name = typeof payload?.name === "string" ? payload.name : void 0;
|
|
@@ -2225,6 +2349,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2225
2349
|
...typeof payload?.phase === "string" ? { phase: payload.phase } : {},
|
|
2226
2350
|
...payload?.args && typeof payload.args === "object" ? { args: payload.args } : {}
|
|
2227
2351
|
}, detailMode === "explain" || detailMode === "raw" ? { detailMode } : void 0), name ? { toolName: name } : void 0);
|
|
2352
|
+
return false;
|
|
2228
2353
|
},
|
|
2229
2354
|
onItemEvent: async (payload) => {
|
|
2230
2355
|
await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLineForEntry)(msteamsCfg, {
|
|
@@ -2240,13 +2365,15 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2240
2365
|
...typeof payload?.progressText === "string" ? { progressText: payload.progressText } : {},
|
|
2241
2366
|
...typeof payload?.meta === "string" ? { meta: payload.meta } : {}
|
|
2242
2367
|
}));
|
|
2368
|
+
return false;
|
|
2243
2369
|
},
|
|
2244
2370
|
onPlanUpdate: async (payload) => {
|
|
2245
|
-
if (payload?.phase !== "update") return;
|
|
2371
|
+
if (payload?.phase !== "update") return false;
|
|
2246
2372
|
await streamController.pushPlanProgress((0, openclaw_plugin_sdk_channel_outbound.normalizeAgentPlanSteps)(payload.steps), { explanation: typeof payload.explanation === "string" ? payload.explanation : void 0 });
|
|
2373
|
+
return false;
|
|
2247
2374
|
},
|
|
2248
2375
|
onApprovalEvent: async (payload) => {
|
|
2249
|
-
if (payload?.phase !== "requested") return;
|
|
2376
|
+
if (payload?.phase !== "requested") return false;
|
|
2250
2377
|
await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLine)({
|
|
2251
2378
|
event: "approval",
|
|
2252
2379
|
phase: payload.phase,
|
|
@@ -2255,10 +2382,11 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2255
2382
|
...typeof payload?.reason === "string" ? { reason: payload.reason } : {},
|
|
2256
2383
|
...typeof payload?.message === "string" ? { message: payload.message } : {}
|
|
2257
2384
|
}));
|
|
2385
|
+
return false;
|
|
2258
2386
|
},
|
|
2259
2387
|
onCommandOutput: async (payload) => {
|
|
2260
|
-
if (payload?.phase !== "end") return;
|
|
2261
|
-
await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.
|
|
2388
|
+
if (payload?.phase !== "end") return false;
|
|
2389
|
+
await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLineForEntry)(msteamsCfg, {
|
|
2262
2390
|
event: "command-output",
|
|
2263
2391
|
...typeof payload?.itemId === "string" ? { itemId: payload.itemId } : {},
|
|
2264
2392
|
...typeof payload?.toolCallId === "string" ? { toolCallId: payload.toolCallId } : {},
|
|
@@ -2268,9 +2396,10 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2268
2396
|
...typeof payload?.status === "string" ? { status: payload.status } : {},
|
|
2269
2397
|
...typeof payload?.exitCode === "number" ? { exitCode: payload.exitCode } : {}
|
|
2270
2398
|
}));
|
|
2399
|
+
return false;
|
|
2271
2400
|
},
|
|
2272
2401
|
onPatchSummary: async (payload) => {
|
|
2273
|
-
if (payload?.phase !== "end") return;
|
|
2402
|
+
if (payload?.phase !== "end") return false;
|
|
2274
2403
|
await streamController.pushProgressLine((0, openclaw_plugin_sdk_channel_outbound.buildChannelProgressDraftLine)({
|
|
2275
2404
|
event: "patch",
|
|
2276
2405
|
...typeof payload?.itemId === "string" ? { itemId: payload.itemId } : {},
|
|
@@ -2283,6 +2412,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2283
2412
|
...Array.isArray(payload?.deleted) && payload.deleted.every((s) => typeof s === "string") ? { deleted: payload.deleted } : {},
|
|
2284
2413
|
...typeof payload?.summary === "string" ? { summary: payload.summary } : {}
|
|
2285
2414
|
}));
|
|
2415
|
+
return false;
|
|
2286
2416
|
}
|
|
2287
2417
|
} : {};
|
|
2288
2418
|
return {
|
|
@@ -2292,7 +2422,10 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2292
2422
|
},
|
|
2293
2423
|
delivery,
|
|
2294
2424
|
replyOptions: {
|
|
2295
|
-
...streamController.hasStream() ? { onPartialReply: (payload) =>
|
|
2425
|
+
...streamController.hasStream() ? { onPartialReply: (payload) => {
|
|
2426
|
+
streamController.onPartialReply(payload);
|
|
2427
|
+
return false;
|
|
2428
|
+
} } : {},
|
|
2296
2429
|
...progressCallbacks,
|
|
2297
2430
|
...shouldSuppressDefaultToolProgressMessages ? { suppressDefaultToolProgressMessages: true } : {},
|
|
2298
2431
|
disableBlockStreaming: blockStreamingResolved == null ? void 0 : !blockStreamingResolved,
|
|
@@ -2310,14 +2443,7 @@ const sentMessages = (0, openclaw_plugin_sdk_dedupe_runtime.createPersistentDedu
|
|
|
2310
2443
|
namespace: "msteams.sent-messages",
|
|
2311
2444
|
maxEntries: 1e3,
|
|
2312
2445
|
openStore: (options) => require_runtime.getOptionalMSTeamsRuntime()?.state.openKeyedStore(options),
|
|
2313
|
-
logError: (
|
|
2314
|
-
try {
|
|
2315
|
-
require_runtime.getOptionalMSTeamsRuntime()?.logging.getChildLogger({
|
|
2316
|
-
plugin: "msteams",
|
|
2317
|
-
feature: "sent-message-state"
|
|
2318
|
-
}).warn("Microsoft Teams persistent sent-message state failed", { error: String(error) });
|
|
2319
|
-
} catch {}
|
|
2320
|
-
},
|
|
2446
|
+
logError: (0, openclaw_plugin_sdk_plugin_state_runtime.createPluginStateErrorReporter)(require_runtime.getOptionalMSTeamsRuntime, "msteams", "sent-message-state", "Microsoft Teams persistent sent-message state failed"),
|
|
2321
2447
|
readTimestamp: (record) => record.sentAt
|
|
2322
2448
|
}
|
|
2323
2449
|
});
|
|
@@ -2389,7 +2515,21 @@ async function dispatchMSTeamsInboundTurn(params) {
|
|
|
2389
2515
|
}) : true;
|
|
2390
2516
|
const bodyForAgent = threadContext ? `[Thread history]\n${threadContext}\n[/Thread history]\n\n${agentBody}` : agentBody;
|
|
2391
2517
|
const nativeChannelId = isChannel && teamAadGroupId ? `${teamAadGroupId}/${graphChannelId}` : void 0;
|
|
2392
|
-
const
|
|
2518
|
+
const boundIngress = await resolveMSTeamsSenderAccess({
|
|
2519
|
+
cfg,
|
|
2520
|
+
activity,
|
|
2521
|
+
hasControlCommand: admission.isControlCommand,
|
|
2522
|
+
conversationThreadId: facts.threadId,
|
|
2523
|
+
contextBinding: {
|
|
2524
|
+
agentId: route.agentId,
|
|
2525
|
+
sessionKey: route.sessionKey,
|
|
2526
|
+
...activity.id ? { messageId: activity.id } : {},
|
|
2527
|
+
...nativeChannelId ? { nativeChannelId } : {},
|
|
2528
|
+
inboundEventKind: "user_request"
|
|
2529
|
+
}
|
|
2530
|
+
});
|
|
2531
|
+
const ctxPayload = core.channel.inbound.buildContext({
|
|
2532
|
+
channelIngress: boundIngress.channelIngress,
|
|
2393
2533
|
channel: "msteams",
|
|
2394
2534
|
contextVisibility: contextVisibilityMode,
|
|
2395
2535
|
supplemental: { quote: quoteInfo ? {
|
|
@@ -2422,6 +2562,8 @@ async function dispatchMSTeamsInboundTurn(params) {
|
|
|
2422
2562
|
},
|
|
2423
2563
|
reply: {
|
|
2424
2564
|
to: teamsTo,
|
|
2565
|
+
originatingTo: `conversation:${conversationId}`,
|
|
2566
|
+
messageThreadId: facts.threadId ?? void 0,
|
|
2425
2567
|
replyToId: activity.replyToId ?? void 0,
|
|
2426
2568
|
nativeChannelId
|
|
2427
2569
|
},
|
|
@@ -2502,7 +2644,7 @@ async function dispatchMSTeamsInboundTurn(params) {
|
|
|
2502
2644
|
},
|
|
2503
2645
|
ctxPayload,
|
|
2504
2646
|
record: { onRecordError: (err) => {
|
|
2505
|
-
logVerboseMessage(`msteams: failed updating session meta: ${
|
|
2647
|
+
logVerboseMessage(`msteams: failed updating session meta: ${require_channel_setup.formatUnknownError(err)}`);
|
|
2506
2648
|
} },
|
|
2507
2649
|
history: {
|
|
2508
2650
|
isGroup: isRoomish,
|
|
@@ -2521,18 +2663,15 @@ async function dispatchMSTeamsInboundTurn(params) {
|
|
|
2521
2663
|
});
|
|
2522
2664
|
const dispatchResult = turnResult.dispatched ? turnResult.dispatchResult : void 0;
|
|
2523
2665
|
const counts = (0, openclaw_plugin_sdk_channel_inbound.resolveInboundReplyDispatchCounts)(dispatchResult);
|
|
2524
|
-
log.info("dispatch complete", {
|
|
2525
|
-
queuedFinal: dispatchResult?.queuedFinal ?? false,
|
|
2526
|
-
counts
|
|
2527
|
-
});
|
|
2666
|
+
log.info("dispatch complete", { counts });
|
|
2528
2667
|
if ((0, openclaw_plugin_sdk_channel_inbound.hasFinalInboundReplyDispatch)(dispatchResult)) logVerboseMessage(`msteams: delivered ${counts.final} repl${counts.final === 1 ? "y" : "ies"} to ${teamsTo}`);
|
|
2529
2668
|
return {
|
|
2530
2669
|
kind: "completed",
|
|
2531
2670
|
finalResponses: counts.final
|
|
2532
2671
|
};
|
|
2533
2672
|
} catch (err) {
|
|
2534
|
-
log.error("dispatch failed", { error:
|
|
2535
|
-
runtime.error(`msteams dispatch failed: ${
|
|
2673
|
+
log.error("dispatch failed", { error: require_channel_setup.formatUnknownError(err) });
|
|
2674
|
+
runtime.error(`msteams dispatch failed: ${require_channel_setup.formatUnknownError(err)}`);
|
|
2536
2675
|
if (facts.turnAdoptionLifecycle) throw err;
|
|
2537
2676
|
try {
|
|
2538
2677
|
await context.sendActivity("⚠️ Something went wrong. Please try again.");
|
|
@@ -2797,7 +2936,7 @@ function prepareMSTeamsThreadRouting(params) {
|
|
|
2797
2936
|
}).catch((err) => {
|
|
2798
2937
|
params.log.debug?.("failed to resolve Teams AAD group ID", {
|
|
2799
2938
|
teamId: conversationTeamId,
|
|
2800
|
-
error:
|
|
2939
|
+
error: require_channel_setup.formatUnknownError(err)
|
|
2801
2940
|
});
|
|
2802
2941
|
});
|
|
2803
2942
|
teamAadGroupId = await teamGroupIdPromise;
|
|
@@ -2831,7 +2970,7 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
2831
2970
|
work: () => require_messenger.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
|
|
2832
2971
|
});
|
|
2833
2972
|
} catch (err) {
|
|
2834
|
-
params.log.debug?.("failed to fetch full quoted message text", { error:
|
|
2973
|
+
params.log.debug?.("failed to fetch full quoted message text", { error: require_channel_setup.formatUnknownError(err) });
|
|
2835
2974
|
}
|
|
2836
2975
|
let threadContext;
|
|
2837
2976
|
const threadParentId = activity.replyToId;
|
|
@@ -2848,8 +2987,8 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
2848
2987
|
});
|
|
2849
2988
|
const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
|
|
2850
2989
|
const replies = repliesResult.status === "fulfilled" ? repliesResult.value : [];
|
|
2851
|
-
if (parentResult.status === "rejected") params.log.debug?.("failed to fetch parent message", { error:
|
|
2852
|
-
if (repliesResult.status === "rejected") params.log.debug?.("failed to fetch thread replies", { error:
|
|
2990
|
+
if (parentResult.status === "rejected") params.log.debug?.("failed to fetch parent message", { error: require_channel_setup.formatUnknownError(parentResult.reason) });
|
|
2991
|
+
if (repliesResult.status === "rejected") params.log.debug?.("failed to fetch thread replies", { error: require_channel_setup.formatUnknownError(repliesResult.reason) });
|
|
2853
2992
|
const isThreadSenderAllowed = (message) => (0, openclaw_plugin_sdk_channel_inbound.resolveInboundSupplementalSenderAllowed)({
|
|
2854
2993
|
isGroup: params.isChannel,
|
|
2855
2994
|
groupPolicy: params.groupPolicy,
|
|
@@ -2886,7 +3025,7 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
2886
3025
|
});
|
|
2887
3026
|
threadContext = require_messenger.formatThreadContext(threadMessages, activity.id) || void 0;
|
|
2888
3027
|
} catch (err) {
|
|
2889
|
-
params.log.debug?.("failed to fetch thread history", { error:
|
|
3028
|
+
params.log.debug?.("failed to fetch thread history", { error: require_channel_setup.formatUnknownError(err) });
|
|
2890
3029
|
}
|
|
2891
3030
|
quoteSenderName ??= params.quoteInfo?.sender;
|
|
2892
3031
|
return {
|
|
@@ -2965,7 +3104,7 @@ function createMSTeamsMessageHandler(deps) {
|
|
|
2965
3104
|
} catch (err) {
|
|
2966
3105
|
log.error("failed to record poll vote", {
|
|
2967
3106
|
pollId: pollVote.pollId,
|
|
2968
|
-
error:
|
|
3107
|
+
error: require_channel_setup.formatUnknownError(err)
|
|
2969
3108
|
});
|
|
2970
3109
|
}
|
|
2971
3110
|
return;
|
|
@@ -3142,7 +3281,7 @@ function createMSTeamsMessageHandler(deps) {
|
|
|
3142
3281
|
});
|
|
3143
3282
|
},
|
|
3144
3283
|
onError: (err) => {
|
|
3145
|
-
runtime.error(`msteams debounce flush failed: ${
|
|
3284
|
+
runtime.error(`msteams debounce flush failed: ${require_channel_setup.formatUnknownError(err)}`);
|
|
3146
3285
|
}
|
|
3147
3286
|
});
|
|
3148
3287
|
return async function handleTeamsMessage(context, turnAdoptionLifecycle) {
|
|
@@ -3166,7 +3305,8 @@ function createMSTeamsReactionHandler(deps) {
|
|
|
3166
3305
|
const msteamsCfg = cfg.channels?.msteams;
|
|
3167
3306
|
return async function handleReaction(context, direction) {
|
|
3168
3307
|
const activity = context.activity;
|
|
3169
|
-
const
|
|
3308
|
+
const rawReactions = direction === "added" ? activity.reactionsAdded : activity.reactionsRemoved;
|
|
3309
|
+
const reactions = Array.isArray(rawReactions) ? rawReactions : [];
|
|
3170
3310
|
if (reactions.length === 0) {
|
|
3171
3311
|
log.debug?.("reaction activity has no reactions; skipping");
|
|
3172
3312
|
return;
|
|
@@ -3376,7 +3516,7 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3376
3516
|
return result;
|
|
3377
3517
|
} catch (err) {
|
|
3378
3518
|
if (turnAdoptionLifecycle) throw err;
|
|
3379
|
-
deps.runtime.error(`msteams handler failed: ${
|
|
3519
|
+
deps.runtime.error(`msteams handler failed: ${require_channel_setup.formatUnknownError(err)}`);
|
|
3380
3520
|
}
|
|
3381
3521
|
if (!nextRan) await runNext();
|
|
3382
3522
|
});
|
|
@@ -3402,7 +3542,7 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3402
3542
|
});
|
|
3403
3543
|
deps.log.info("sent welcome card");
|
|
3404
3544
|
} catch (err) {
|
|
3405
|
-
deps.log.debug?.("failed to send welcome card", { error:
|
|
3545
|
+
deps.log.debug?.("failed to send welcome card", { error: require_channel_setup.formatUnknownError(err) });
|
|
3406
3546
|
}
|
|
3407
3547
|
} else if (!isPersonal && msteamsCfg?.groupWelcomeCard === true) {
|
|
3408
3548
|
const botName = ctx.activity?.recipient?.name ?? void 0;
|
|
@@ -3410,7 +3550,7 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3410
3550
|
await ctx.sendActivity(buildGroupWelcomeText(botName));
|
|
3411
3551
|
deps.log.info("sent group welcome message");
|
|
3412
3552
|
} catch (err) {
|
|
3413
|
-
deps.log.debug?.("failed to send group welcome", { error:
|
|
3553
|
+
deps.log.debug?.("failed to send group welcome", { error: require_channel_setup.formatUnknownError(err) });
|
|
3414
3554
|
}
|
|
3415
3555
|
} else deps.log.debug?.("skipping welcome (disabled by config or conversation type)");
|
|
3416
3556
|
} else deps.log.debug?.("member added", { member: member.id });
|
|
@@ -3546,7 +3686,7 @@ async function runMSTeamsFeedbackInvokeHandler(context, deps) {
|
|
|
3546
3686
|
userComment,
|
|
3547
3687
|
log: deps.log
|
|
3548
3688
|
}).catch((err) => {
|
|
3549
|
-
deps.log.error("feedback reflection failed", { error:
|
|
3689
|
+
deps.log.error("feedback reflection failed", { error: require_channel_setup.formatUnknownError(err) });
|
|
3550
3690
|
});
|
|
3551
3691
|
return true;
|
|
3552
3692
|
}
|
|
@@ -3623,7 +3763,7 @@ async function handleMSTeamsFileConsentInvoke(context, log) {
|
|
|
3623
3763
|
} catch (err) {
|
|
3624
3764
|
log.error("file upload failed", {
|
|
3625
3765
|
uploadId,
|
|
3626
|
-
error:
|
|
3766
|
+
error: require_channel_setup.formatUnknownError(err)
|
|
3627
3767
|
});
|
|
3628
3768
|
await context.sendActivity("File upload failed. Please try again.");
|
|
3629
3769
|
} finally {
|
|
@@ -3656,10 +3796,28 @@ async function runMSTeamsFileConsentInvokeHandler(context, log) {
|
|
|
3656
3796
|
}
|
|
3657
3797
|
});
|
|
3658
3798
|
} catch (err) {
|
|
3659
|
-
log.debug?.("file consent handler error", { error:
|
|
3799
|
+
log.debug?.("file consent handler error", { error: require_channel_setup.formatUnknownError(err) });
|
|
3660
3800
|
}
|
|
3661
3801
|
}
|
|
3662
3802
|
//#endregion
|
|
3803
|
+
//#region extensions/msteams/src/monitor-status.ts
|
|
3804
|
+
function publishMSTeamsBlocked(statusSink, lastError) {
|
|
3805
|
+
statusSink?.((0, openclaw_plugin_sdk_gateway_runtime.channelBlockedPatch)(lastError, { running: true }));
|
|
3806
|
+
}
|
|
3807
|
+
function publishMSTeamsReady(statusSink, now = Date.now()) {
|
|
3808
|
+
statusSink?.((0, openclaw_plugin_sdk_gateway_runtime.channelReadyPatch)({ lastConnectedAt: now }));
|
|
3809
|
+
}
|
|
3810
|
+
function publishMSTeamsRecovering(statusSink, lastError) {
|
|
3811
|
+
statusSink?.({
|
|
3812
|
+
connected: false,
|
|
3813
|
+
lifecycle: "recovering",
|
|
3814
|
+
lastError
|
|
3815
|
+
});
|
|
3816
|
+
}
|
|
3817
|
+
function publishMSTeamsStopped(statusSink) {
|
|
3818
|
+
statusSink?.((0, openclaw_plugin_sdk_gateway_runtime.channelStoppedPatch)());
|
|
3819
|
+
}
|
|
3820
|
+
//#endregion
|
|
3663
3821
|
//#region extensions/msteams/src/msteams-ingress.ts
|
|
3664
3822
|
const MSTEAMS_INGRESS_VERSION = 1;
|
|
3665
3823
|
const MSTEAMS_INGRESS_DRAIN_INTERVAL_MS = 500;
|
|
@@ -3695,9 +3853,6 @@ function parseClaimedActivity(payload, claimedId) {
|
|
|
3695
3853
|
if (facts.eventId !== claimedId) throw new MSTeamsIngressPayloadError("invalid-activity", "Microsoft Teams activity id changed after durable admission.");
|
|
3696
3854
|
return parsed;
|
|
3697
3855
|
}
|
|
3698
|
-
function errorText(error) {
|
|
3699
|
-
return error instanceof Error ? error.message : String(error);
|
|
3700
|
-
}
|
|
3701
3856
|
function createMSTeamsIngress(options) {
|
|
3702
3857
|
const queue = options.queue ?? require_runtime.getMSTeamsRuntime().state.openChannelIngressQueue({ accountId: options.accountId });
|
|
3703
3858
|
const liveContexts = /* @__PURE__ */ new Map();
|
|
@@ -3746,15 +3901,15 @@ function createMSTeamsIngress(options) {
|
|
|
3746
3901
|
reason: error.reason,
|
|
3747
3902
|
message: error.message
|
|
3748
3903
|
};
|
|
3749
|
-
return
|
|
3904
|
+
return require_channel_setup.classifyMSTeamsSendError(error).kind === "auth" ? {
|
|
3750
3905
|
reason: "authentication-failed",
|
|
3751
|
-
message:
|
|
3906
|
+
message: (0, openclaw_plugin_sdk_error_runtime.formatErrorMessage)(error)
|
|
3752
3907
|
} : null;
|
|
3753
3908
|
},
|
|
3754
3909
|
onLog: (message) => options.runtime.error?.(`msteams: ${message}`)
|
|
3755
3910
|
},
|
|
3756
3911
|
createStoppedError: () => /* @__PURE__ */ new Error("Microsoft Teams ingress stopped."),
|
|
3757
|
-
onError: (error) => options.runtime.error?.(`msteams ingress drain failed: ${
|
|
3912
|
+
onError: (error) => options.runtime.error?.(`msteams ingress drain failed: ${(0, openclaw_plugin_sdk_error_runtime.formatErrorMessage)(error)}`)
|
|
3758
3913
|
});
|
|
3759
3914
|
let stopTask;
|
|
3760
3915
|
return {
|
|
@@ -3799,6 +3954,54 @@ function createMSTeamsIngress(options) {
|
|
|
3799
3954
|
};
|
|
3800
3955
|
}
|
|
3801
3956
|
//#endregion
|
|
3957
|
+
//#region extensions/msteams/src/replay-context.ts
|
|
3958
|
+
function createMSTeamsReplayContext(activity, app, serviceUrlBoundary) {
|
|
3959
|
+
const rawConversationId = activity.conversation?.id ?? "";
|
|
3960
|
+
const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
|
|
3961
|
+
const conversationType = activity.conversation?.conversationType ?? "personal";
|
|
3962
|
+
const normalizedConversationType = conversationType.toLowerCase();
|
|
3963
|
+
const threadActivityId = normalizedConversationType === "channel" ? require_resolve_allowlist.extractMSTeamsConversationMessageId(rawConversationId) ?? activity.replyToId : void 0;
|
|
3964
|
+
const quoteActivityId = normalizedConversationType === "channel" || normalizedConversationType === "groupchat" ? activity.id : void 0;
|
|
3965
|
+
const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
|
|
3966
|
+
const reference = {
|
|
3967
|
+
activityId: activity.id,
|
|
3968
|
+
user: activity.from,
|
|
3969
|
+
agent: activity.recipient,
|
|
3970
|
+
conversation: {
|
|
3971
|
+
id: conversationId,
|
|
3972
|
+
conversationType,
|
|
3973
|
+
...tenantId ? { tenantId } : {}
|
|
3974
|
+
},
|
|
3975
|
+
channelId: activity.channelId,
|
|
3976
|
+
serviceUrl: activity.serviceUrl,
|
|
3977
|
+
locale: activity.locale,
|
|
3978
|
+
...tenantId ? { tenantId } : {},
|
|
3979
|
+
...activity.from?.aadObjectId ? { aadObjectId: activity.from.aadObjectId } : {}
|
|
3980
|
+
};
|
|
3981
|
+
const proactiveOptions = {
|
|
3982
|
+
...quoteActivityId ? { quoteActivityId } : {},
|
|
3983
|
+
...threadActivityId ? { threadActivityId } : {},
|
|
3984
|
+
serviceUrlBoundary
|
|
3985
|
+
};
|
|
3986
|
+
const sendActivity = (outbound) => require_messenger.sendMSTeamsActivityWithReference(app, reference, outbound, proactiveOptions);
|
|
3987
|
+
return {
|
|
3988
|
+
activity,
|
|
3989
|
+
sendActivity,
|
|
3990
|
+
sendActivities: async (activities) => {
|
|
3991
|
+
const results = [];
|
|
3992
|
+
for (const outbound of activities) results.push(await sendActivity(outbound));
|
|
3993
|
+
return results;
|
|
3994
|
+
},
|
|
3995
|
+
updateActivity: async (outbound) => {
|
|
3996
|
+
return await require_messenger.updateMSTeamsActivityWithReference(app, reference, typeof outbound.id === "string" ? outbound.id : "", outbound, proactiveOptions);
|
|
3997
|
+
},
|
|
3998
|
+
deleteActivity: async (activityId) => {
|
|
3999
|
+
await require_messenger.deleteMSTeamsActivityWithReference(app, reference, activityId, proactiveOptions);
|
|
4000
|
+
},
|
|
4001
|
+
getTeamDetails: (teamId) => app.api.teams.getById(teamId)
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
//#endregion
|
|
3802
4005
|
//#region extensions/msteams/src/webhook-timeouts.ts
|
|
3803
4006
|
const MSTEAMS_WEBHOOK_INACTIVITY_TIMEOUT_MS = 3e4;
|
|
3804
4007
|
const MSTEAMS_WEBHOOK_REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -3820,6 +4023,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3820
4023
|
let msteamsCfg = cfg.channels?.msteams;
|
|
3821
4024
|
if (!msteamsCfg?.enabled) {
|
|
3822
4025
|
log.debug?.("msteams provider disabled");
|
|
4026
|
+
publishMSTeamsBlocked(opts.statusSink, "Microsoft Teams provider is disabled");
|
|
3823
4027
|
return {
|
|
3824
4028
|
app: null,
|
|
3825
4029
|
shutdown: async () => {}
|
|
@@ -3828,6 +4032,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3828
4032
|
const creds = require_resolve_allowlist.resolveMSTeamsCredentials(msteamsCfg);
|
|
3829
4033
|
if (!creds) {
|
|
3830
4034
|
log.error("msteams credentials not configured");
|
|
4035
|
+
publishMSTeamsBlocked(opts.statusSink, "Microsoft Teams credentials are not configured");
|
|
3831
4036
|
return {
|
|
3832
4037
|
app: null,
|
|
3833
4038
|
shutdown: async () => {}
|
|
@@ -3901,7 +4106,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3901
4106
|
(0, openclaw_plugin_sdk_allow_from.summarizeMapping)("msteams channels", resolved.mapping, resolved.unresolved, runtime);
|
|
3902
4107
|
}
|
|
3903
4108
|
} catch (err) {
|
|
3904
|
-
runtime.error?.(`msteams resolve failed; mutable allowlist entries are disabled. ${
|
|
4109
|
+
runtime.error?.(`msteams resolve failed; mutable allowlist entries are disabled. ${require_channel_setup.formatUnknownError(err)}`);
|
|
3905
4110
|
}
|
|
3906
4111
|
if (configuredGroupAllowFrom == null && groupAllowFrom) groupAllowFrom = (0, openclaw_plugin_sdk_allow_from.mergeAllowlist)({
|
|
3907
4112
|
existing: groupAllowFrom,
|
|
@@ -3922,9 +4127,10 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
3922
4127
|
};
|
|
3923
4128
|
const port = msteamsCfg.webhook?.port ?? 3978;
|
|
3924
4129
|
const textLimit = core.channel.text.resolveTextChunkLimit(cfg, "msteams");
|
|
3925
|
-
const
|
|
3926
|
-
|
|
3927
|
-
|
|
4130
|
+
const mediaMaxBytes = (0, openclaw_plugin_sdk_media_runtime.resolveChannelMediaMaxBytes)({
|
|
4131
|
+
cfg,
|
|
4132
|
+
resolveChannelLimitMb: ({ cfg: channelCfg }) => channelCfg.channels?.msteams?.mediaMaxMb
|
|
4133
|
+
}) ?? 8 * 1024 * 1024;
|
|
3928
4134
|
const conversationStore = opts.conversationStore ?? require_polls.createMSTeamsConversationStoreState();
|
|
3929
4135
|
const pollStore = opts.pollStore ?? require_polls.createMSTeamsPollStoreState();
|
|
3930
4136
|
log.info(`starting provider (port ${port})`);
|
|
@@ -4054,7 +4260,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4054
4260
|
} catch (err) {
|
|
4055
4261
|
log.error("failed to record poll vote", {
|
|
4056
4262
|
pollId: vote.pollId,
|
|
4057
|
-
error:
|
|
4263
|
+
error: require_channel_setup.formatUnknownError(err)
|
|
4058
4264
|
});
|
|
4059
4265
|
return {
|
|
4060
4266
|
statusCode: 500,
|
|
@@ -4077,7 +4283,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4077
4283
|
value: "OK"
|
|
4078
4284
|
};
|
|
4079
4285
|
} catch (err) {
|
|
4080
|
-
log.error("msteams card.action failed", { error:
|
|
4286
|
+
log.error("msteams card.action failed", { error: require_channel_setup.formatUnknownError(err) });
|
|
4081
4287
|
return {
|
|
4082
4288
|
statusCode: 500,
|
|
4083
4289
|
type: "application/vnd.microsoft.error",
|
|
@@ -4145,7 +4351,7 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4145
4351
|
hasExpiry: Boolean(ctx.token.expiration)
|
|
4146
4352
|
});
|
|
4147
4353
|
})().catch((err) => {
|
|
4148
|
-
log.error("msteams sso token persistence failed", { error:
|
|
4354
|
+
log.error("msteams sso token persistence failed", { error: require_channel_setup.formatUnknownError(err) });
|
|
4149
4355
|
});
|
|
4150
4356
|
});
|
|
4151
4357
|
app.on("message.submit", async (ctx) => {
|
|
@@ -4166,32 +4372,37 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4166
4372
|
try {
|
|
4167
4373
|
await handler.run(adaptedCtx);
|
|
4168
4374
|
} catch (err) {
|
|
4169
|
-
log.error("msteams non-turn activity failed", { error:
|
|
4375
|
+
log.error("msteams non-turn activity failed", { error: require_channel_setup.formatUnknownError(err) });
|
|
4170
4376
|
}
|
|
4171
4377
|
});
|
|
4172
4378
|
await app.initialize();
|
|
4173
4379
|
ingress.start();
|
|
4380
|
+
const privateQaRuntime = require_resolve_allowlist.resolveMSTeamsPrivateQaRuntime();
|
|
4174
4381
|
const httpServer = await new Promise((resolve, reject) => {
|
|
4175
|
-
const
|
|
4382
|
+
const onListen = (err) => err ? reject(err) : resolve(server);
|
|
4383
|
+
const server = privateQaRuntime ? expressApp.listen(port, privateQaRuntime.listenHost, onListen) : expressApp.listen(port, onListen);
|
|
4176
4384
|
}).catch(async (err) => {
|
|
4177
|
-
log.error("msteams server error", { error:
|
|
4385
|
+
log.error("msteams server error", { error: require_channel_setup.formatUnknownError(err) });
|
|
4178
4386
|
await ingress.stop();
|
|
4179
4387
|
throw err;
|
|
4180
4388
|
});
|
|
4181
4389
|
log.info(`msteams provider started on port ${port}`);
|
|
4390
|
+
publishMSTeamsReady(opts.statusSink);
|
|
4182
4391
|
applyMSTeamsWebhookTimeouts(httpServer);
|
|
4183
4392
|
httpServer.on("error", (err) => {
|
|
4184
|
-
log.error("msteams server error", { error:
|
|
4393
|
+
log.error("msteams server error", { error: require_channel_setup.formatUnknownError(err) });
|
|
4394
|
+
publishMSTeamsRecovering(opts.statusSink, require_channel_setup.formatUnknownError(err));
|
|
4185
4395
|
});
|
|
4186
4396
|
const shutdown = async () => {
|
|
4187
4397
|
log.info("shutting down msteams provider");
|
|
4188
4398
|
await new Promise((resolve) => {
|
|
4189
4399
|
httpServer.close((err) => {
|
|
4190
|
-
if (err) log.debug?.("msteams server close error", { error:
|
|
4400
|
+
if (err) log.debug?.("msteams server close error", { error: require_channel_setup.formatUnknownError(err) });
|
|
4191
4401
|
resolve();
|
|
4192
4402
|
});
|
|
4193
4403
|
});
|
|
4194
4404
|
await ingress.stop();
|
|
4405
|
+
publishMSTeamsStopped(opts.statusSink);
|
|
4195
4406
|
};
|
|
4196
4407
|
await (0, openclaw_plugin_sdk_channel_outbound.keepHttpServerTaskAlive)({
|
|
4197
4408
|
server: httpServer,
|
|
@@ -4247,47 +4458,6 @@ function buildActivityHandler() {
|
|
|
4247
4458
|
};
|
|
4248
4459
|
return handler;
|
|
4249
4460
|
}
|
|
4250
|
-
function createMSTeamsReplayContext(activity, app, serviceUrlBoundary) {
|
|
4251
|
-
const rawConversationId = activity.conversation?.id ?? "";
|
|
4252
|
-
const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
|
|
4253
|
-
const conversationType = activity.conversation?.conversationType ?? "personal";
|
|
4254
|
-
const threadActivityId = conversationType.toLowerCase() === "channel" ? require_resolve_allowlist.extractMSTeamsConversationMessageId(rawConversationId) ?? activity.replyToId : void 0;
|
|
4255
|
-
const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
|
|
4256
|
-
const reference = {
|
|
4257
|
-
activityId: activity.id,
|
|
4258
|
-
user: activity.from,
|
|
4259
|
-
agent: activity.recipient,
|
|
4260
|
-
conversation: {
|
|
4261
|
-
id: conversationId,
|
|
4262
|
-
conversationType,
|
|
4263
|
-
...tenantId ? { tenantId } : {}
|
|
4264
|
-
},
|
|
4265
|
-
channelId: activity.channelId,
|
|
4266
|
-
serviceUrl: activity.serviceUrl,
|
|
4267
|
-
locale: activity.locale,
|
|
4268
|
-
...tenantId ? { tenantId } : {},
|
|
4269
|
-
...activity.from?.aadObjectId ? { aadObjectId: activity.from.aadObjectId } : {}
|
|
4270
|
-
};
|
|
4271
|
-
const proactiveOptions = {
|
|
4272
|
-
...threadActivityId ? { threadActivityId } : {},
|
|
4273
|
-
serviceUrlBoundary
|
|
4274
|
-
};
|
|
4275
|
-
const sendActivity = (outbound) => require_messenger.sendMSTeamsActivityWithReference(app, reference, outbound, proactiveOptions);
|
|
4276
|
-
return {
|
|
4277
|
-
activity,
|
|
4278
|
-
sendActivity,
|
|
4279
|
-
sendActivities: async (activities) => {
|
|
4280
|
-
const results = [];
|
|
4281
|
-
for (const outbound of activities) results.push(await sendActivity(outbound));
|
|
4282
|
-
return results;
|
|
4283
|
-
},
|
|
4284
|
-
updateActivity: async (outbound) => await require_messenger.updateMSTeamsActivityWithReference(app, reference, typeof outbound.id === "string" ? outbound.id : "", outbound, proactiveOptions),
|
|
4285
|
-
deleteActivity: async (activityId) => {
|
|
4286
|
-
await require_messenger.deleteMSTeamsActivityWithReference(app, reference, activityId, proactiveOptions);
|
|
4287
|
-
},
|
|
4288
|
-
getTeamDetails: (teamId) => app.api.teams.getById(teamId)
|
|
4289
|
-
};
|
|
4290
|
-
}
|
|
4291
4461
|
/**
|
|
4292
4462
|
* Adapt a new @microsoft/teams.apps SDK context to the MSTeamsTurnContext interface
|
|
4293
4463
|
* our handlers expect. The new SDK uses reply()/send() instead of sendActivity().
|