@openclaw/msteams 2026.8.1-beta.2 → 2026.9.1-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/{adapter.runtime-DEYjslFX.cjs → adapter.runtime-8g-MOPfb.cjs} +4 -2
- package/dist/api.cjs +6 -6
- package/dist/approval-card-B6ZIMO83.cjs +303 -0
- package/dist/approval-handler.runtime-C3FXQ_6Z.cjs +107 -0
- package/dist/{channel-DfCbi0d_.cjs → channel-BsqcQ0E9.cjs} +174 -106
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/{channel.runtime-BJmueA4q.cjs → channel.runtime-DuQWuKFd.cjs} +38 -598
- package/dist/{setup-surface-DAhGL2h8.cjs → channel.setup-BvYxZIFG.cjs} +89 -36
- package/dist/configured-state.cjs +20 -0
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/{messenger-BqA8G3pY.cjs → messenger-BJB30CC2.cjs} +46 -188
- package/dist/{oauth-DktsbN22.cjs → oauth-BXQBTEta.cjs} +2 -2
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/reaction-types-dGkp4bkW.cjs +149 -0
- package/dist/{resolve-allowlist-C6YcNC9a.cjs → resolve-allowlist-B6FQAa3r.cjs} +71 -68
- package/dist/runtime-api.cjs +1 -1
- package/dist/secret-input-C65t6kjM.cjs +1 -0
- package/dist/send-S0VPVSUi.cjs +627 -0
- package/dist/setup-plugin-api.cjs +2 -36
- package/dist/{src-Bz9wY0Mr.cjs → src-NMnaP_95.cjs} +221 -106
- package/dist/thread-session-DdWfgc8U.cjs +63 -0
- package/package.json +13 -11
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
1
|
+
const require_resolve_allowlist = require("./resolve-allowlist-B6FQAa3r.cjs");
|
|
2
|
+
require("./secret-input-C65t6kjM.cjs");
|
|
3
|
+
const require_config_schema = require("./config-schema-C4CszdDi.cjs");
|
|
2
4
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
3
|
-
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
4
5
|
let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
|
|
6
|
+
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
5
7
|
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
6
8
|
let openclaw_plugin_sdk_channel_config_helpers = require("openclaw/plugin-sdk/channel-config-helpers");
|
|
9
|
+
let openclaw_plugin_sdk_secret_file_runtime = require("openclaw/plugin-sdk/secret-file-runtime");
|
|
10
|
+
let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
|
|
7
11
|
let openclaw_plugin_sdk_channel_setup = require("openclaw/plugin-sdk/channel-setup");
|
|
8
12
|
let openclaw_plugin_sdk_setup = require("openclaw/plugin-sdk/setup");
|
|
9
13
|
let openclaw_plugin_sdk_setup_tools = require("openclaw/plugin-sdk/setup-tools");
|
|
@@ -20,13 +24,23 @@ const msteamsMeta = {
|
|
|
20
24
|
aliases: ["teams"],
|
|
21
25
|
order: 60
|
|
22
26
|
};
|
|
27
|
+
function resolveMSTeamsAccount(cfg) {
|
|
28
|
+
const config = cfg.channels?.msteams;
|
|
29
|
+
const credentials = require_resolve_allowlist.resolveMSTeamsCredentials(config);
|
|
30
|
+
const certificatePath = credentials?.type === "federated" && !credentials.useManagedIdentity ? credentials.certificatePath : void 0;
|
|
31
|
+
const certificate = certificatePath ? (0, openclaw_plugin_sdk_secret_file_runtime.tryReadSecretFileSync)(certificatePath, "Microsoft Teams certificate", void 0, { configPath: config?.certificatePath?.trim() ? "channels.msteams.certificatePath" : "env.MSTEAMS_CERTIFICATE_PATH" }) : void 0;
|
|
32
|
+
const unavailable = certificate?.status === "configured_unavailable";
|
|
33
|
+
return {
|
|
34
|
+
accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
|
|
35
|
+
enabled: config?.enabled !== false,
|
|
36
|
+
configured: Boolean(credentials),
|
|
37
|
+
tokenStatus: !credentials ? "missing" : unavailable ? "configured_unavailable" : "available",
|
|
38
|
+
...unavailable ? { credentialDiagnostics: [certificate.diagnostic] } : {}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
23
41
|
const msteamsConfigAdapter = (0, openclaw_plugin_sdk_channel_config_helpers.createTopLevelChannelConfigAdapter)({
|
|
24
42
|
sectionKey: "msteams",
|
|
25
|
-
resolveAccount:
|
|
26
|
-
accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
|
|
27
|
-
enabled: cfg.channels?.msteams?.enabled !== false,
|
|
28
|
-
configured: Boolean(require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams))
|
|
29
|
-
}),
|
|
43
|
+
resolveAccount: resolveMSTeamsAccount,
|
|
30
44
|
resolveAccessorAccount: ({ cfg }) => ({
|
|
31
45
|
allowFrom: cfg.channels?.msteams?.allowFrom,
|
|
32
46
|
defaultTo: cfg.channels?.msteams?.defaultTo
|
|
@@ -220,12 +234,8 @@ function parseNonNegativeRetryAfterSeconds(raw) {
|
|
|
220
234
|
});
|
|
221
235
|
}
|
|
222
236
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* Important: We only mark errors as retryable when we have an explicit HTTP
|
|
226
|
-
* status code that indicates the message was not accepted (e.g. 429, 5xx).
|
|
227
|
-
* For transport-level errors where delivery is ambiguous, we prefer to avoid
|
|
228
|
-
* retries to reduce the chance of duplicate posts.
|
|
237
|
+
* Owns retry safety and delivery ambiguity for Teams send failures.
|
|
238
|
+
* Only Teams rate-limit rejection proves this unkeyed POST safe to replay.
|
|
229
239
|
*/
|
|
230
240
|
function classifyMSTeamsSendError(err) {
|
|
231
241
|
const statusCode = extractStatusCode(err);
|
|
@@ -249,15 +259,15 @@ function classifyMSTeamsSendError(err) {
|
|
|
249
259
|
};
|
|
250
260
|
}
|
|
251
261
|
if (statusCode === 429) return {
|
|
252
|
-
kind: "
|
|
262
|
+
kind: "replay-safe",
|
|
253
263
|
statusCode,
|
|
254
264
|
retryAfterMs: retryAfterMs ?? void 0,
|
|
255
265
|
errorCode
|
|
256
266
|
};
|
|
257
267
|
if (statusCode === 408 || statusCode != null && statusCode >= 500) return {
|
|
258
|
-
kind: "
|
|
268
|
+
kind: "ambiguous",
|
|
269
|
+
source: "http",
|
|
259
270
|
statusCode,
|
|
260
|
-
retryAfterMs: retryAfterMs ?? void 0,
|
|
261
271
|
errorCode
|
|
262
272
|
};
|
|
263
273
|
if (statusCode != null && statusCode >= 400) return {
|
|
@@ -265,17 +275,14 @@ function classifyMSTeamsSendError(err) {
|
|
|
265
275
|
statusCode,
|
|
266
276
|
errorCode
|
|
267
277
|
};
|
|
268
|
-
if (statusCode == null) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
};
|
|
274
|
-
}
|
|
278
|
+
if (statusCode == null && (0, openclaw_plugin_sdk_retry_runtime.isTransientNetworkError)(err)) return {
|
|
279
|
+
kind: "ambiguous",
|
|
280
|
+
source: "transport",
|
|
281
|
+
errorCode
|
|
282
|
+
};
|
|
275
283
|
return {
|
|
276
284
|
kind: "unknown",
|
|
277
285
|
statusCode: statusCode ?? void 0,
|
|
278
|
-
retryAfterMs: retryAfterMs ?? void 0,
|
|
279
286
|
errorCode
|
|
280
287
|
};
|
|
281
288
|
}
|
|
@@ -294,9 +301,15 @@ function isRevokedProxyError(err) {
|
|
|
294
301
|
function formatMSTeamsSendErrorHint(classification) {
|
|
295
302
|
if (classification.kind === "auth") return "check msteams appId/appPassword/tenantId (or env vars MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID)";
|
|
296
303
|
if (classification.errorCode === "ContentStreamNotAllowed") return "Teams expired the content stream; stop streaming earlier and fall back to normal message delivery";
|
|
297
|
-
if (classification.kind === "
|
|
298
|
-
if (classification.kind === "
|
|
299
|
-
|
|
304
|
+
if (classification.kind === "replay-safe") return "Teams throttled the bot; backing off may help";
|
|
305
|
+
if (classification.kind === "ambiguous") {
|
|
306
|
+
if (classification.source === "transport") return "transport-level failure sending to Teams Bot Connector (smba.trafficmanager.net); the outcome is unknown, so check egress and conversation history before taking further action";
|
|
307
|
+
return "Teams/Bot Framework delivery outcome is unknown; inspect the conversation history before taking further action";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function formatMSTeamsDeliveryFailureGuidance(classification) {
|
|
311
|
+
if (classification.kind === "replay-safe") return "The request was rate-limited before delivery; retrying later may succeed.";
|
|
312
|
+
if (classification.kind === "ambiguous") return "Delivery may already have succeeded; do not send the same content again without checking the conversation.";
|
|
300
313
|
}
|
|
301
314
|
//#endregion
|
|
302
315
|
//#region extensions/msteams/src/setup-surface.ts
|
|
@@ -466,7 +479,7 @@ const msteamsSetupWizard = {
|
|
|
466
479
|
};
|
|
467
480
|
let oauthModule;
|
|
468
481
|
try {
|
|
469
|
-
oauthModule = await Promise.resolve().then(() => require("./oauth-
|
|
482
|
+
oauthModule = await Promise.resolve().then(() => require("./oauth-BXQBTEta.cjs"));
|
|
470
483
|
} catch (err) {
|
|
471
484
|
await noteDelegatedAuthFailure(err);
|
|
472
485
|
return {
|
|
@@ -520,6 +533,40 @@ const msteamsSetupWizard = {
|
|
|
520
533
|
disable: (cfg) => (0, openclaw_plugin_sdk_setup.setSetupChannelEnabled)(cfg, channel, false)
|
|
521
534
|
};
|
|
522
535
|
//#endregion
|
|
536
|
+
//#region extensions/msteams/src/channel.setup.ts
|
|
537
|
+
const msteamsSetupPlugin = {
|
|
538
|
+
id: "msteams",
|
|
539
|
+
meta: {
|
|
540
|
+
...msteamsMeta,
|
|
541
|
+
aliases: [...msteamsMeta.aliases]
|
|
542
|
+
},
|
|
543
|
+
capabilities: {
|
|
544
|
+
chatTypes: [
|
|
545
|
+
"direct",
|
|
546
|
+
"channel",
|
|
547
|
+
"group",
|
|
548
|
+
"thread"
|
|
549
|
+
],
|
|
550
|
+
polls: true,
|
|
551
|
+
threads: true,
|
|
552
|
+
media: true,
|
|
553
|
+
reactions: true
|
|
554
|
+
},
|
|
555
|
+
reload: { configPrefixes: ["channels.msteams"] },
|
|
556
|
+
configSchema: require_config_schema.MSTeamsChannelConfigSchema,
|
|
557
|
+
config: {
|
|
558
|
+
...msteamsConfigAdapter,
|
|
559
|
+
isConfigured: (account) => account.configured,
|
|
560
|
+
describeAccount: (account) => (0, openclaw_plugin_sdk_account_helpers.describeAccountSnapshot)({
|
|
561
|
+
account,
|
|
562
|
+
configured: account.configured,
|
|
563
|
+
extra: { tokenStatus: account.tokenStatus }
|
|
564
|
+
})
|
|
565
|
+
},
|
|
566
|
+
setupWizard: msteamsSetupWizard,
|
|
567
|
+
setupContract: msteamsSetupContract
|
|
568
|
+
};
|
|
569
|
+
//#endregion
|
|
523
570
|
Object.defineProperty(exports, "classifyMSTeamsSendError", {
|
|
524
571
|
enumerable: true,
|
|
525
572
|
get: function() {
|
|
@@ -532,6 +579,12 @@ Object.defineProperty(exports, "createMSTeamsSetupWizardBase", {
|
|
|
532
579
|
return createMSTeamsSetupWizardBase;
|
|
533
580
|
}
|
|
534
581
|
});
|
|
582
|
+
Object.defineProperty(exports, "formatMSTeamsDeliveryFailureGuidance", {
|
|
583
|
+
enumerable: true,
|
|
584
|
+
get: function() {
|
|
585
|
+
return formatMSTeamsDeliveryFailureGuidance;
|
|
586
|
+
}
|
|
587
|
+
});
|
|
535
588
|
Object.defineProperty(exports, "formatMSTeamsSendErrorHint", {
|
|
536
589
|
enumerable: true,
|
|
537
590
|
get: function() {
|
|
@@ -556,22 +609,16 @@ Object.defineProperty(exports, "msteamsConfigAdapter", {
|
|
|
556
609
|
return msteamsConfigAdapter;
|
|
557
610
|
}
|
|
558
611
|
});
|
|
559
|
-
Object.defineProperty(exports, "msteamsMeta", {
|
|
560
|
-
enumerable: true,
|
|
561
|
-
get: function() {
|
|
562
|
-
return msteamsMeta;
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
612
|
Object.defineProperty(exports, "msteamsSetupAdapter", {
|
|
566
613
|
enumerable: true,
|
|
567
614
|
get: function() {
|
|
568
615
|
return msteamsSetupAdapter;
|
|
569
616
|
}
|
|
570
617
|
});
|
|
571
|
-
Object.defineProperty(exports, "
|
|
618
|
+
Object.defineProperty(exports, "msteamsSetupPlugin", {
|
|
572
619
|
enumerable: true,
|
|
573
620
|
get: function() {
|
|
574
|
-
return
|
|
621
|
+
return msteamsSetupPlugin;
|
|
575
622
|
}
|
|
576
623
|
});
|
|
577
624
|
Object.defineProperty(exports, "msteamsSetupWizard", {
|
|
@@ -586,3 +633,9 @@ Object.defineProperty(exports, "openDelegatedOAuthUrl", {
|
|
|
586
633
|
return openDelegatedOAuthUrl;
|
|
587
634
|
}
|
|
588
635
|
});
|
|
636
|
+
Object.defineProperty(exports, "resolveMSTeamsAccount", {
|
|
637
|
+
enumerable: true,
|
|
638
|
+
get: function() {
|
|
639
|
+
return resolveMSTeamsAccount;
|
|
640
|
+
}
|
|
641
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("./secret-input-C65t6kjM.cjs");
|
|
3
|
+
let openclaw_plugin_sdk_secret_input = require("openclaw/plugin-sdk/secret-input");
|
|
4
|
+
//#region extensions/msteams/configured-state.ts
|
|
5
|
+
/** Mirror Teams auth-mode requirements without loading the Azure SDK or full channel. */
|
|
6
|
+
function hasConfiguredMSTeamsChannelState(params) {
|
|
7
|
+
const config = params.cfg.channels?.msteams;
|
|
8
|
+
if (config?.enabled === false) return false;
|
|
9
|
+
const env = params.env ?? process.env;
|
|
10
|
+
const appId = (0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(config && Object.hasOwn(config, "appId") ? config.appId : env.MSTEAMS_APP_ID);
|
|
11
|
+
const tenantId = (0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(config && Object.hasOwn(config, "tenantId") ? config.tenantId : env.MSTEAMS_TENANT_ID);
|
|
12
|
+
if (!appId || !tenantId) return false;
|
|
13
|
+
if ((config?.authType ?? env.MSTEAMS_AUTH_TYPE ?? "secret") === "federated") {
|
|
14
|
+
const certificatePath = (0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(config && Object.hasOwn(config, "certificatePath") ? config.certificatePath : env.MSTEAMS_CERTIFICATE_PATH);
|
|
15
|
+
return Boolean(certificatePath || (config?.useManagedIdentity ?? env.MSTEAMS_USE_MANAGED_IDENTITY === "true"));
|
|
16
|
+
}
|
|
17
|
+
return config && Object.hasOwn(config, "appPassword") ? (0, openclaw_plugin_sdk_secret_input.hasConfiguredSecretInput)(config.appPassword) : Boolean((0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(env.MSTEAMS_APP_PASSWORD));
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
exports.hasConfiguredMSTeamsChannelState = hasConfiguredMSTeamsChannelState;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
2
|
+
const require_resolve_allowlist = require("./resolve-allowlist-B6FQAa3r.cjs");
|
|
3
3
|
let openclaw_plugin_sdk_directory_runtime = require("openclaw/plugin-sdk/directory-runtime");
|
|
4
4
|
const msteamsDirectoryContractPlugin = {
|
|
5
5
|
id: "msteams",
|
|
@@ -1,132 +1,28 @@
|
|
|
1
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
|
|
4
|
+
const require_resolve_allowlist = require("./resolve-allowlist-B6FQAa3r.cjs");
|
|
5
|
+
const require_channel_setup = require("./channel.setup-BvYxZIFG.cjs");
|
|
6
6
|
const require_polls = require("./polls-DvuJvaDG.cjs");
|
|
7
7
|
let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
|
|
8
8
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
9
|
+
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
9
10
|
let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
|
|
10
11
|
let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
|
|
11
|
-
let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
|
|
12
|
-
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
13
12
|
let node_dns_promises = require("node:dns/promises");
|
|
14
13
|
let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
|
|
15
14
|
let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
|
|
16
|
-
let
|
|
15
|
+
let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
|
|
17
16
|
let node_crypto = require("node:crypto");
|
|
18
17
|
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
19
18
|
let node_path = require("node:path");
|
|
20
19
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
20
|
+
let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
|
|
21
21
|
let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
|
|
22
|
+
let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
|
|
22
23
|
let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
|
|
23
24
|
let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
|
|
24
25
|
let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
|
|
25
|
-
//#region extensions/msteams/src/graph-thread.ts
|
|
26
|
-
/**
|
|
27
|
-
* Strip HTML tags from Teams message content, preserving @mention display names.
|
|
28
|
-
* Teams wraps mentions in <at>Name</at> tags.
|
|
29
|
-
*/
|
|
30
|
-
function stripHtmlFromTeamsMessage(html) {
|
|
31
|
-
let text = html.replace(/<at[^>]*>(.*?)<\/at>/gi, "@$1");
|
|
32
|
-
text = text.replace(/<[^>]*>/g, " ");
|
|
33
|
-
text = (0, openclaw_plugin_sdk_html_entity_runtime.decodeHtmlEntities)(text).replaceAll("\xA0", " ");
|
|
34
|
-
return text.replace(/\s+/g, " ").trim();
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Fetch a single channel message (the parent/root of a thread).
|
|
38
|
-
* Returns undefined on error so callers can degrade gracefully.
|
|
39
|
-
*/
|
|
40
|
-
async function fetchChannelMessage(token, groupId, channelId, messageId, deadline) {
|
|
41
|
-
const path = `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}?$select=id,from,body,createdDateTime`;
|
|
42
|
-
try {
|
|
43
|
-
return await require_resolve_allowlist.fetchGraphJson({
|
|
44
|
-
token,
|
|
45
|
-
path,
|
|
46
|
-
...deadline ? { deadline } : {}
|
|
47
|
-
});
|
|
48
|
-
} catch {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Fetch a single chat message's full text via Graph and return plain text.
|
|
54
|
-
*
|
|
55
|
-
* Used to recover the complete quoted message for Teams quote replies: the
|
|
56
|
-
* inbound blockquote only carries a Teams-truncated `preview` snippet. The
|
|
57
|
-
* app-only `GET /chats/{chatId}/messages/{messageId}` endpoint IS permitted
|
|
58
|
-
* with the `Chat.Read.All` application permission.
|
|
59
|
-
*
|
|
60
|
-
* Returns undefined on any failure so callers degrade to the truncated preview.
|
|
61
|
-
*/
|
|
62
|
-
async function fetchChatMessageText(token, chatId, messageId, deadline) {
|
|
63
|
-
const path = `/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
|
|
64
|
-
try {
|
|
65
|
-
const msg = await require_resolve_allowlist.fetchGraphJson({
|
|
66
|
-
token,
|
|
67
|
-
path,
|
|
68
|
-
...deadline ? { deadline } : {}
|
|
69
|
-
});
|
|
70
|
-
const raw = msg.body?.content ?? "";
|
|
71
|
-
return (msg.body?.contentType === "html" ? stripHtmlFromTeamsMessage(raw) : raw.trim()) || void 0;
|
|
72
|
-
} catch {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Fetch thread replies for a channel message, ordered chronologically.
|
|
78
|
-
*
|
|
79
|
-
* **Limitation:** The Graph API replies endpoint (`/messages/{id}/replies`) does not
|
|
80
|
-
* support `$orderby`, so results are always returned in ascending (oldest-first) order.
|
|
81
|
-
* Combined with the `$top` cap of 50, this means only the **oldest 50 replies** are
|
|
82
|
-
* returned for long threads — newer replies are silently omitted. There is currently no
|
|
83
|
-
* Graph API workaround for this; pagination via `@odata.nextLink` can retrieve more
|
|
84
|
-
* replies but still in ascending order only.
|
|
85
|
-
*/
|
|
86
|
-
async function fetchThreadReplies(token, groupId, channelId, messageId, limit = 50, deadline) {
|
|
87
|
-
return (await require_resolve_allowlist.fetchGraphJson({
|
|
88
|
-
token,
|
|
89
|
-
path: `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}/replies?$top=${Math.min(Math.max(limit, 1), 50)}&$select=id,from,body,createdDateTime`,
|
|
90
|
-
...deadline ? { deadline } : {}
|
|
91
|
-
})).value ?? [];
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Format thread messages into a context string for the agent.
|
|
95
|
-
* Skips the current message (by id) and blank messages.
|
|
96
|
-
*/
|
|
97
|
-
function formatThreadContext(messages, currentMessageId) {
|
|
98
|
-
const lines = [];
|
|
99
|
-
for (const msg of messages) {
|
|
100
|
-
if (msg.id && msg.id === currentMessageId) continue;
|
|
101
|
-
const sender = msg.from?.user?.displayName ?? msg.from?.application?.displayName ?? "unknown";
|
|
102
|
-
const contentType = msg.body?.contentType ?? "text";
|
|
103
|
-
const rawContent = msg.body?.content ?? "";
|
|
104
|
-
const content = contentType === "html" ? stripHtmlFromTeamsMessage(rawContent) : rawContent.trim();
|
|
105
|
-
if (!content) continue;
|
|
106
|
-
lines.push(`${sender}: ${content}`);
|
|
107
|
-
}
|
|
108
|
-
return lines.join("\n");
|
|
109
|
-
}
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region extensions/msteams/src/reaction-types.ts
|
|
112
|
-
const TEAMS_REACTION_EMOJI = {
|
|
113
|
-
like: "👍",
|
|
114
|
-
heart: "❤️",
|
|
115
|
-
laugh: "😆",
|
|
116
|
-
surprised: "😮",
|
|
117
|
-
sad: "😢",
|
|
118
|
-
angry: "😡"
|
|
119
|
-
};
|
|
120
|
-
const TEAMS_REACTION_TYPES = Object.keys(TEAMS_REACTION_EMOJI);
|
|
121
|
-
function getMSTeamsReactionEmoji(raw) {
|
|
122
|
-
return TEAMS_REACTION_EMOJI[raw.trim().toLowerCase()];
|
|
123
|
-
}
|
|
124
|
-
function resolveMSTeamsReactionEmoji(raw) {
|
|
125
|
-
const normalized = raw.trim();
|
|
126
|
-
if (!normalized) throw new Error(`Reaction type is required. Common types: ${TEAMS_REACTION_TYPES.join(", ")}`);
|
|
127
|
-
return getMSTeamsReactionEmoji(normalized) ?? normalized;
|
|
128
|
-
}
|
|
129
|
-
//#endregion
|
|
130
26
|
//#region extensions/msteams/src/file-consent.ts
|
|
131
27
|
/**
|
|
132
28
|
* FileConsentCard utilities for MS Teams large file uploads (>4MB) in personal chats.
|
|
@@ -1323,6 +1219,15 @@ function extractMessageId(response) {
|
|
|
1323
1219
|
return id;
|
|
1324
1220
|
}
|
|
1325
1221
|
//#endregion
|
|
1222
|
+
//#region extensions/msteams/src/ai-entity.ts
|
|
1223
|
+
/** AI-generated content entity added to every outbound AI message. */
|
|
1224
|
+
const AI_GENERATED_ENTITY = {
|
|
1225
|
+
type: "https://schema.org/Message",
|
|
1226
|
+
"@type": "Message",
|
|
1227
|
+
"@id": "",
|
|
1228
|
+
additionalType: ["AIGeneratedContent"]
|
|
1229
|
+
};
|
|
1230
|
+
//#endregion
|
|
1326
1231
|
//#region extensions/msteams/src/mentions.ts
|
|
1327
1232
|
/**
|
|
1328
1233
|
* Check whether an ID looks like a valid Teams user/bot identifier.
|
|
@@ -1376,7 +1281,7 @@ async function withRevokedProxyFallback(params) {
|
|
|
1376
1281
|
try {
|
|
1377
1282
|
return await params.run();
|
|
1378
1283
|
} catch (err) {
|
|
1379
|
-
if (!
|
|
1284
|
+
if (!require_channel_setup.isRevokedProxyError(err)) throw err;
|
|
1380
1285
|
params.onRevokedLog?.();
|
|
1381
1286
|
return await params.onRevoked();
|
|
1382
1287
|
}
|
|
@@ -1384,6 +1289,12 @@ async function withRevokedProxyFallback(params) {
|
|
|
1384
1289
|
//#endregion
|
|
1385
1290
|
//#region extensions/msteams/src/sdk-proactive.ts
|
|
1386
1291
|
const loadMSTeamsApiModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api"));
|
|
1292
|
+
async function quoteMSTeamsActivity(activity, messageId) {
|
|
1293
|
+
const { MessageActivityInput } = await loadMSTeamsApiModule();
|
|
1294
|
+
if (typeof activity === "string") return new MessageActivityInput(activity).prependQuote(messageId);
|
|
1295
|
+
if (activity.type !== "message") return activity;
|
|
1296
|
+
return MessageActivityInput.from(activity).prependQuote(messageId);
|
|
1297
|
+
}
|
|
1387
1298
|
function resolveThreadedConversationId(conversationId, threadActivityId) {
|
|
1388
1299
|
if (!threadActivityId) return conversationId.split(";")[0] ?? conversationId;
|
|
1389
1300
|
return `${conversationId.split(";")[0] ?? conversationId};messageid=${threadActivityId}`;
|
|
@@ -1481,7 +1392,7 @@ function mergeReferenceIntoActivity(activity, ref) {
|
|
|
1481
1392
|
async function sendMSTeamsActivityWithReference(app, source, activity, options) {
|
|
1482
1393
|
const ref = buildSdkConversationReference(source, options);
|
|
1483
1394
|
const activities = (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id);
|
|
1484
|
-
const activityWithRef = mergeReferenceIntoActivity(activity, ref);
|
|
1395
|
+
const activityWithRef = mergeReferenceIntoActivity(options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity, ref);
|
|
1485
1396
|
const isTargeted = activityWithRef.recipient?.isTargeted === true;
|
|
1486
1397
|
if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
|
|
1487
1398
|
const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
|
|
@@ -1507,15 +1418,6 @@ async function deleteMSTeamsActivityWithReference(app, source, activityId, optio
|
|
|
1507
1418
|
return (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id).delete(activityId);
|
|
1508
1419
|
}
|
|
1509
1420
|
//#endregion
|
|
1510
|
-
//#region extensions/msteams/src/ai-entity.ts
|
|
1511
|
-
/** AI-generated content entity added to every outbound AI message. */
|
|
1512
|
-
const AI_GENERATED_ENTITY = {
|
|
1513
|
-
type: "https://schema.org/Message",
|
|
1514
|
-
"@type": "Message",
|
|
1515
|
-
"@id": "",
|
|
1516
|
-
additionalType: ["AIGeneratedContent"]
|
|
1517
|
-
};
|
|
1518
|
-
//#endregion
|
|
1519
1421
|
//#region extensions/msteams/src/messenger.ts
|
|
1520
1422
|
/**
|
|
1521
1423
|
* MSTeams-specific media size limit (100MB).
|
|
@@ -1591,12 +1493,9 @@ function resolveRetryOptions(retry) {
|
|
|
1591
1493
|
};
|
|
1592
1494
|
}
|
|
1593
1495
|
function computeRetryDelayMs(attempt, classification, opts) {
|
|
1594
|
-
if (classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
|
|
1496
|
+
if (classification.kind === "replay-safe" && classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
|
|
1595
1497
|
return clampMs(opts.baseDelayMs * 2 ** Math.max(0, attempt - 1), opts.maxDelayMs);
|
|
1596
1498
|
}
|
|
1597
|
-
function shouldRetry(classification) {
|
|
1598
|
-
return classification.kind === "throttled" || classification.kind === "transient";
|
|
1599
|
-
}
|
|
1600
1499
|
function renderReplyPayloadsToMessages(replies, options) {
|
|
1601
1500
|
const out = [];
|
|
1602
1501
|
const chunkLimit = Math.min(options.textChunkLimit, 4e3);
|
|
@@ -1720,34 +1619,35 @@ async function sendMSTeamsMessages(params) {
|
|
|
1720
1619
|
const retryOptions = resolveRetryOptions(params.retry);
|
|
1721
1620
|
const sendWithRetry = async (sendOnce, meta) => {
|
|
1722
1621
|
if (!retryOptions.enabled) return await sendOnce();
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1622
|
+
return await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(sendOnce, {
|
|
1623
|
+
attempts: retryOptions.maxAttempts,
|
|
1624
|
+
minDelayMs: 0,
|
|
1625
|
+
maxDelayMs: retryOptions.maxDelayMs,
|
|
1626
|
+
shouldRetry: (err) => require_channel_setup.classifyMSTeamsSendError(err).kind === "replay-safe",
|
|
1627
|
+
delayMs: ({ attempt, err }) => computeRetryDelayMs(attempt, require_channel_setup.classifyMSTeamsSendError(err), retryOptions),
|
|
1628
|
+
onRetry: ({ attempt, err, delayMs }) => {
|
|
1629
|
+
params.onRetry?.({
|
|
1630
|
+
messageIndex: meta.messageIndex,
|
|
1631
|
+
messageCount: meta.messageCount,
|
|
1632
|
+
nextAttempt: attempt + 1,
|
|
1633
|
+
maxAttempts: retryOptions.maxAttempts,
|
|
1634
|
+
delayMs,
|
|
1635
|
+
classification: require_channel_setup.classifyMSTeamsSendError(err)
|
|
1636
|
+
});
|
|
1637
|
+
},
|
|
1638
|
+
sleep: (delayMs) => (0, openclaw_plugin_sdk_runtime_env.sleepWithAbort)(delayMs)
|
|
1639
|
+
});
|
|
1741
1640
|
};
|
|
1742
1641
|
let providerDispatchStarted = false;
|
|
1743
1642
|
const sendMessageInContext = async (sendFn, message, messageIndex) => {
|
|
1643
|
+
let activity;
|
|
1744
1644
|
let pendingUploadId;
|
|
1745
1645
|
let response;
|
|
1746
1646
|
try {
|
|
1747
1647
|
response = await sendWithRetry(async () => {
|
|
1748
|
-
|
|
1749
|
-
pendingUploadId
|
|
1750
|
-
|
|
1648
|
+
activity ??= await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, { feedbackLoopEnabled: params.feedbackLoopEnabled });
|
|
1649
|
+
pendingUploadId ??= typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
|
|
1650
|
+
delete activity["_pendingUploadId"];
|
|
1751
1651
|
providerDispatchStarted = true;
|
|
1752
1652
|
return await sendFn(activity);
|
|
1753
1653
|
}, {
|
|
@@ -1846,48 +1746,18 @@ Object.defineProperty(exports, "extractMessageId", {
|
|
|
1846
1746
|
return extractMessageId;
|
|
1847
1747
|
}
|
|
1848
1748
|
});
|
|
1849
|
-
Object.defineProperty(exports, "fetchChannelMessage", {
|
|
1850
|
-
enumerable: true,
|
|
1851
|
-
get: function() {
|
|
1852
|
-
return fetchChannelMessage;
|
|
1853
|
-
}
|
|
1854
|
-
});
|
|
1855
|
-
Object.defineProperty(exports, "fetchChatMessageText", {
|
|
1856
|
-
enumerable: true,
|
|
1857
|
-
get: function() {
|
|
1858
|
-
return fetchChatMessageText;
|
|
1859
|
-
}
|
|
1860
|
-
});
|
|
1861
|
-
Object.defineProperty(exports, "fetchThreadReplies", {
|
|
1862
|
-
enumerable: true,
|
|
1863
|
-
get: function() {
|
|
1864
|
-
return fetchThreadReplies;
|
|
1865
|
-
}
|
|
1866
|
-
});
|
|
1867
1749
|
Object.defineProperty(exports, "formatMSTeamsMarkdown", {
|
|
1868
1750
|
enumerable: true,
|
|
1869
1751
|
get: function() {
|
|
1870
1752
|
return formatMSTeamsMarkdown;
|
|
1871
1753
|
}
|
|
1872
1754
|
});
|
|
1873
|
-
Object.defineProperty(exports, "formatThreadContext", {
|
|
1874
|
-
enumerable: true,
|
|
1875
|
-
get: function() {
|
|
1876
|
-
return formatThreadContext;
|
|
1877
|
-
}
|
|
1878
|
-
});
|
|
1879
1755
|
Object.defineProperty(exports, "getDriveItemProperties", {
|
|
1880
1756
|
enumerable: true,
|
|
1881
1757
|
get: function() {
|
|
1882
1758
|
return getDriveItemProperties;
|
|
1883
1759
|
}
|
|
1884
1760
|
});
|
|
1885
|
-
Object.defineProperty(exports, "getMSTeamsReactionEmoji", {
|
|
1886
|
-
enumerable: true,
|
|
1887
|
-
get: function() {
|
|
1888
|
-
return getMSTeamsReactionEmoji;
|
|
1889
|
-
}
|
|
1890
|
-
});
|
|
1891
1761
|
Object.defineProperty(exports, "getPendingUpload", {
|
|
1892
1762
|
enumerable: true,
|
|
1893
1763
|
get: function() {
|
|
@@ -1942,12 +1812,6 @@ Object.defineProperty(exports, "requiresFileConsent", {
|
|
|
1942
1812
|
return requiresFileConsent;
|
|
1943
1813
|
}
|
|
1944
1814
|
});
|
|
1945
|
-
Object.defineProperty(exports, "resolveMSTeamsReactionEmoji", {
|
|
1946
|
-
enumerable: true,
|
|
1947
|
-
get: function() {
|
|
1948
|
-
return resolveMSTeamsReactionEmoji;
|
|
1949
|
-
}
|
|
1950
|
-
});
|
|
1951
1815
|
Object.defineProperty(exports, "sendMSTeamsActivityWithReference", {
|
|
1952
1816
|
enumerable: true,
|
|
1953
1817
|
get: function() {
|
|
@@ -1972,12 +1836,6 @@ Object.defineProperty(exports, "setPendingUploadActivityIdFs", {
|
|
|
1972
1836
|
return setPendingUploadActivityIdFs;
|
|
1973
1837
|
}
|
|
1974
1838
|
});
|
|
1975
|
-
Object.defineProperty(exports, "stripHtmlFromTeamsMessage", {
|
|
1976
|
-
enumerable: true,
|
|
1977
|
-
get: function() {
|
|
1978
|
-
return stripHtmlFromTeamsMessage;
|
|
1979
|
-
}
|
|
1980
|
-
});
|
|
1981
1839
|
Object.defineProperty(exports, "updateMSTeamsActivityWithReference", {
|
|
1982
1840
|
enumerable: true,
|
|
1983
1841
|
get: function() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
1
|
+
const require_resolve_allowlist = require("./resolve-allowlist-B6FQAa3r.cjs");
|
|
2
|
+
let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
|
|
2
3
|
let openclaw_plugin_sdk_provider_auth = require("openclaw/plugin-sdk/provider-auth");
|
|
3
4
|
let openclaw_plugin_sdk_provider_auth_runtime = require("openclaw/plugin-sdk/provider-auth-runtime");
|
|
4
|
-
let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
|
|
5
5
|
//#region extensions/msteams/src/oauth.flow.ts
|
|
6
6
|
function shouldUseManualOAuthFlow(isRemote) {
|
|
7
7
|
return isRemote || (0, openclaw_plugin_sdk_runtime_env.isWSL2Sync)();
|
package/dist/qa-runner-api.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let openclaw_plugin_sdk_qa_runner_runtime = require("openclaw/plugin-sdk/qa-runner-runtime");
|
|
3
3
|
//#region extensions/msteams/src/qa/cli.ts
|
|
4
4
|
const DEFAULT_MSTEAMS_QA_SCENARIOS = ["channel-canary"];
|
|
5
|
-
const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./adapter.runtime-
|
|
5
|
+
const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./adapter.runtime-8g-MOPfb.cjs")));
|
|
6
6
|
async function runQaMSTeams(options) {
|
|
7
7
|
await (0, openclaw_plugin_sdk_qa_runner_runtime.runLiveTransportQaSuiteCommand)({
|
|
8
8
|
channelId: "msteams",
|