@openclaw/googlechat 2026.5.12-beta.8 → 2026.5.14-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/{accounts-Dt3H6z0l.js → accounts-BlfWEj_G.js} +6 -2
- package/dist/{actions-nBGKFgiH.js → actions-C__ryYKJ.js} +5 -5
- package/dist/{api-DubPSfme.js → api-CBWAN9YL.js} +4 -17
- package/dist/api.js +2 -2
- package/dist/{channel-DoEjIr9p.js → channel-BpW0Eiw7.js} +9 -9
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-DMNTL2NR.js → channel.runtime-CKDAMPpq.js} +69 -6
- package/dist/{runtime-api-CAQFEJsQ.js → runtime-api-DuEfWHnr.js} +2 -2
- package/dist/runtime-api.js +2 -2
- package/dist/setup-plugin-api.js +2 -2
- package/dist/{setup-surface-HU4P5FzD.js → setup-surface-Cr3BORD4.js} +1 -1
- package/dist/{targets-C_U5SbnT.js → targets-AuEcZdcJ.js} +1 -1
- package/dist/test-api.js +2 -2
- package/openclaw.plugin.json +96 -0
- package/package.json +4 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { safeParseJsonWithSchema, safeParseWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
2
2
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, normalizeAccountId, resolveAccountEntry, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
4
|
+
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
4
5
|
import { isSecretRef } from "openclaw/plugin-sdk/secret-input";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
//#region extensions/googlechat/src/accounts.ts
|
|
@@ -14,14 +15,17 @@ function mergeGoogleChatAccountConfig(cfg, accountId) {
|
|
|
14
15
|
channelConfig: raw,
|
|
15
16
|
accounts: raw.accounts,
|
|
16
17
|
accountId,
|
|
17
|
-
omitKeys: ["defaultAccount"]
|
|
18
|
+
omitKeys: ["defaultAccount"],
|
|
19
|
+
nestedObjectKeys: ["botLoopProtection"]
|
|
18
20
|
});
|
|
19
21
|
const defaultAccountConfig = resolveAccountEntry(raw.accounts, DEFAULT_ACCOUNT_ID) ?? {};
|
|
20
22
|
if (accountId === DEFAULT_ACCOUNT_ID) return base;
|
|
21
23
|
const { enabled: _ignoredEnabled, dangerouslyAllowNameMatching: _ignoredDangerouslyAllowNameMatching, serviceAccount: _ignoredServiceAccount, serviceAccountRef: _ignoredServiceAccountRef, serviceAccountFile: _ignoredServiceAccountFile, ...defaultAccountShared } = defaultAccountConfig;
|
|
24
|
+
const botLoopProtection = mergePairLoopGuardConfig(defaultAccountShared.botLoopProtection, base.botLoopProtection);
|
|
22
25
|
return {
|
|
23
26
|
...defaultAccountShared,
|
|
24
|
-
...base
|
|
27
|
+
...base,
|
|
28
|
+
...botLoopProtection ? { botLoopProtection } : {}
|
|
25
29
|
};
|
|
26
30
|
}
|
|
27
31
|
function resolveGoogleChatConfigAccessorAccount(params) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as resolveGoogleChatAccount, t as listEnabledGoogleChatAccounts } from "./accounts-
|
|
2
|
-
import { P as getGoogleChatRuntime } from "./runtime-api-
|
|
3
|
-
import { c as sendGoogleChatMessage, o as listGoogleChatReactions, r as deleteGoogleChatReaction, t as createGoogleChatReaction, u as uploadGoogleChatAttachment } from "./api-
|
|
4
|
-
import { i as resolveGoogleChatOutboundSpace } from "./targets-
|
|
1
|
+
import { i as resolveGoogleChatAccount, t as listEnabledGoogleChatAccounts } from "./accounts-BlfWEj_G.js";
|
|
2
|
+
import { P as getGoogleChatRuntime } from "./runtime-api-DuEfWHnr.js";
|
|
3
|
+
import { c as sendGoogleChatMessage, o as listGoogleChatReactions, r as deleteGoogleChatReaction, t as createGoogleChatReaction, u as uploadGoogleChatAttachment } from "./api-CBWAN9YL.js";
|
|
4
|
+
import { i as resolveGoogleChatOutboundSpace } from "./targets-AuEcZdcJ.js";
|
|
5
5
|
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
6
6
|
import { createActionGate, jsonResult, readNumberParam, readReactionParams, readStringParam } from "openclaw/plugin-sdk/channel-actions";
|
|
7
7
|
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
@@ -19,7 +19,7 @@ function resolveAppUserNames(account) {
|
|
|
19
19
|
}
|
|
20
20
|
async function loadGoogleChatActionMedia(params) {
|
|
21
21
|
const runtime = getGoogleChatRuntime();
|
|
22
|
-
return /^https?:\/\//i.test(params.mediaUrl) ? await runtime.channel.media.
|
|
22
|
+
return /^https?:\/\//i.test(params.mediaUrl) ? await runtime.channel.media.readRemoteMediaBuffer({
|
|
23
23
|
url: params.mediaUrl,
|
|
24
24
|
maxBytes: params.maxBytes
|
|
25
25
|
}) : await loadOutboundMediaFromUrl(params.mediaUrl, {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { p as fetchWithSsrFGuard$1 } from "./runtime-api-DuEfWHnr.js";
|
|
2
2
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import crypto from "node:crypto";
|
|
4
4
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
5
|
+
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
5
6
|
import { buildHostnameAllowlistPolicyFromSuffixAllowlist, fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
6
7
|
import fs from "node:fs/promises";
|
|
7
8
|
import { resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
@@ -513,26 +514,12 @@ async function fetchBuffer(account, url, init, options) {
|
|
|
513
514
|
const length = Number(lengthHeader);
|
|
514
515
|
if (Number.isFinite(length) && length > maxBytes) throw new Error(`Google Chat media exceeds max bytes (${maxBytes})`);
|
|
515
516
|
}
|
|
516
|
-
if (!maxBytes
|
|
517
|
+
if (!maxBytes) return {
|
|
517
518
|
buffer: Buffer.from(await res.arrayBuffer()),
|
|
518
519
|
contentType: res.headers.get("content-type") ?? void 0
|
|
519
520
|
};
|
|
520
|
-
const reader = res.body.getReader();
|
|
521
|
-
const chunks = [];
|
|
522
|
-
let total = 0;
|
|
523
|
-
while (true) {
|
|
524
|
-
const { done, value } = await reader.read();
|
|
525
|
-
if (done) break;
|
|
526
|
-
if (!value) continue;
|
|
527
|
-
total += value.length;
|
|
528
|
-
if (total > maxBytes) {
|
|
529
|
-
await reader.cancel();
|
|
530
|
-
throw new Error(`Google Chat media exceeds max bytes (${maxBytes})`);
|
|
531
|
-
}
|
|
532
|
-
chunks.push(Buffer.from(value));
|
|
533
|
-
}
|
|
534
521
|
return {
|
|
535
|
-
buffer:
|
|
522
|
+
buffer: await readResponseWithLimit(res, maxBytes, { onOverflow: () => /* @__PURE__ */ new Error(`Google Chat media exceeds max bytes (${maxBytes})`) }),
|
|
536
523
|
contentType: res.headers.get("content-type") ?? void 0
|
|
537
524
|
};
|
|
538
525
|
}
|
package/dist/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as googlechatPlugin } from "./channel-
|
|
2
|
-
import { n as googlechatSetupAdapter, t as googlechatSetupWizard } from "./setup-surface-
|
|
1
|
+
import { t as googlechatPlugin } from "./channel-BpW0Eiw7.js";
|
|
2
|
+
import { n as googlechatSetupAdapter, t as googlechatSetupWizard } from "./setup-surface-Cr3BORD4.js";
|
|
3
3
|
export { googlechatPlugin, googlechatSetupAdapter, googlechatSetupWizard };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as resolveGoogleChatConfigAccessorAccount, i as resolveGoogleChatAccount, n as listGoogleChatAccountIds, r as resolveDefaultGoogleChatAccountId } from "./accounts-
|
|
2
|
-
import { T as resolveChannelMediaMaxBytes, _ as
|
|
3
|
-
import { i as resolveGoogleChatOutboundSpace, n as isGoogleChatUserTarget, r as normalizeGoogleChatTarget, t as isGoogleChatSpaceTarget } from "./targets-
|
|
1
|
+
import { a as resolveGoogleChatConfigAccessorAccount, i as resolveGoogleChatAccount, n as listGoogleChatAccountIds, r as resolveDefaultGoogleChatAccountId } from "./accounts-BlfWEj_G.js";
|
|
2
|
+
import { T as resolveChannelMediaMaxBytes, _ as missingTargetError, a as buildChannelConfigSchema, g as loadOutboundMediaFromUrl, i as PAIRING_APPROVED_MESSAGE, o as chunkTextForOutbound, r as GoogleChatConfigSchema, t as DEFAULT_ACCOUNT_ID, x as readRemoteMediaBuffer } from "./runtime-api-DuEfWHnr.js";
|
|
3
|
+
import { i as resolveGoogleChatOutboundSpace, n as isGoogleChatUserTarget, r as normalizeGoogleChatTarget, t as isGoogleChatSpaceTarget } from "./targets-AuEcZdcJ.js";
|
|
4
4
|
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BsERSjSe.js";
|
|
5
5
|
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DLAG2_NI.js";
|
|
6
|
-
import { n as googlechatSetupAdapter, t as googlechatSetupWizard } from "./setup-surface-
|
|
6
|
+
import { n as googlechatSetupAdapter, t as googlechatSetupWizard } from "./setup-surface-Cr3BORD4.js";
|
|
7
7
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
8
8
|
import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
|
|
9
9
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
@@ -54,7 +54,7 @@ function resolveGoogleChatGroupRequireMention(params) {
|
|
|
54
54
|
}
|
|
55
55
|
//#endregion
|
|
56
56
|
//#region extensions/googlechat/src/channel.adapters.ts
|
|
57
|
-
const loadGoogleChatChannelRuntime$2 = createLazyRuntimeNamedExport(() => import("./channel.runtime-
|
|
57
|
+
const loadGoogleChatChannelRuntime$2 = createLazyRuntimeNamedExport(() => import("./channel.runtime-CKDAMPpq.js"), "googleChatChannelRuntime");
|
|
58
58
|
function createGoogleChatSendReceipt(params) {
|
|
59
59
|
const messageId = params.messageId?.trim();
|
|
60
60
|
return createMessageReceiptFromOutboundResults({
|
|
@@ -204,7 +204,7 @@ const googlechatOutboundAdapter = {
|
|
|
204
204
|
resolveChannelLimitMb: ({ cfg, accountId }) => (cfg.channels?.googlechat)?.accounts?.[accountId]?.mediaMaxMb ?? (cfg.channels?.googlechat)?.mediaMaxMb,
|
|
205
205
|
accountId
|
|
206
206
|
}) ?? (account.config.mediaMaxMb ?? 20) * 1024 * 1024;
|
|
207
|
-
const loaded = /^https?:\/\//i.test(mediaUrl) ? await
|
|
207
|
+
const loaded = /^https?:\/\//i.test(mediaUrl) ? await readRemoteMediaBuffer({
|
|
208
208
|
url: mediaUrl,
|
|
209
209
|
maxBytes: effectiveMaxBytes
|
|
210
210
|
}) : await loadOutboundMediaFromUrl(mediaUrl, {
|
|
@@ -295,7 +295,7 @@ const collectGoogleChatMutableAllowlistWarnings = createDangerousNameMatchingMut
|
|
|
295
295
|
});
|
|
296
296
|
//#endregion
|
|
297
297
|
//#region extensions/googlechat/src/gateway.ts
|
|
298
|
-
const loadGoogleChatChannelRuntime$1 = createLazyRuntimeNamedExport(() => import("./channel.runtime-
|
|
298
|
+
const loadGoogleChatChannelRuntime$1 = createLazyRuntimeNamedExport(() => import("./channel.runtime-CKDAMPpq.js"), "googleChatChannelRuntime");
|
|
299
299
|
async function startGoogleChatGatewayAccount(ctx) {
|
|
300
300
|
const account = ctx.account;
|
|
301
301
|
const statusSink = createAccountStatusSink({
|
|
@@ -335,7 +335,7 @@ async function startGoogleChatGatewayAccount(ctx) {
|
|
|
335
335
|
}
|
|
336
336
|
//#endregion
|
|
337
337
|
//#region extensions/googlechat/src/channel.ts
|
|
338
|
-
const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-
|
|
338
|
+
const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-CKDAMPpq.js"), "googleChatChannelRuntime");
|
|
339
339
|
const meta = {
|
|
340
340
|
id: "googlechat",
|
|
341
341
|
label: "Google Chat",
|
|
@@ -391,7 +391,7 @@ const googlechatActions = {
|
|
|
391
391
|
},
|
|
392
392
|
extractToolSend: ({ args }) => extractToolSend(args, "sendMessage"),
|
|
393
393
|
handleAction: async (ctx) => {
|
|
394
|
-
const { googlechatMessageActions } = await import("./actions-
|
|
394
|
+
const { googlechatMessageActions } = await import("./actions-C__ryYKJ.js");
|
|
395
395
|
if (!googlechatMessageActions.handleAction) throw new Error("Google Chat actions are not available.");
|
|
396
396
|
return await googlechatMessageActions.handleAction(ctx);
|
|
397
397
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as googlechatPlugin } from "./channel-
|
|
1
|
+
import { t as googlechatPlugin } from "./channel-BpW0Eiw7.js";
|
|
2
2
|
export { googlechatPlugin };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { E as resolveDefaultGroupPolicy, M as warnMissingProviderGroupPolicyFallbackOnce, O as resolveInboundRouteEnvelopeBuilderWithRuntime, P as getGoogleChatRuntime,
|
|
2
|
-
import { c as sendGoogleChatMessage, d as verifyGoogleChatRequest, i as downloadGoogleChatMedia, l as updateGoogleChatMessage, n as deleteGoogleChatMessage, s as probeGoogleChat, u as uploadGoogleChatAttachment } from "./api-
|
|
1
|
+
import { E as resolveDefaultGroupPolicy, M as warnMissingProviderGroupPolicyFallbackOnce, O as resolveInboundRouteEnvelopeBuilderWithRuntime, P as getGoogleChatRuntime, k as resolveWebhookPath, m as isDangerousNameMatchingEnabled, n as GROUP_POLICY_BLOCKED_LABEL, u as createChannelPairingController, w as resolveAllowlistProviderRuntimeGroupPolicy } from "./runtime-api-DuEfWHnr.js";
|
|
2
|
+
import { c as sendGoogleChatMessage, d as verifyGoogleChatRequest, i as downloadGoogleChatMedia, l as updateGoogleChatMessage, n as deleteGoogleChatMessage, s as probeGoogleChat, u as uploadGoogleChatAttachment } from "./api-CBWAN9YL.js";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
|
+
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
5
|
+
import { WEBHOOK_RATE_LIMIT_DEFAULTS, createFixedWindowRateLimiter, normalizeWebhookPath, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
|
|
4
6
|
import { registerWebhookTargetWithPluginRoute, resolveWebhookTargetWithAuthOrReject, withResolvedWebhookRequestPipeline } from "openclaw/plugin-sdk/webhook-targets";
|
|
5
7
|
import { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
8
|
+
import { recordChannelBotPairLoopAndCheckSuppression } from "openclaw/plugin-sdk/inbound-reply-dispatch";
|
|
6
9
|
import { channelIngressRoutes, createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
7
10
|
import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
8
11
|
//#region extensions/googlechat/src/monitor-access.ts
|
|
@@ -277,6 +280,7 @@ async function applyGoogleChatInboundAccessPolicy(params) {
|
|
|
277
280
|
ok: true,
|
|
278
281
|
commandAuthorized,
|
|
279
282
|
effectiveWasMentioned,
|
|
283
|
+
groupBotLoopProtection: groupEntry?.botLoopProtection,
|
|
280
284
|
groupSystemPrompt: normalizeOptionalString(groupEntry?.systemPrompt)
|
|
281
285
|
};
|
|
282
286
|
}
|
|
@@ -368,7 +372,7 @@ async function deliverGoogleChatReply(params) {
|
|
|
368
372
|
},
|
|
369
373
|
sendMedia: async ({ mediaUrl, caption }) => {
|
|
370
374
|
try {
|
|
371
|
-
const loaded = await core.channel.media.
|
|
375
|
+
const loaded = await core.channel.media.readRemoteMediaBuffer({
|
|
372
376
|
url: mediaUrl,
|
|
373
377
|
maxBytes: (account.config.mediaMaxMb ?? 20) * 1024 * 1024
|
|
374
378
|
});
|
|
@@ -512,12 +516,17 @@ function warnAppPrincipalMisconfiguration(params) {
|
|
|
512
516
|
}
|
|
513
517
|
function createGoogleChatWebhookRequestHandler(params) {
|
|
514
518
|
return async (req, res) => {
|
|
519
|
+
const path = normalizeWebhookPath(new URL(req.url ?? "/", "http://localhost").pathname);
|
|
520
|
+
const config = params.webhookTargets.get(path)?.[0]?.config;
|
|
521
|
+
const clientIp = resolveRequestClientIp(req, config?.gateway?.trustedProxies, config?.gateway?.allowRealIpFallback === true) ?? "unknown";
|
|
515
522
|
return await withResolvedWebhookRequestPipeline({
|
|
516
523
|
req,
|
|
517
524
|
res,
|
|
518
525
|
targetsByPath: params.webhookTargets,
|
|
519
526
|
allowMethods: ["POST"],
|
|
520
527
|
requireJsonContentType: true,
|
|
528
|
+
rateLimiter: params.webhookRateLimiter,
|
|
529
|
+
rateLimitKey: `${path}:${clientIp}`,
|
|
521
530
|
inFlightLimiter: params.webhookInFlightLimiter,
|
|
522
531
|
handle: async ({ targets }) => {
|
|
523
532
|
const headerBearer = extractBearerToken(req.headers.authorization);
|
|
@@ -587,6 +596,11 @@ function createGoogleChatWebhookRequestHandler(params) {
|
|
|
587
596
|
//#endregion
|
|
588
597
|
//#region extensions/googlechat/src/monitor-routing.ts
|
|
589
598
|
const webhookTargets = /* @__PURE__ */ new Map();
|
|
599
|
+
const webhookRateLimiter = createFixedWindowRateLimiter({
|
|
600
|
+
windowMs: WEBHOOK_RATE_LIMIT_DEFAULTS.windowMs,
|
|
601
|
+
maxRequests: WEBHOOK_RATE_LIMIT_DEFAULTS.maxRequests,
|
|
602
|
+
maxTrackedKeys: WEBHOOK_RATE_LIMIT_DEFAULTS.maxTrackedKeys
|
|
603
|
+
});
|
|
590
604
|
const webhookInFlightLimiter = createWebhookInFlightLimiter();
|
|
591
605
|
let processGoogleChatEvent$1 = async () => {};
|
|
592
606
|
function setGoogleChatWebhookEventProcessor(processEvent) {
|
|
@@ -594,6 +608,7 @@ function setGoogleChatWebhookEventProcessor(processEvent) {
|
|
|
594
608
|
}
|
|
595
609
|
const googleChatWebhookRequestHandler = createGoogleChatWebhookRequestHandler({
|
|
596
610
|
webhookTargets,
|
|
611
|
+
webhookRateLimiter,
|
|
597
612
|
webhookInFlightLimiter,
|
|
598
613
|
processEvent: async (event, target) => {
|
|
599
614
|
await processGoogleChatEvent$1(event, target);
|
|
@@ -634,6 +649,33 @@ function normalizeAudienceType(value) {
|
|
|
634
649
|
if (normalized === "app-url" || normalized === "app_url" || normalized === "app") return "app-url";
|
|
635
650
|
if (normalized === "project-number" || normalized === "project_number" || normalized === "project") return "project-number";
|
|
636
651
|
}
|
|
652
|
+
function resolveGoogleChatTimestampMs(eventTime) {
|
|
653
|
+
if (!eventTime) return;
|
|
654
|
+
const parsed = Date.parse(eventTime);
|
|
655
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
656
|
+
}
|
|
657
|
+
function resolveGoogleChatBotLoopProtection(params) {
|
|
658
|
+
if (!params.allowBots || !params.isBotSender || !params.senderId || params.senderId === params.appUserId) return;
|
|
659
|
+
return {
|
|
660
|
+
scopeId: params.accountId,
|
|
661
|
+
conversationId: params.conversationId,
|
|
662
|
+
senderId: params.senderId,
|
|
663
|
+
receiverId: params.appUserId,
|
|
664
|
+
config: params.config,
|
|
665
|
+
defaultsConfig: params.defaultsConfig,
|
|
666
|
+
defaultEnabled: true,
|
|
667
|
+
nowMs: resolveGoogleChatTimestampMs(params.eventTime)
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function resolveGoogleChatBotLoopProtectionConfig(params) {
|
|
671
|
+
return mergePairLoopGuardConfig(params.accountConfig, params.groupConfig);
|
|
672
|
+
}
|
|
673
|
+
function shouldSuppressGoogleChatBotLoop(params) {
|
|
674
|
+
if (!params.botLoopProtection) return false;
|
|
675
|
+
if (!recordChannelBotPairLoopAndCheckSuppression(params.botLoopProtection).suppressed) return false;
|
|
676
|
+
logVerbose(params.core, params.runtime, `skip bot-to-bot loop in ${params.botLoopProtection.conversationId}`);
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
637
679
|
async function processGoogleChatEvent(event, target) {
|
|
638
680
|
if ((event.type ?? event.eventType) !== "MESSAGE") return;
|
|
639
681
|
if (!event.message || !event.space) return;
|
|
@@ -672,8 +714,11 @@ async function processMessageWithPipeline(params) {
|
|
|
672
714
|
const senderId = sender?.name ?? "";
|
|
673
715
|
const senderName = sender?.displayName ?? "";
|
|
674
716
|
const senderEmail = sender?.email ?? void 0;
|
|
675
|
-
|
|
676
|
-
|
|
717
|
+
const isBotSender = sender?.type?.toUpperCase() === "BOT";
|
|
718
|
+
const appUserId = account.config.botUser?.trim() || "users/app";
|
|
719
|
+
const allowBots = account.config.allowBots === true;
|
|
720
|
+
if (!allowBots) {
|
|
721
|
+
if (isBotSender) {
|
|
677
722
|
logVerbose(core, runtime, `skip bot-authored message (${senderId || "unknown"})`);
|
|
678
723
|
return;
|
|
679
724
|
}
|
|
@@ -702,7 +747,25 @@ async function processMessageWithPipeline(params) {
|
|
|
702
747
|
logVerbose: (message) => logVerbose(core, runtime, message)
|
|
703
748
|
});
|
|
704
749
|
if (!access.ok) return;
|
|
705
|
-
const { commandAuthorized, effectiveWasMentioned, groupSystemPrompt } = access;
|
|
750
|
+
const { commandAuthorized, effectiveWasMentioned, groupBotLoopProtection, groupSystemPrompt } = access;
|
|
751
|
+
if (shouldSuppressGoogleChatBotLoop({
|
|
752
|
+
botLoopProtection: resolveGoogleChatBotLoopProtection({
|
|
753
|
+
allowBots,
|
|
754
|
+
isBotSender,
|
|
755
|
+
senderId,
|
|
756
|
+
appUserId,
|
|
757
|
+
accountId: account.accountId,
|
|
758
|
+
conversationId: spaceId,
|
|
759
|
+
config: resolveGoogleChatBotLoopProtectionConfig({
|
|
760
|
+
accountConfig: account.config.botLoopProtection,
|
|
761
|
+
groupConfig: groupBotLoopProtection
|
|
762
|
+
}),
|
|
763
|
+
defaultsConfig: config.channels?.defaults?.botLoopProtection,
|
|
764
|
+
eventTime: event.eventTime
|
|
765
|
+
}),
|
|
766
|
+
core,
|
|
767
|
+
runtime
|
|
768
|
+
})) return;
|
|
706
769
|
const { route, buildEnvelope } = resolveInboundRouteEnvelopeBuilderWithRuntime({
|
|
707
770
|
cfg: config,
|
|
708
771
|
channel: "googlechat",
|
|
@@ -12,7 +12,7 @@ import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
|
12
12
|
import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
|
|
13
13
|
import { GROUP_POLICY_BLOCKED_LABEL, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
14
14
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
15
|
-
import {
|
|
15
|
+
import { readRemoteMediaBuffer, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
16
16
|
import { loadOutboundMediaFromUrl as loadOutboundMediaFromUrl$1 } from "openclaw/plugin-sdk/outbound-media";
|
|
17
17
|
import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
|
|
18
18
|
import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
|
|
@@ -26,4 +26,4 @@ const { setRuntime: setGoogleChatRuntime, getRuntime: getGoogleChatRuntime } = c
|
|
|
26
26
|
errorMessage: "Google Chat runtime not initialized"
|
|
27
27
|
});
|
|
28
28
|
//#endregion
|
|
29
|
-
export { resolveWebhookTargetWithAuthOrReject$1 as A, registerWebhookTargetWithPluginRoute$1 as C, resolveInboundMentionDecision as D, resolveDefaultGroupPolicy as E, setGoogleChatRuntime as F, warnMissingProviderGroupPolicyFallbackOnce as M, withResolvedWebhookRequestPipeline$1 as N, resolveInboundRouteEnvelopeBuilderWithRuntime as O, getGoogleChatRuntime as P, readStringParam$1 as S, resolveChannelMediaMaxBytes as T,
|
|
29
|
+
export { resolveWebhookTargetWithAuthOrReject$1 as A, registerWebhookTargetWithPluginRoute$1 as C, resolveInboundMentionDecision as D, resolveDefaultGroupPolicy as E, setGoogleChatRuntime as F, warnMissingProviderGroupPolicyFallbackOnce as M, withResolvedWebhookRequestPipeline$1 as N, resolveInboundRouteEnvelopeBuilderWithRuntime as O, getGoogleChatRuntime as P, readStringParam$1 as S, resolveChannelMediaMaxBytes as T, missingTargetError as _, buildChannelConfigSchema as a, readReactionParams$1 as b, createActionGate$1 as c, createWebhookInFlightLimiter$1 as d, extractToolSend$1 as f, loadOutboundMediaFromUrl$1 as g, jsonResult$1 as h, PAIRING_APPROVED_MESSAGE as i, runPassiveAccountLifecycle$1 as j, resolveWebhookPath as k, createChannelMessageReplyPipeline as l, isDangerousNameMatchingEnabled as m, GROUP_POLICY_BLOCKED_LABEL as n, chunkTextForOutbound as o, fetchWithSsrFGuard$1 as p, GoogleChatConfigSchema as r, createAccountStatusSink$1 as s, DEFAULT_ACCOUNT_ID as t, createChannelPairingController as u, readJsonWebhookBodyOrReject$1 as v, resolveAllowlistProviderRuntimeGroupPolicy as w, readRemoteMediaBuffer as x, readNumberParam$1 as y };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as resolveWebhookTargetWithAuthOrReject, C as registerWebhookTargetWithPluginRoute, D as resolveInboundMentionDecision, E as resolveDefaultGroupPolicy, F as setGoogleChatRuntime, M as warnMissingProviderGroupPolicyFallbackOnce, N as withResolvedWebhookRequestPipeline, O as resolveInboundRouteEnvelopeBuilderWithRuntime, S as readStringParam, T as resolveChannelMediaMaxBytes, _ as
|
|
2
|
-
export { DEFAULT_ACCOUNT_ID, GROUP_POLICY_BLOCKED_LABEL, GoogleChatConfigSchema, PAIRING_APPROVED_MESSAGE, buildChannelConfigSchema, chunkTextForOutbound, createAccountStatusSink, createActionGate, createChannelMessageReplyPipeline, createChannelPairingController, createWebhookInFlightLimiter, extractToolSend,
|
|
1
|
+
import { A as resolveWebhookTargetWithAuthOrReject, C as registerWebhookTargetWithPluginRoute, D as resolveInboundMentionDecision, E as resolveDefaultGroupPolicy, F as setGoogleChatRuntime, M as warnMissingProviderGroupPolicyFallbackOnce, N as withResolvedWebhookRequestPipeline, O as resolveInboundRouteEnvelopeBuilderWithRuntime, S as readStringParam, T as resolveChannelMediaMaxBytes, _ as missingTargetError, a as buildChannelConfigSchema, b as readReactionParams, c as createActionGate, d as createWebhookInFlightLimiter, f as extractToolSend, g as loadOutboundMediaFromUrl, h as jsonResult, i as PAIRING_APPROVED_MESSAGE, j as runPassiveAccountLifecycle, k as resolveWebhookPath, l as createChannelMessageReplyPipeline, m as isDangerousNameMatchingEnabled, n as GROUP_POLICY_BLOCKED_LABEL, o as chunkTextForOutbound, p as fetchWithSsrFGuard, r as GoogleChatConfigSchema, s as createAccountStatusSink, t as DEFAULT_ACCOUNT_ID, u as createChannelPairingController, v as readJsonWebhookBodyOrReject, w as resolveAllowlistProviderRuntimeGroupPolicy, x as readRemoteMediaBuffer, y as readNumberParam } from "./runtime-api-DuEfWHnr.js";
|
|
2
|
+
export { DEFAULT_ACCOUNT_ID, GROUP_POLICY_BLOCKED_LABEL, GoogleChatConfigSchema, PAIRING_APPROVED_MESSAGE, buildChannelConfigSchema, chunkTextForOutbound, createAccountStatusSink, createActionGate, createChannelMessageReplyPipeline, createChannelPairingController, createWebhookInFlightLimiter, extractToolSend, fetchWithSsrFGuard, isDangerousNameMatchingEnabled, jsonResult, loadOutboundMediaFromUrl, missingTargetError, readJsonWebhookBodyOrReject, readNumberParam, readReactionParams, readRemoteMediaBuffer, readStringParam, registerWebhookTargetWithPluginRoute, resolveAllowlistProviderRuntimeGroupPolicy, resolveChannelMediaMaxBytes, resolveDefaultGroupPolicy, resolveInboundMentionDecision, resolveInboundRouteEnvelopeBuilderWithRuntime, resolveWebhookPath, resolveWebhookTargetWithAuthOrReject, runPassiveAccountLifecycle, setGoogleChatRuntime, warnMissingProviderGroupPolicyFallbackOnce, withResolvedWebhookRequestPipeline };
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as resolveGoogleChatConfigAccessorAccount, i as resolveGoogleChatAccount, n as listGoogleChatAccountIds, r as resolveDefaultGoogleChatAccountId } from "./accounts-
|
|
2
|
-
import { n as googlechatSetupAdapter, t as googlechatSetupWizard } from "./setup-surface-
|
|
1
|
+
import { a as resolveGoogleChatConfigAccessorAccount, i as resolveGoogleChatAccount, n as listGoogleChatAccountIds, r as resolveDefaultGoogleChatAccountId } from "./accounts-BlfWEj_G.js";
|
|
2
|
+
import { n as googlechatSetupAdapter, t as googlechatSetupWizard } from "./setup-surface-Cr3BORD4.js";
|
|
3
3
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
4
4
|
import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
|
|
5
5
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as resolveGoogleChatAccount, r as resolveDefaultGoogleChatAccountId } from "./accounts-
|
|
1
|
+
import { i as resolveGoogleChatAccount, r as resolveDefaultGoogleChatAccountId } from "./accounts-BlfWEj_G.js";
|
|
2
2
|
import { normalizeOptionalString, normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import { createPatchedAccountSetupAdapter, createSetupInputPresenceValidator } from "openclaw/plugin-sdk/setup-runtime";
|
|
4
4
|
import { DEFAULT_ACCOUNT_ID, addWildcardAllowFrom, applySetupAccountConfigPatch, createPromptParsedAllowFromForAccount, createStandardChannelSetupStatus, formatDocsLink, mergeAllowFromEntries, migrateBaseNameToDefaultAccount, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as findGoogleChatDirectMessage } from "./api-
|
|
1
|
+
import { a as findGoogleChatDirectMessage } from "./api-CBWAN9YL.js";
|
|
2
2
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
//#region extensions/googlechat/src/targets.ts
|
|
4
4
|
function normalizeGoogleChatTarget(raw) {
|
package/dist/test-api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { F as setGoogleChatRuntime } from "./runtime-api-
|
|
2
|
-
import { t as googlechatPlugin } from "./channel-
|
|
1
|
+
import { F as setGoogleChatRuntime } from "./runtime-api-DuEfWHnr.js";
|
|
2
|
+
import { t as googlechatPlugin } from "./channel-BpW0Eiw7.js";
|
|
3
3
|
export { googlechatPlugin, setGoogleChatRuntime };
|
package/openclaw.plugin.json
CHANGED
|
@@ -41,6 +41,30 @@
|
|
|
41
41
|
"allowBots": {
|
|
42
42
|
"type": "boolean"
|
|
43
43
|
},
|
|
44
|
+
"botLoopProtection": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"enabled": {
|
|
48
|
+
"type": "boolean"
|
|
49
|
+
},
|
|
50
|
+
"maxEventsPerWindow": {
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"exclusiveMinimum": 0,
|
|
53
|
+
"maximum": 9007199254740991
|
|
54
|
+
},
|
|
55
|
+
"windowSeconds": {
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"exclusiveMinimum": 0,
|
|
58
|
+
"maximum": 9007199254740991
|
|
59
|
+
},
|
|
60
|
+
"cooldownSeconds": {
|
|
61
|
+
"type": "integer",
|
|
62
|
+
"exclusiveMinimum": 0,
|
|
63
|
+
"maximum": 9007199254740991
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"additionalProperties": false
|
|
67
|
+
},
|
|
44
68
|
"dangerouslyAllowNameMatching": {
|
|
45
69
|
"type": "boolean"
|
|
46
70
|
},
|
|
@@ -83,6 +107,30 @@
|
|
|
83
107
|
"requireMention": {
|
|
84
108
|
"type": "boolean"
|
|
85
109
|
},
|
|
110
|
+
"botLoopProtection": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"properties": {
|
|
113
|
+
"enabled": {
|
|
114
|
+
"type": "boolean"
|
|
115
|
+
},
|
|
116
|
+
"maxEventsPerWindow": {
|
|
117
|
+
"type": "integer",
|
|
118
|
+
"exclusiveMinimum": 0,
|
|
119
|
+
"maximum": 9007199254740991
|
|
120
|
+
},
|
|
121
|
+
"windowSeconds": {
|
|
122
|
+
"type": "integer",
|
|
123
|
+
"exclusiveMinimum": 0,
|
|
124
|
+
"maximum": 9007199254740991
|
|
125
|
+
},
|
|
126
|
+
"cooldownSeconds": {
|
|
127
|
+
"type": "integer",
|
|
128
|
+
"exclusiveMinimum": 0,
|
|
129
|
+
"maximum": 9007199254740991
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"additionalProperties": false
|
|
133
|
+
},
|
|
86
134
|
"users": {
|
|
87
135
|
"type": "array",
|
|
88
136
|
"items": {
|
|
@@ -464,6 +512,30 @@
|
|
|
464
512
|
"allowBots": {
|
|
465
513
|
"type": "boolean"
|
|
466
514
|
},
|
|
515
|
+
"botLoopProtection": {
|
|
516
|
+
"type": "object",
|
|
517
|
+
"properties": {
|
|
518
|
+
"enabled": {
|
|
519
|
+
"type": "boolean"
|
|
520
|
+
},
|
|
521
|
+
"maxEventsPerWindow": {
|
|
522
|
+
"type": "integer",
|
|
523
|
+
"exclusiveMinimum": 0,
|
|
524
|
+
"maximum": 9007199254740991
|
|
525
|
+
},
|
|
526
|
+
"windowSeconds": {
|
|
527
|
+
"type": "integer",
|
|
528
|
+
"exclusiveMinimum": 0,
|
|
529
|
+
"maximum": 9007199254740991
|
|
530
|
+
},
|
|
531
|
+
"cooldownSeconds": {
|
|
532
|
+
"type": "integer",
|
|
533
|
+
"exclusiveMinimum": 0,
|
|
534
|
+
"maximum": 9007199254740991
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
"additionalProperties": false
|
|
538
|
+
},
|
|
467
539
|
"dangerouslyAllowNameMatching": {
|
|
468
540
|
"type": "boolean"
|
|
469
541
|
},
|
|
@@ -506,6 +578,30 @@
|
|
|
506
578
|
"requireMention": {
|
|
507
579
|
"type": "boolean"
|
|
508
580
|
},
|
|
581
|
+
"botLoopProtection": {
|
|
582
|
+
"type": "object",
|
|
583
|
+
"properties": {
|
|
584
|
+
"enabled": {
|
|
585
|
+
"type": "boolean"
|
|
586
|
+
},
|
|
587
|
+
"maxEventsPerWindow": {
|
|
588
|
+
"type": "integer",
|
|
589
|
+
"exclusiveMinimum": 0,
|
|
590
|
+
"maximum": 9007199254740991
|
|
591
|
+
},
|
|
592
|
+
"windowSeconds": {
|
|
593
|
+
"type": "integer",
|
|
594
|
+
"exclusiveMinimum": 0,
|
|
595
|
+
"maximum": 9007199254740991
|
|
596
|
+
},
|
|
597
|
+
"cooldownSeconds": {
|
|
598
|
+
"type": "integer",
|
|
599
|
+
"exclusiveMinimum": 0,
|
|
600
|
+
"maximum": 9007199254740991
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
"additionalProperties": false
|
|
604
|
+
},
|
|
509
605
|
"users": {
|
|
510
606
|
"type": "array",
|
|
511
607
|
"items": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/googlechat",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.14-beta.1",
|
|
4
4
|
"description": "OpenClaw Google Chat channel plugin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"openclaw": "workspace:*"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"openclaw": ">=2026.5.
|
|
20
|
+
"openclaw": ">=2026.5.14-beta.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependenciesMeta": {
|
|
23
23
|
"openclaw": {
|
|
@@ -75,10 +75,10 @@
|
|
|
75
75
|
"minHostVersion": ">=2026.4.10"
|
|
76
76
|
},
|
|
77
77
|
"compat": {
|
|
78
|
-
"pluginApi": ">=2026.5.
|
|
78
|
+
"pluginApi": ">=2026.5.14-beta.1"
|
|
79
79
|
},
|
|
80
80
|
"build": {
|
|
81
|
-
"openclawVersion": "2026.5.
|
|
81
|
+
"openclawVersion": "2026.5.14-beta.1"
|
|
82
82
|
},
|
|
83
83
|
"release": {
|
|
84
84
|
"publishToClawHub": true,
|