@openclaw/googlechat 2026.7.1 → 2026.7.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions-B4nbMjmi.js +76 -0
- package/dist/api.js +2 -2
- package/dist/approval-auth-B2m8ckdj.js +30 -0
- package/dist/{approval-handler.runtime-BnkufknT.js → approval-handler.runtime-DH6QCsS8.js} +5 -4
- package/dist/{channel-_o671C-U.js → channel-CST-JKw9.js} +34 -55
- package/dist/{channel-base-DJICAvKH.js → channel-base-fY2AAQj5.js} +1 -2
- package/dist/channel-config-api.js +1 -2
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.adapters-FEj7zUjh.js → channel.adapters-Dhy4lV4f.js} +85 -146
- package/dist/{channel.runtime-CYmt7Ybo.js → channel.runtime-CE5zWkzP.js} +156 -120
- package/dist/config-api-CsD0IFxF.js +3 -0
- package/dist/directory-contract-api.js +1 -1
- package/dist/{doctor-contract-BcEqUZ4j.js → doctor-contract-CvhD0eoX.js} +19 -3
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{runtime-api-BbVoWRxq.js → runtime-api-1v-DgldF.js} +3 -6
- package/dist/runtime-api.js +3 -2
- package/dist/{secret-contract-lCMHqumt.js → secret-contract-D__4IIu_.js} +19 -26
- package/dist/secret-contract-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/npm-shrinkwrap.json +3 -4
- package/openclaw.plugin.json +72 -48
- package/package.json +4 -6
- package/dist/actions-BacnMHv0.js +0 -159
- package/dist/approval-auth-C_BVZZFA.js +0 -27
|
@@ -1,15 +1,73 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import {
|
|
3
|
-
import { n as googleChatApprovalAuth } from "./approval-auth-
|
|
1
|
+
import { A as releaseGoogleChatApprovalCardBinding, C as claimGoogleChatApprovalCardBinding, D as readGoogleChatApprovalActionToken, E as getGoogleChatApprovalCardBinding, _ as probeGoogleChat, b as verifyGoogleChatRequest, c as buildGoogleChatGroupPolicyScope, g as downloadGoogleChatMedia, h as deleteGoogleChatMessage, l as isGoogleChatGroupSpace, v as sendGoogleChatMessage, w as completeGoogleChatApprovalCardBinding, y as updateGoogleChatMessage } from "./channel.adapters-Dhy4lV4f.js";
|
|
2
|
+
import { C as resolveInboundRouteEnvelopeBuilderWithRuntime, D as warnMissingProviderGroupPolicyFallbackOnce, b as resolveAllowlistProviderRuntimeGroupPolicy, c as createChannelPairingController, f as isDangerousNameMatchingEnabled, k as getGoogleChatRuntime, n as GROUP_POLICY_BLOCKED_LABEL, w as resolveWebhookPath, x as resolveDefaultGroupPolicy } from "./runtime-api-1v-DgldF.js";
|
|
3
|
+
import { n as googleChatApprovalAuth } from "./approval-auth-B2m8ckdj.js";
|
|
4
4
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
5
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
6
6
|
import { recordChannelBotPairLoopAndCheckSuppression } from "openclaw/plugin-sdk/channel-inbound";
|
|
7
7
|
import { WEBHOOK_RATE_LIMIT_DEFAULTS, createFixedWindowRateLimiter, normalizeWebhookPath, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
|
|
8
8
|
import { registerWebhookTargetWithPluginRoute, resolveWebhookTargetWithAuthOrReject, withResolvedWebhookRequestPipeline } from "openclaw/plugin-sdk/webhook-targets";
|
|
9
|
-
import { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
9
|
+
import { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject, runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
10
|
+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
10
11
|
import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
|
|
11
12
|
import { channelIngressRoutes, createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
12
|
-
import {
|
|
13
|
+
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
14
|
+
//#region extensions/googlechat/src/approval-terminal-card.ts
|
|
15
|
+
const GOOGLECHAT_APPROVAL_CARD_ID = "openclaw-approval";
|
|
16
|
+
const MAX_TEXT_PARAGRAPH_CHARS = 1800;
|
|
17
|
+
function escapeGoogleChatText(text) {
|
|
18
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19
|
+
}
|
|
20
|
+
function truncateText(text) {
|
|
21
|
+
return text.length <= MAX_TEXT_PARAGRAPH_CHARS ? text : `${truncateUtf16Safe(text, MAX_TEXT_PARAGRAPH_CHARS - 3)}...`;
|
|
22
|
+
}
|
|
23
|
+
function formatApprovalId(value) {
|
|
24
|
+
return JSON.stringify(value).slice(1, -1);
|
|
25
|
+
}
|
|
26
|
+
function formatCanonicalOutcome(approval) {
|
|
27
|
+
switch (approval.status) {
|
|
28
|
+
case "allowed": return approval.decision === "allow-always" ? "Allowed always" : "Allowed once";
|
|
29
|
+
case "denied": return "Denied";
|
|
30
|
+
case "expired": return "Expired";
|
|
31
|
+
case "cancelled": return "Cancelled";
|
|
32
|
+
}
|
|
33
|
+
return "Unavailable";
|
|
34
|
+
}
|
|
35
|
+
function buildSubjectSection(presentation) {
|
|
36
|
+
if (presentation.kind === "exec") return {
|
|
37
|
+
header: "Command",
|
|
38
|
+
widgets: [{ textParagraph: { text: escapeGoogleChatText(truncateText(presentation.commandPreview ?? presentation.commandText)) } }]
|
|
39
|
+
};
|
|
40
|
+
const description = presentation.description.trim();
|
|
41
|
+
return {
|
|
42
|
+
header: "Request",
|
|
43
|
+
widgets: [{ textParagraph: { text: truncateText(`<b>${escapeGoogleChatText(presentation.title)}</b>${description ? `<br>${escapeGoogleChatText(description)}` : ""}`) } }]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Render the canonical first-answer result without retaining any actionable buttons. */
|
|
47
|
+
function buildGoogleChatCanonicalApprovalTerminalCards(result) {
|
|
48
|
+
const { approval } = result;
|
|
49
|
+
const kindLabel = approval.presentation.kind === "plugin" ? "Plugin" : "Exec";
|
|
50
|
+
const detailLines = [
|
|
51
|
+
`<b>Approval ID:</b> ${escapeGoogleChatText(formatApprovalId(approval.id))}`,
|
|
52
|
+
`<b>Status:</b> ${escapeGoogleChatText(approval.status)}`,
|
|
53
|
+
...approval.status === "allowed" || approval.status === "denied" ? [`<b>Decision:</b> ${escapeGoogleChatText(approval.decision)}`] : [],
|
|
54
|
+
`<b>Reason:</b> ${escapeGoogleChatText(approval.reason)}`
|
|
55
|
+
];
|
|
56
|
+
return [{
|
|
57
|
+
cardId: GOOGLECHAT_APPROVAL_CARD_ID,
|
|
58
|
+
card: {
|
|
59
|
+
header: {
|
|
60
|
+
title: `${kindLabel} Approval: ${formatCanonicalOutcome(approval)}`,
|
|
61
|
+
subtitle: result.applied ? "Resolved by this action" : "Already resolved"
|
|
62
|
+
},
|
|
63
|
+
sections: [buildSubjectSection(approval.presentation), {
|
|
64
|
+
header: "Details",
|
|
65
|
+
widgets: [{ textParagraph: { text: truncateText(detailLines.join("<br>")) } }]
|
|
66
|
+
}]
|
|
67
|
+
}
|
|
68
|
+
}];
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
13
71
|
//#region extensions/googlechat/src/approval-card-click.ts
|
|
14
72
|
function logIgnored(target, message) {
|
|
15
73
|
target.runtime.log?.(`[${target.account.accountId}] googlechat approval ignored: ${message}`);
|
|
@@ -60,21 +118,29 @@ async function maybeHandleGoogleChatApprovalCardClick(params) {
|
|
|
60
118
|
return true;
|
|
61
119
|
}
|
|
62
120
|
const consumed = claim.binding;
|
|
121
|
+
let result;
|
|
63
122
|
try {
|
|
64
|
-
await resolveApprovalOverGateway({
|
|
123
|
+
result = await resolveApprovalOverGateway({
|
|
65
124
|
cfg: params.target.config,
|
|
66
125
|
approvalId: consumed.approvalId,
|
|
126
|
+
approvalKind: consumed.approvalKind,
|
|
67
127
|
decision: consumed.decision,
|
|
68
128
|
senderId: actor,
|
|
69
|
-
allowPluginFallback: consumed.approvalKind === "exec",
|
|
70
129
|
clientDisplayName: `Google Chat approval (${actor?.trim() || "unknown"})`
|
|
71
130
|
});
|
|
131
|
+
await updateGoogleChatMessage({
|
|
132
|
+
account: params.target.account,
|
|
133
|
+
messageName: consumed.messageName,
|
|
134
|
+
cardsV2: buildGoogleChatCanonicalApprovalTerminalCards(result)
|
|
135
|
+
});
|
|
72
136
|
} catch (error) {
|
|
73
137
|
releaseGoogleChatApprovalCardBinding(token);
|
|
74
138
|
throw error;
|
|
75
139
|
}
|
|
76
140
|
completeGoogleChatApprovalCardBinding(token);
|
|
77
|
-
|
|
141
|
+
const outcome = result.applied ? "resolved" : "already resolved";
|
|
142
|
+
const decision = "decision" in result.approval ? result.approval.decision : "none";
|
|
143
|
+
params.target.runtime.log?.(`[${params.target.account.accountId}] googlechat approval ${outcome} id=${consumed.approvalId} status=${result.approval.status} decision=${decision} sender=${actor || "unknown"}`);
|
|
78
144
|
return true;
|
|
79
145
|
}
|
|
80
146
|
//#endregion
|
|
@@ -112,7 +178,7 @@ const googleChatIngressIdentity = defineStableChannelIngressIdentity({
|
|
|
112
178
|
isWildcardEntry: (entry) => normalizeEntryValue(entry) === "*",
|
|
113
179
|
resolveEntryId: ({ entryIndex, fieldKey }) => fieldKey === "stableId" ? `entry-${entryIndex + 1}:user` : `entry-${entryIndex + 1}:${fieldKey}`
|
|
114
180
|
});
|
|
115
|
-
function
|
|
181
|
+
function resolveGoogleChatGroupConfig(params) {
|
|
116
182
|
const { groupId, groupName, groups } = params;
|
|
117
183
|
const entries = groups ?? {};
|
|
118
184
|
const keys = Object.keys(entries);
|
|
@@ -121,14 +187,21 @@ function resolveGroupConfig(params) {
|
|
|
121
187
|
allowlistConfigured: false,
|
|
122
188
|
deprecatedNameMatch: false
|
|
123
189
|
};
|
|
124
|
-
const
|
|
190
|
+
const { "*": fallback, ...scopes } = entries;
|
|
191
|
+
const scope = buildGoogleChatGroupPolicyScope({
|
|
192
|
+
tree: {
|
|
193
|
+
defaults: fallback,
|
|
194
|
+
scopes
|
|
195
|
+
},
|
|
196
|
+
groupId
|
|
197
|
+
});
|
|
198
|
+
const entry = scope.matchKey ? entries[scope.matchKey] : void 0;
|
|
125
199
|
const normalizedGroupName = normalizeLowercaseStringOrEmpty(groupName ?? "");
|
|
126
200
|
const deprecatedNameMatch = !entry && Boolean(groupName && keys.some((key) => {
|
|
127
201
|
const trimmed = key.trim();
|
|
128
202
|
if (!trimmed || trimmed === "*" || /^spaces\//i.test(trimmed)) return false;
|
|
129
203
|
return trimmed === groupName || normalizeLowercaseStringOrEmpty(trimmed) === normalizedGroupName;
|
|
130
204
|
}));
|
|
131
|
-
const fallback = entries["*"];
|
|
132
205
|
return {
|
|
133
206
|
entry: deprecatedNameMatch ? void 0 : entry ?? fallback,
|
|
134
207
|
allowlistConfigured: true,
|
|
@@ -191,7 +264,7 @@ async function applyGoogleChatInboundAccessPolicy(params) {
|
|
|
191
264
|
log: logVerbose
|
|
192
265
|
});
|
|
193
266
|
warnMutableGroupKeysConfigured(logVerbose, account.config.groups ?? void 0);
|
|
194
|
-
const groupConfigResolved =
|
|
267
|
+
const groupConfigResolved = resolveGoogleChatGroupConfig({
|
|
195
268
|
groupId: spaceId,
|
|
196
269
|
groupName: space.displayName ?? null,
|
|
197
270
|
groups: account.config.groups ?? void 0
|
|
@@ -357,49 +430,50 @@ async function applyGoogleChatInboundAccessPolicy(params) {
|
|
|
357
430
|
//#endregion
|
|
358
431
|
//#region extensions/googlechat/src/monitor-durable.ts
|
|
359
432
|
function resolveGoogleChatDurableReplyOptions(params) {
|
|
360
|
-
if (params.infoKind !== "final" || params.
|
|
433
|
+
if (params.infoKind !== "final" || params.hasTypingMessage) return false;
|
|
361
434
|
const threadId = params.payload.replyToId?.trim() || void 0;
|
|
435
|
+
if (!threadId) return {
|
|
436
|
+
to: params.spaceId,
|
|
437
|
+
replyToId: null
|
|
438
|
+
};
|
|
362
439
|
return {
|
|
363
440
|
to: params.spaceId,
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
threadId
|
|
367
|
-
} : {}
|
|
441
|
+
replyToId: threadId,
|
|
442
|
+
threadId
|
|
368
443
|
};
|
|
369
444
|
}
|
|
370
445
|
//#endregion
|
|
371
446
|
//#region extensions/googlechat/src/monitor-reply-delivery.ts
|
|
372
447
|
async function deliverGoogleChatReply(params) {
|
|
373
448
|
const { payload, account, spaceId, runtime, core, config, statusSink } = params;
|
|
374
|
-
let
|
|
449
|
+
let typingMessage = params.typingMessage;
|
|
450
|
+
const replyThreadName = payload.replyToId?.trim() || void 0;
|
|
451
|
+
const typingMessageThreadName = typingMessage?.thread?.trim() || void 0;
|
|
375
452
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
376
|
-
const mediaCount = reply.mediaCount;
|
|
377
|
-
const hasMedia = reply.hasMedia;
|
|
378
453
|
const text = reply.text;
|
|
379
454
|
let firstTextChunk = true;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
runtime.error?.(`Google Chat typing cleanup failed: ${String(err)}`);
|
|
389
|
-
if (typingMessageName) {
|
|
390
|
-
const fallbackText = reply.hasText ? text : mediaCount > 1 ? "Sent attachments." : "Sent attachment.";
|
|
391
|
-
try {
|
|
392
|
-
await updateGoogleChatMessage({
|
|
393
|
-
account,
|
|
394
|
-
messageName: typingMessageName,
|
|
395
|
-
text: fallbackText
|
|
396
|
-
});
|
|
397
|
-
suppressCaption = Boolean(text.trim());
|
|
398
|
-
} catch (updateErr) {
|
|
399
|
-
runtime.error?.(`Google Chat typing update failed: ${String(updateErr)}`);
|
|
400
|
-
typingMessageName = void 0;
|
|
401
|
-
}
|
|
455
|
+
if (typingMessage && typingMessageThreadName !== replyThreadName) {
|
|
456
|
+
try {
|
|
457
|
+
await deleteGoogleChatMessage({
|
|
458
|
+
account,
|
|
459
|
+
messageName: typingMessage.name
|
|
460
|
+
});
|
|
461
|
+
} catch (err) {
|
|
462
|
+
runtime.error?.(`Google Chat typing cleanup failed: ${String(err)}`);
|
|
402
463
|
}
|
|
464
|
+
typingMessage = void 0;
|
|
465
|
+
}
|
|
466
|
+
if (reply.hasMedia) runtime.error?.("Google Chat outbound attachments require user OAuth and are not supported by this service-account channel; sending text fallback only.");
|
|
467
|
+
if (reply.hasMedia && !reply.hasText) {
|
|
468
|
+
try {
|
|
469
|
+
if (typingMessage) await deleteGoogleChatMessage({
|
|
470
|
+
account,
|
|
471
|
+
messageName: typingMessage.name
|
|
472
|
+
});
|
|
473
|
+
} catch (err) {
|
|
474
|
+
runtime.error?.(`Google Chat typing cleanup failed: ${String(err)}`);
|
|
475
|
+
}
|
|
476
|
+
throw new Error("Google Chat outbound attachments require user OAuth and no text fallback is available.");
|
|
403
477
|
}
|
|
404
478
|
const chunkLimit = account.config.textChunkLimit ?? 4e3;
|
|
405
479
|
const chunkMode = core.channel.text.resolveChunkMode(config, "googlechat", account.accountId);
|
|
@@ -408,78 +482,36 @@ async function deliverGoogleChatReply(params) {
|
|
|
408
482
|
account,
|
|
409
483
|
space: spaceId,
|
|
410
484
|
text: chunk,
|
|
411
|
-
thread:
|
|
485
|
+
thread: replyThreadName
|
|
412
486
|
});
|
|
413
487
|
};
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
} finally {
|
|
438
|
-
firstTextChunk = false;
|
|
439
|
-
}
|
|
488
|
+
const chunks = core.channel.text.chunkMarkdownTextWithMode(text, chunkLimit, chunkMode);
|
|
489
|
+
for (const chunk of chunks) {
|
|
490
|
+
if (!chunk) continue;
|
|
491
|
+
try {
|
|
492
|
+
if (firstTextChunk && typingMessage) await updateGoogleChatMessage({
|
|
493
|
+
account,
|
|
494
|
+
messageName: typingMessage.name,
|
|
495
|
+
text: chunk
|
|
496
|
+
});
|
|
497
|
+
else await sendTextMessage(chunk);
|
|
498
|
+
firstTextChunk = false;
|
|
499
|
+
statusSink?.({ lastOutboundAt: Date.now() });
|
|
500
|
+
} catch (err) {
|
|
501
|
+
runtime.error?.(`Google Chat message send failed: ${String(err)}`);
|
|
502
|
+
if (firstTextChunk && typingMessage) {
|
|
503
|
+
typingMessage = void 0;
|
|
504
|
+
try {
|
|
505
|
+
await sendTextMessage(chunk);
|
|
506
|
+
statusSink?.({ lastOutboundAt: Date.now() });
|
|
507
|
+
} catch (fallbackErr) {
|
|
508
|
+
runtime.error?.(`Google Chat message fallback send failed: ${String(fallbackErr)}`);
|
|
509
|
+
} finally {
|
|
510
|
+
firstTextChunk = false;
|
|
440
511
|
}
|
|
441
512
|
}
|
|
442
|
-
},
|
|
443
|
-
sendMedia: async ({ mediaUrl, caption }) => {
|
|
444
|
-
try {
|
|
445
|
-
const loaded = await core.channel.media.readRemoteMediaBuffer({
|
|
446
|
-
url: mediaUrl,
|
|
447
|
-
maxBytes: (account.config.mediaMaxMb ?? 20) * 1024 * 1024
|
|
448
|
-
});
|
|
449
|
-
const upload = await uploadAttachmentForReply({
|
|
450
|
-
account,
|
|
451
|
-
spaceId,
|
|
452
|
-
buffer: loaded.buffer,
|
|
453
|
-
contentType: loaded.contentType,
|
|
454
|
-
filename: loaded.fileName ?? "attachment"
|
|
455
|
-
});
|
|
456
|
-
if (!upload.attachmentUploadToken) throw new Error("missing attachment upload token");
|
|
457
|
-
await sendGoogleChatMessage({
|
|
458
|
-
account,
|
|
459
|
-
space: spaceId,
|
|
460
|
-
text: caption,
|
|
461
|
-
thread: payload.replyToId,
|
|
462
|
-
attachments: [{
|
|
463
|
-
attachmentUploadToken: upload.attachmentUploadToken,
|
|
464
|
-
contentName: loaded.fileName
|
|
465
|
-
}]
|
|
466
|
-
});
|
|
467
|
-
statusSink?.({ lastOutboundAt: Date.now() });
|
|
468
|
-
} catch (err) {
|
|
469
|
-
runtime.error?.(`Google Chat attachment send failed: ${String(err)}`);
|
|
470
|
-
}
|
|
471
513
|
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
async function uploadAttachmentForReply(params) {
|
|
475
|
-
const { account, spaceId, buffer, contentType, filename } = params;
|
|
476
|
-
return await uploadGoogleChatAttachment({
|
|
477
|
-
account,
|
|
478
|
-
space: spaceId,
|
|
479
|
-
filename,
|
|
480
|
-
buffer,
|
|
481
|
-
contentType
|
|
482
|
-
});
|
|
514
|
+
}
|
|
483
515
|
}
|
|
484
516
|
//#endregion
|
|
485
517
|
//#region extensions/googlechat/src/monitor-webhook.ts
|
|
@@ -688,7 +720,7 @@ function createGoogleChatWebhookRequestHandler(params) {
|
|
|
688
720
|
}
|
|
689
721
|
const dispatchTarget = selectedTarget;
|
|
690
722
|
dispatchTarget.statusSink?.({ lastInboundAt: Date.now() });
|
|
691
|
-
params.processEvent(parsedEvent, dispatchTarget).catch((err) => {
|
|
723
|
+
runDetachedWebhookWork(() => params.processEvent(parsedEvent, dispatchTarget)).catch((err) => {
|
|
692
724
|
dispatchTarget.runtime.error?.(`[${dispatchTarget.account.accountId}] Google Chat webhook failed: ${String(err)}`);
|
|
693
725
|
});
|
|
694
726
|
res.statusCode = 200;
|
|
@@ -893,8 +925,8 @@ async function processMessageWithPipeline(params) {
|
|
|
893
925
|
});
|
|
894
926
|
let mediaPath;
|
|
895
927
|
let mediaType;
|
|
896
|
-
|
|
897
|
-
|
|
928
|
+
const first = attachments.at(0);
|
|
929
|
+
if (first) {
|
|
898
930
|
const attachmentData = await downloadAttachment(first, account, mediaMaxMb, core);
|
|
899
931
|
if (attachmentData) {
|
|
900
932
|
mediaPath = attachmentData.path;
|
|
@@ -964,9 +996,10 @@ async function processMessageWithPipeline(params) {
|
|
|
964
996
|
runtime.error?.(`[${account.accountId}] typingIndicator="reaction" requires user OAuth (not supported with service account). Falling back to "message" mode.`);
|
|
965
997
|
typingIndicator = "message";
|
|
966
998
|
}
|
|
967
|
-
let
|
|
999
|
+
let typingMessage;
|
|
1000
|
+
const typingMessageThreadName = account.config.replyToMode && account.config.replyToMode !== "off" ? replyThreadName : void 0;
|
|
968
1001
|
if (typingIndicator === "message") try {
|
|
969
|
-
|
|
1002
|
+
const result = await sendGoogleChatMessage({
|
|
970
1003
|
account,
|
|
971
1004
|
space: spaceId,
|
|
972
1005
|
text: `_${resolveBotDisplayName({
|
|
@@ -974,8 +1007,12 @@ async function processMessageWithPipeline(params) {
|
|
|
974
1007
|
agentId: route.agentId,
|
|
975
1008
|
config
|
|
976
1009
|
})} is typing..._`,
|
|
977
|
-
thread:
|
|
978
|
-
})
|
|
1010
|
+
thread: typingMessageThreadName
|
|
1011
|
+
});
|
|
1012
|
+
if (result?.messageName) typingMessage = {
|
|
1013
|
+
name: result.messageName,
|
|
1014
|
+
thread: typingMessageThreadName
|
|
1015
|
+
};
|
|
979
1016
|
} catch (err) {
|
|
980
1017
|
runtime.error?.(`Failed sending typing message: ${String(err)}`);
|
|
981
1018
|
}
|
|
@@ -1007,7 +1044,7 @@ async function processMessageWithPipeline(params) {
|
|
|
1007
1044
|
payload,
|
|
1008
1045
|
infoKind: info.kind,
|
|
1009
1046
|
spaceId,
|
|
1010
|
-
|
|
1047
|
+
hasTypingMessage: Boolean(typingMessage)
|
|
1011
1048
|
}),
|
|
1012
1049
|
deliver: async (payload) => {
|
|
1013
1050
|
await deliverGoogleChatReply({
|
|
@@ -1018,9 +1055,9 @@ async function processMessageWithPipeline(params) {
|
|
|
1018
1055
|
core,
|
|
1019
1056
|
config,
|
|
1020
1057
|
statusSink,
|
|
1021
|
-
|
|
1058
|
+
typingMessage
|
|
1022
1059
|
});
|
|
1023
|
-
|
|
1060
|
+
typingMessage = void 0;
|
|
1024
1061
|
},
|
|
1025
1062
|
onDelivered: () => {
|
|
1026
1063
|
statusSink?.({ lastOutboundAt: Date.now() });
|
|
@@ -1102,7 +1139,6 @@ function resolveGoogleChatWebhookPath(params) {
|
|
|
1102
1139
|
const googleChatChannelRuntime = {
|
|
1103
1140
|
probeGoogleChat,
|
|
1104
1141
|
sendGoogleChatMessage,
|
|
1105
|
-
uploadGoogleChatAttachment,
|
|
1106
1142
|
resolveGoogleChatWebhookPath,
|
|
1107
1143
|
startGoogleChatMonitor
|
|
1108
1144
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as googlechatDirectoryAdapter } from "./channel.adapters-
|
|
1
|
+
import { t as googlechatDirectoryAdapter } from "./channel.adapters-Dhy4lV4f.js";
|
|
2
2
|
//#region extensions/googlechat/directory-contract-api.ts
|
|
3
3
|
const googlechatDirectoryContractPlugin = {
|
|
4
4
|
id: "googlechat",
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor";
|
|
1
|
+
import { asObjectRecord, defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
|
|
2
2
|
//#region extensions/googlechat/src/doctor-contract.ts
|
|
3
|
+
const streamingAliasMigration = defineChannelAliasMigration({
|
|
4
|
+
channelId: "googlechat",
|
|
5
|
+
streaming: {
|
|
6
|
+
defaultMode: "partial",
|
|
7
|
+
deliveryOnly: true
|
|
8
|
+
},
|
|
9
|
+
accountStreamingReplacesRoot: true
|
|
10
|
+
});
|
|
3
11
|
function hasLegacyGoogleChatStreamMode(value) {
|
|
4
12
|
return asObjectRecord(value)?.streamMode !== void 0;
|
|
5
13
|
}
|
|
@@ -90,9 +98,10 @@ const legacyConfigRules = [
|
|
|
90
98
|
],
|
|
91
99
|
message: "channels.googlechat.accounts.<id>.groups.<id>.allow is legacy; use channels.googlechat.accounts.<id>.groups.<id>.enabled instead. Run \"openclaw doctor --fix\".",
|
|
92
100
|
match: (value) => hasLegacyAccountAliases(value, hasLegacyGoogleChatGroupAllowAlias)
|
|
93
|
-
}
|
|
101
|
+
},
|
|
102
|
+
...streamingAliasMigration.legacyConfigRules
|
|
94
103
|
];
|
|
95
|
-
function
|
|
104
|
+
function normalizeRetiredGoogleChatKeys(cfg) {
|
|
96
105
|
const rawEntry = asObjectRecord(cfg.channels?.googlechat);
|
|
97
106
|
if (!rawEntry) return {
|
|
98
107
|
config: cfg,
|
|
@@ -147,5 +156,12 @@ function normalizeCompatibilityConfig({ cfg }) {
|
|
|
147
156
|
changes
|
|
148
157
|
};
|
|
149
158
|
}
|
|
159
|
+
function normalizeCompatibilityConfig({ cfg }) {
|
|
160
|
+
const retired = normalizeRetiredGoogleChatKeys(cfg);
|
|
161
|
+
return streamingAliasMigration.normalizeChannelConfig({
|
|
162
|
+
cfg: retired.config,
|
|
163
|
+
changes: retired.changes
|
|
164
|
+
});
|
|
165
|
+
}
|
|
150
166
|
//#endregion
|
|
151
167
|
export { normalizeCompatibilityConfig as n, legacyConfigRules as t };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-
|
|
1
|
+
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-CvhD0eoX.js";
|
|
2
2
|
export { legacyConfigRules, normalizeCompatibilityConfig };
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
import "./config-api-CsD0IFxF.js";
|
|
1
2
|
import { extractToolSend as extractToolSend$1 } from "openclaw/plugin-sdk/tool-send";
|
|
2
|
-
import { readRemoteMediaBuffer, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
3
3
|
import { fetchWithSsrFGuard as fetchWithSsrFGuard$1 } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
4
4
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
5
|
-
import { createActionGate
|
|
6
|
-
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
|
|
5
|
+
import { createActionGate, jsonResult as jsonResult$1, readNumberParam, readReactionParams, readStringParam as readStringParam$1 } from "openclaw/plugin-sdk/channel-actions";
|
|
7
6
|
import { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
|
|
8
7
|
import { createAccountStatusSink as createAccountStatusSink$1, createChannelMessageReplyPipeline, runPassiveAccountLifecycle as runPassiveAccountLifecycle$1 } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
8
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
10
9
|
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
11
10
|
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
12
|
-
import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
|
|
13
11
|
import { GROUP_POLICY_BLOCKED_LABEL, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
14
12
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
15
|
-
import { loadOutboundMediaFromUrl as loadOutboundMediaFromUrl$1 } from "openclaw/plugin-sdk/outbound-media";
|
|
16
13
|
import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
|
|
17
14
|
import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
|
|
18
15
|
import { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
|
|
@@ -25,4 +22,4 @@ const { setRuntime: setGoogleChatRuntime, getRuntime: getGoogleChatRuntime } = c
|
|
|
25
22
|
errorMessage: "Google Chat runtime not initialized"
|
|
26
23
|
});
|
|
27
24
|
//#endregion
|
|
28
|
-
export {
|
|
25
|
+
export { setGoogleChatRuntime as A, resolveInboundRouteEnvelopeBuilderWithRuntime as C, warnMissingProviderGroupPolicyFallbackOnce as D, runPassiveAccountLifecycle$1 as E, withResolvedWebhookRequestPipeline$1 as O, resolveInboundMentionDecision as S, resolveWebhookTargetWithAuthOrReject$1 as T, readReactionParams as _, createAccountStatusSink$1 as a, resolveAllowlistProviderRuntimeGroupPolicy as b, createChannelPairingController as c, fetchWithSsrFGuard$1 as d, isDangerousNameMatchingEnabled as f, readNumberParam as g, readJsonWebhookBodyOrReject$1 as h, chunkTextForOutbound as i, getGoogleChatRuntime as k, createWebhookInFlightLimiter$1 as l, missingTargetError as m, GROUP_POLICY_BLOCKED_LABEL as n, createActionGate as o, jsonResult$1 as p, PAIRING_APPROVED_MESSAGE as r, createChannelMessageReplyPipeline as s, DEFAULT_ACCOUNT_ID as t, extractToolSend$1 as u, readStringParam$1 as v, resolveWebhookPath as w, resolveDefaultGroupPolicy as x, registerWebhookTargetWithPluginRoute$1 as y };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { n as buildChannelConfigSchema, t as GoogleChatConfigSchema } from "./config-api-CsD0IFxF.js";
|
|
2
|
+
import { A as setGoogleChatRuntime, C as resolveInboundRouteEnvelopeBuilderWithRuntime, D as warnMissingProviderGroupPolicyFallbackOnce, E as runPassiveAccountLifecycle, O as withResolvedWebhookRequestPipeline, S as resolveInboundMentionDecision, T as resolveWebhookTargetWithAuthOrReject, _ as readReactionParams, a as createAccountStatusSink, b as resolveAllowlistProviderRuntimeGroupPolicy, c as createChannelPairingController, d as fetchWithSsrFGuard, f as isDangerousNameMatchingEnabled, g as readNumberParam, h as readJsonWebhookBodyOrReject, i as chunkTextForOutbound, l as createWebhookInFlightLimiter, m as missingTargetError, n as GROUP_POLICY_BLOCKED_LABEL, o as createActionGate, p as jsonResult, r as PAIRING_APPROVED_MESSAGE, s as createChannelMessageReplyPipeline, t as DEFAULT_ACCOUNT_ID, u as extractToolSend, v as readStringParam, w as resolveWebhookPath, x as resolveDefaultGroupPolicy, y as registerWebhookTargetWithPluginRoute } from "./runtime-api-1v-DgldF.js";
|
|
3
|
+
export { DEFAULT_ACCOUNT_ID, GROUP_POLICY_BLOCKED_LABEL, GoogleChatConfigSchema, PAIRING_APPROVED_MESSAGE, buildChannelConfigSchema, chunkTextForOutbound, createAccountStatusSink, createActionGate, createChannelMessageReplyPipeline, createChannelPairingController, createWebhookInFlightLimiter, extractToolSend, fetchWithSsrFGuard, isDangerousNameMatchingEnabled, jsonResult, missingTargetError, readJsonWebhookBodyOrReject, readNumberParam, readReactionParams, readStringParam, registerWebhookTargetWithPluginRoute, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, resolveInboundMentionDecision, resolveInboundRouteEnvelopeBuilderWithRuntime, resolveWebhookPath, resolveWebhookTargetWithAuthOrReject, runPassiveAccountLifecycle, setGoogleChatRuntime, warnMissingProviderGroupPolicyFallbackOnce, withResolvedWebhookRequestPipeline };
|
|
@@ -1,31 +1,24 @@
|
|
|
1
|
-
import { getChannelSurface, hasOwnProperty, pushAssignment, pushInactiveSurfaceWarning, pushWarning, resolveChannelAccountSurface } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
1
|
+
import { createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty, pushAssignment, pushInactiveSurfaceWarning, pushWarning, resolveChannelAccountSurface } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
2
|
import { coerceSecretRef } from "openclaw/plugin-sdk/secret-ref-runtime";
|
|
3
3
|
//#region extensions/googlechat/src/secret-contract.ts
|
|
4
|
-
const secretTargetRegistryEntries =
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
refPathPattern: "channels.googlechat.serviceAccountRef",
|
|
23
|
-
secretShape: "sibling_ref",
|
|
24
|
-
expectedResolvedValue: "string-or-object",
|
|
25
|
-
includeInPlan: true,
|
|
26
|
-
includeInConfigure: true,
|
|
27
|
-
includeInAudit: true
|
|
28
|
-
}];
|
|
4
|
+
const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
|
5
|
+
channelKey: "googlechat",
|
|
6
|
+
account: [{
|
|
7
|
+
path: "serviceAccount",
|
|
8
|
+
refPath: "serviceAccountRef",
|
|
9
|
+
targetType: "channels.googlechat.serviceAccount",
|
|
10
|
+
targetTypeAliases: ["channels.googlechat.accounts.*.serviceAccount"],
|
|
11
|
+
secretShape: "sibling_ref",
|
|
12
|
+
expectedResolvedValue: "string-or-object",
|
|
13
|
+
accountIdPathSegmentIndex: 3
|
|
14
|
+
}],
|
|
15
|
+
channel: [{
|
|
16
|
+
path: "serviceAccount",
|
|
17
|
+
refPath: "serviceAccountRef",
|
|
18
|
+
secretShape: "sibling_ref",
|
|
19
|
+
expectedResolvedValue: "string-or-object"
|
|
20
|
+
}]
|
|
21
|
+
});
|
|
29
22
|
function resolveSecretInputRef(params) {
|
|
30
23
|
const explicitRef = coerceSecretRef(params.refValue, params.defaults);
|
|
31
24
|
const inlineRef = explicitRef ? null : coerceSecretRef(params.value, params.defaults);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-
|
|
1
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-D__4IIu_.js";
|
|
2
2
|
export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createGoogleChatPluginBase } from "./channel-base-
|
|
1
|
+
import { n as createGoogleChatPluginBase } from "./channel-base-fY2AAQj5.js";
|
|
2
2
|
//#region extensions/googlechat/src/channel.setup.ts
|
|
3
3
|
const googlechatSetupPlugin = createGoogleChatPluginBase();
|
|
4
4
|
//#endregion
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/googlechat",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/googlechat",
|
|
9
|
-
"version": "2026.7.
|
|
9
|
+
"version": "2026.7.2-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"gaxios": "7.1.5",
|
|
12
11
|
"google-auth-library": "10.9.0",
|
|
13
12
|
"zod": "4.4.3"
|
|
14
13
|
},
|
|
15
14
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.7.
|
|
15
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
17
16
|
},
|
|
18
17
|
"peerDependenciesMeta": {
|
|
19
18
|
"openclaw": {
|