From 90b69cac02e36cb50633bedce3180a18faabb97a Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 6 May 2026 19:18:53 +0100 Subject: [PATCH] test(perf): slim channel directory contracts --- extensions/googlechat/src/channel.ts | 26 ++++++++++++++++--- .../threading-directory-contract-suites.ts | 24 +++++++---------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/extensions/googlechat/src/channel.ts b/extensions/googlechat/src/channel.ts index 7235c16112a..945d4f588ec 100644 --- a/extensions/googlechat/src/channel.ts +++ b/extensions/googlechat/src/channel.ts @@ -11,7 +11,7 @@ import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState, } from "openclaw/plugin-sdk/status-helpers"; -import { googlechatMessageActions } from "./actions.js"; +import { extractToolSend } from "openclaw/plugin-sdk/tool-send"; import { googleChatApprovalAuth } from "./approval-auth.js"; import { formatAllowFromEntry, @@ -35,7 +35,9 @@ import { resolveGoogleChatConfigAccessorAccount, resolveDefaultGoogleChatAccountId, resolveGoogleChatAccount, + listGoogleChatAccountIds, type ChannelMessageActionAdapter, + type ChannelMessageActionName, type ChannelStatusIssue, type ResolvedGoogleChatAccount, } from "./channel.deps.runtime.js"; @@ -97,9 +99,27 @@ const googleChatConfigAdapter = createScopedChannelConfigAdapter< }); const googlechatActions: ChannelMessageActionAdapter = { - describeMessageTool: (ctx) => googlechatMessageActions.describeMessageTool?.(ctx) ?? null, - extractToolSend: (ctx) => googlechatMessageActions.extractToolSend?.(ctx) ?? null, + describeMessageTool: ({ cfg, accountId }) => { + const accounts = accountId + ? [resolveGoogleChatAccount({ cfg, accountId })].filter( + (account) => account.enabled && account.credentialSource !== "none", + ) + : listGoogleChatAccountIds(cfg) + .map((id) => resolveGoogleChatAccount({ cfg, accountId: id })) + .filter((account) => account.enabled && account.credentialSource !== "none"); + if (accounts.length === 0) { + return null; + } + const actions = new Set(["send", "upload-file"]); + if (accounts.some((account) => account.config.actions?.reactions !== false)) { + actions.add("react"); + actions.add("reactions"); + } + return { actions: Array.from(actions) }; + }, + extractToolSend: ({ args }) => extractToolSend(args, "sendMessage"), handleAction: async (ctx) => { + const { googlechatMessageActions } = await import("./actions.js"); if (!googlechatMessageActions.handleAction) { throw new Error("Google Chat actions are not available."); } diff --git a/src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts b/src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts index 3af5e712ff1..43c065e5e8d 100644 --- a/src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts +++ b/src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts @@ -9,16 +9,11 @@ import type { } from "../../types.core.js"; import type { ChannelPlugin } from "../../types.js"; -let contractRuntime: RuntimeEnv | undefined; - -async function getDirectoryContractRuntime(): Promise { - if (contractRuntime) { - return contractRuntime; - } - const { createNonExitingRuntime } = await import("../../../../runtime.js"); - contractRuntime = createNonExitingRuntime(); - return contractRuntime; -} +const contractRuntime = new Proxy(Object.create(null), { + get(_target, property) { + throw new Error(`Directory contract unexpectedly accessed runtime.${String(property)}`); + }, +}) as RuntimeEnv; function expectDirectoryEntryShape(entry: ChannelDirectoryEntry) { expect(["user", "group", "channel"]).toContain(entry.kind); @@ -193,11 +188,10 @@ export async function expectChannelDirectoryBaseContract(params: { if (params.coverage === "presence") { return; } - const runtime = await getDirectoryContractRuntime(); const self = await directory?.self?.({ cfg, accountId, - runtime, + runtime: contractRuntime, }); if (self) { expectDirectoryEntryShape(self); @@ -209,7 +203,7 @@ export async function expectChannelDirectoryBaseContract(params: { accountId, query: "", limit: 5, - runtime, + runtime: contractRuntime, })) ?? []; expect(Array.isArray(peers)).toBe(true); for (const peer of peers) { @@ -222,7 +216,7 @@ export async function expectChannelDirectoryBaseContract(params: { accountId, query: "", limit: 5, - runtime, + runtime: contractRuntime, })) ?? []; expect(Array.isArray(groups)).toBe(true); for (const group of groups) { @@ -235,7 +229,7 @@ export async function expectChannelDirectoryBaseContract(params: { accountId, groupId: groups[0].id, limit: 5, - runtime, + runtime: contractRuntime, }); expect(Array.isArray(members)).toBe(true); for (const member of members) {