mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-19 01:41:34 +00:00
* fix(channels): enforce configured read targets * test(channels): align policy checks with boundaries * fix: bind channel reads to trusted turn context * test: satisfy gateway lint * fix: narrow message action channel imports * fix(feishu): authorize message reads before provider access * fix(slack): await reaction clear authorization * fix(channels): align provider action contracts * fix(matrix): read direct-room account data before sync * fix(channels): reject unsupported attachment actions early * fix: restore trusted operator conversation reads * fix(matrix): authorize pin actions before provider reads * fix: preserve trusted channel read workflows * fix(discord): resolve current channel ids consistently * fix(agents): preserve message action turn capability * fix(plugins): enforce host-owned read provenance * fix(channels): harden Teams and Discord read policy * fix(channels): preserve exact-current action compatibility * fix(imessage): authorize trusted current chat aliases * fix(channels): preserve normalized current aliases * fix(channels): preserve external current target aliases * fix: reconcile channel policy with current main * fix(discord): isolate DM read policy * fix(channels): enforce provider read gates * fix(gateway): await serialized message action identity tokens * fix(ci): refresh channel protocol contracts
125 lines
3.8 KiB
TypeScript
125 lines
3.8 KiB
TypeScript
// Googlechat plugin module implements channel base behavior.
|
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
|
|
import {
|
|
adaptScopedAccountAccessor,
|
|
createScopedChannelConfigAdapter,
|
|
} from "openclaw/plugin-sdk/channel-config-helpers";
|
|
import type { ChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
import {
|
|
type GoogleChatConfigAccessorAccount,
|
|
listGoogleChatAccountIds,
|
|
resolveDefaultGoogleChatAccountId,
|
|
resolveGoogleChatConfigAccessorAccount,
|
|
resolveGoogleChatAccount,
|
|
type ResolvedGoogleChatAccount,
|
|
} from "./accounts.js";
|
|
import { googlechatSetupAdapter } from "./setup-core.js";
|
|
import { googlechatSetupWizard } from "./setup-surface.js";
|
|
|
|
export const GOOGLECHAT_CHANNEL_ID = "googlechat" as const;
|
|
|
|
const googlechatMeta = {
|
|
id: GOOGLECHAT_CHANNEL_ID,
|
|
label: "Google Chat",
|
|
selectionLabel: "Google Chat (Chat API)",
|
|
docsPath: "/channels/googlechat",
|
|
docsLabel: "googlechat",
|
|
blurb: "Google Workspace Chat app with HTTP webhook.",
|
|
aliases: ["gchat", "google-chat"],
|
|
order: 55,
|
|
detailLabel: "Google Chat",
|
|
systemImage: "message.badge",
|
|
markdownCapable: true,
|
|
};
|
|
|
|
export const formatGoogleChatAllowFromEntry = (entry: string) =>
|
|
normalizeLowercaseStringOrEmpty(
|
|
entry
|
|
.trim()
|
|
.replace(/^(googlechat|google-chat|gchat):/i, "")
|
|
.replace(/^user:/i, "")
|
|
.replace(/^users\//i, ""),
|
|
);
|
|
|
|
const googleChatConfigAdapter = createScopedChannelConfigAdapter<
|
|
ResolvedGoogleChatAccount,
|
|
GoogleChatConfigAccessorAccount
|
|
>({
|
|
sectionKey: GOOGLECHAT_CHANNEL_ID,
|
|
listAccountIds: listGoogleChatAccountIds,
|
|
resolveAccount: adaptScopedAccountAccessor(resolveGoogleChatAccount),
|
|
resolveAccessorAccount: resolveGoogleChatConfigAccessorAccount,
|
|
defaultAccountId: resolveDefaultGoogleChatAccountId,
|
|
clearBaseFields: [
|
|
"serviceAccount",
|
|
"serviceAccountFile",
|
|
"audienceType",
|
|
"audience",
|
|
"webhookPath",
|
|
"webhookUrl",
|
|
"botUser",
|
|
"name",
|
|
],
|
|
resolveAllowFrom: (account) => account.config.dm?.allowFrom,
|
|
formatAllowFrom: (allowFrom) =>
|
|
formatNormalizedAllowFromEntries({
|
|
allowFrom,
|
|
normalizeEntry: formatGoogleChatAllowFromEntry,
|
|
}),
|
|
resolveDefaultTo: (account) => account.config.defaultTo,
|
|
});
|
|
|
|
type GoogleChatPluginBase = Pick<
|
|
ChannelPlugin<ResolvedGoogleChatAccount>,
|
|
| "id"
|
|
| "meta"
|
|
| "setup"
|
|
| "setupWizard"
|
|
| "capabilities"
|
|
| "streaming"
|
|
| "reload"
|
|
| "configSchema"
|
|
| "config"
|
|
>;
|
|
|
|
export function createGoogleChatPluginBase(
|
|
params: {
|
|
configSchema?: ChannelPlugin<ResolvedGoogleChatAccount>["configSchema"];
|
|
} = {},
|
|
): GoogleChatPluginBase {
|
|
return {
|
|
id: GOOGLECHAT_CHANNEL_ID,
|
|
meta: { ...googlechatMeta },
|
|
setup: googlechatSetupAdapter,
|
|
setupWizard: googlechatSetupWizard,
|
|
capabilities: {
|
|
chatTypes: ["direct", "group", "thread"],
|
|
threads: true,
|
|
// Inbound attachment download remains supported even though service-account
|
|
// authentication cannot use Google Chat's user-auth-only upload endpoint.
|
|
media: true,
|
|
nativeCommands: false,
|
|
blockStreaming: true,
|
|
},
|
|
streaming: {
|
|
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
|
|
},
|
|
reload: { configPrefixes: ["channels.googlechat"] },
|
|
...(params.configSchema ? { configSchema: params.configSchema } : {}),
|
|
config: {
|
|
...googleChatConfigAdapter,
|
|
isConfigured: (account) => account.credentialSource !== "none",
|
|
describeAccount: (account) =>
|
|
describeAccountSnapshot({
|
|
account,
|
|
configured: account.credentialSource !== "none",
|
|
extra: {
|
|
credentialSource: account.credentialSource,
|
|
},
|
|
}),
|
|
},
|
|
};
|
|
}
|