refactor: centralize computed channel status adapters

This commit is contained in:
Peter Steinberger
2026-03-22 21:15:09 +00:00
parent 29c0e783b1
commit 87b2672126
8 changed files with 185 additions and 104 deletions

View File

@@ -16,6 +16,7 @@ import {
} from "openclaw/plugin-sdk/channel-policy";
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
import {
listBlueBubblesAccountIds,
type ResolvedBlueBubblesAccount,
@@ -32,7 +33,6 @@ import {
import type { ChannelAccountSnapshot, ChannelPlugin } from "./runtime-api.js";
import {
buildChannelConfigSchema,
buildComputedAccountStatusSnapshot,
buildProbeChannelStatusSummary,
collectBlueBubblesStatusIssues,
DEFAULT_ACCOUNT_ID,
@@ -305,7 +305,7 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
},
}),
},
status: {
status: createComputedAccountStatusAdapter<ResolvedBlueBubblesAccount, BlueBubblesProbe>({
defaultRuntime: {
accountId: DEFAULT_ACCOUNT_ID,
running: false,
@@ -322,25 +322,21 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
password: account.config.password ?? null,
timeoutMs,
}),
buildAccountSnapshot: ({ account, runtime, probe }) => {
resolveAccountSnapshot: ({ account, runtime, probe }) => {
const running = runtime?.running ?? false;
const probeOk = (probe as BlueBubblesProbe | undefined)?.ok;
return buildComputedAccountStatusSnapshot(
{
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: account.configured,
runtime,
probe,
},
{
const probeOk = probe?.ok;
return {
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: account.configured,
extra: {
baseUrl: account.baseUrl,
connected: probeOk ?? running,
},
);
};
},
},
}),
gateway: {
startAccount: async (ctx) => {
const runtime = await loadBlueBubblesChannelRuntime();

View File

@@ -28,6 +28,7 @@ import {
resolveThreadSessionKeys,
type RoutePeer,
} from "openclaw/plugin-sdk/routing";
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
import {
listDiscordAccountIds,
resolveDiscordAccount,
@@ -54,7 +55,6 @@ import {
import { probeDiscord, type DiscordProbe } from "./probe.js";
import { resolveDiscordUserAllowlist } from "./resolve-users.js";
import {
buildComputedAccountStatusSnapshot,
buildTokenChannelStatusSummary,
type ChannelMessageActionAdapter,
type ChannelPlugin,
@@ -499,7 +499,7 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
parentConversationId,
}),
},
status: {
status: createComputedAccountStatusAdapter<ResolvedDiscordAccount, DiscordProbe, unknown>({
defaultRuntime: {
accountId: DEFAULT_ACCOUNT_ID,
running: false,
@@ -630,21 +630,17 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
});
return { ...audit, unresolvedChannels };
},
buildAccountSnapshot: ({ account, runtime, probe, audit }) => {
resolveAccountSnapshot: ({ account, runtime, probe, audit }) => {
const configured =
resolveConfiguredFromCredentialStatuses(account) ?? Boolean(account.token?.trim());
const app = runtime?.application ?? (probe as { application?: unknown })?.application;
const bot = runtime?.bot ?? (probe as { bot?: unknown })?.bot;
return buildComputedAccountStatusSnapshot(
{
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured,
runtime,
probe,
},
{
return {
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured,
extra: {
...projectCredentialSnapshotFields(account),
connected: runtime?.connected ?? false,
reconnectAttempts: runtime?.reconnectAttempts,
@@ -655,9 +651,9 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
bot: bot ?? undefined,
audit,
},
);
};
},
},
}),
gateway: {
startAccount: async (ctx) => {
const account = ctx.account;

View File

@@ -18,8 +18,8 @@ import {
} from "openclaw/plugin-sdk/directory-runtime";
import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
import {
buildComputedAccountStatusSnapshot,
buildChannelConfigSchema,
DEFAULT_ACCOUNT_ID,
createAccountStatusSink,
@@ -207,7 +207,7 @@ export const googlechatPlugin = createChatChannelPlugin({
},
},
actions: googlechatActions,
status: {
status: createComputedAccountStatusAdapter<ResolvedGoogleChatAccount>({
defaultRuntime: {
accountId: DEFAULT_ACCOUNT_ID,
running: false,
@@ -254,26 +254,21 @@ export const googlechatPlugin = createChatChannelPlugin({
}),
probeAccount: async ({ account }) =>
(await loadGoogleChatChannelRuntime()).probeGoogleChat(account),
buildAccountSnapshot: ({ account, runtime, probe }) =>
buildComputedAccountStatusSnapshot(
{
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: account.credentialSource !== "none",
runtime,
probe,
},
{
credentialSource: account.credentialSource,
audienceType: account.config.audienceType,
audience: account.config.audience,
webhookPath: account.config.webhookPath,
webhookUrl: account.config.webhookUrl,
dmPolicy: account.config.dm?.policy ?? "pairing",
},
),
},
resolveAccountSnapshot: ({ account }) => ({
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: account.credentialSource !== "none",
extra: {
credentialSource: account.credentialSource,
audienceType: account.config.audienceType,
audience: account.config.audience,
webhookPath: account.config.webhookPath,
webhookUrl: account.config.webhookUrl,
dmPolicy: account.config.dm?.policy ?? "pairing",
},
}),
}),
gateway: {
startAccount: async (ctx) => {
const account = ctx.account;

View File

@@ -10,8 +10,8 @@ import {
} from "openclaw/plugin-sdk/channel-send-result";
import { createEmptyChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
import { resolveOutboundMediaUrls } from "openclaw/plugin-sdk/reply-payload";
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
import {
buildComputedAccountStatusSnapshot,
buildTokenChannelStatusSummary,
clearAccountEntryFields,
DEFAULT_ACCOUNT_ID,
@@ -323,7 +323,7 @@ export const linePlugin: ChannelPlugin<ResolvedLineAccount> = {
}),
}),
},
status: {
status: createComputedAccountStatusAdapter<ResolvedLineAccount>({
defaultRuntime: {
accountId: DEFAULT_ACCOUNT_ID,
running: false,
@@ -357,26 +357,22 @@ export const linePlugin: ChannelPlugin<ResolvedLineAccount> = {
buildChannelSummary: ({ snapshot }) => buildTokenChannelStatusSummary(snapshot),
probeAccount: async ({ account, timeoutMs }) =>
getLineRuntime().channel.line.probeLineBot(account.channelAccessToken, timeoutMs),
buildAccountSnapshot: ({ account, runtime, probe }) => {
resolveAccountSnapshot: ({ account }) => {
const configured = Boolean(
account.channelAccessToken?.trim() && account.channelSecret?.trim(),
);
return buildComputedAccountStatusSnapshot(
{
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured,
runtime,
probe,
},
{
return {
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured,
extra: {
tokenSource: account.tokenSource,
mode: "webhook",
},
);
};
},
},
}),
gateway: {
startAccount: async (ctx) => {
const account = ctx.account;

View File

@@ -17,6 +17,7 @@ import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-
import { createScopedAccountReplyToModeResolver } from "openclaw/plugin-sdk/conversation-runtime";
import { createChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
import { MattermostConfigSchema } from "./config-schema.js";
import { resolveMattermostGroupRequireMention } from "./group-mentions.js";
import {
@@ -37,7 +38,6 @@ import { sendMessageMattermost } from "./mattermost/send.js";
import { resolveMattermostOpaqueTarget } from "./mattermost/target-resolution.js";
import { looksLikeMattermostTargetId, normalizeMattermostMessagingTarget } from "./normalize.js";
import {
buildComputedAccountStatusSnapshot,
buildChannelConfigSchema,
createAccountStatusSink,
DEFAULT_ACCOUNT_ID,
@@ -420,7 +420,7 @@ export const mattermostPlugin: ChannelPlugin<ResolvedMattermostAccount> = {
}),
}),
},
status: {
status: createComputedAccountStatusAdapter<ResolvedMattermostAccount>({
defaultRuntime: {
accountId: DEFAULT_ACCOUNT_ID,
running: false,
@@ -445,25 +445,20 @@ export const mattermostPlugin: ChannelPlugin<ResolvedMattermostAccount> = {
}
return await probeMattermost(baseUrl, token, timeoutMs);
},
buildAccountSnapshot: ({ account, runtime, probe }) =>
buildComputedAccountStatusSnapshot(
{
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: Boolean(account.botToken && account.baseUrl),
runtime,
probe,
},
{
botTokenSource: account.botTokenSource,
baseUrl: account.baseUrl,
connected: runtime?.connected ?? false,
lastConnectedAt: runtime?.lastConnectedAt ?? null,
lastDisconnect: runtime?.lastDisconnect ?? null,
},
),
},
resolveAccountSnapshot: ({ account, runtime }) => ({
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: Boolean(account.botToken && account.baseUrl),
extra: {
botTokenSource: account.botTokenSource,
baseUrl: account.baseUrl,
connected: runtime?.connected ?? false,
lastConnectedAt: runtime?.lastConnectedAt ?? null,
lastDisconnect: runtime?.lastDisconnect ?? null,
},
}),
}),
gateway: {
startAccount: async (ctx) => {
const account = ctx.account;

View File

@@ -30,6 +30,7 @@ import {
resolveThreadSessionKeys,
type RoutePeer,
} from "openclaw/plugin-sdk/routing";
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
import {
listEnabledSlackAccounts,
resolveSlackAccount,
@@ -50,7 +51,6 @@ import { normalizeAllowListLower } from "./monitor/allow-list.js";
import type { SlackProbe } from "./probe.js";
import { resolveSlackUserAllowlist } from "./resolve-users.js";
import {
buildComputedAccountStatusSnapshot,
DEFAULT_ACCOUNT_ID,
looksLikeSlackTargetId,
normalizeSlackMessagingTarget,
@@ -556,7 +556,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
},
}),
},
status: {
status: createComputedAccountStatusAdapter<ResolvedSlackAccount, SlackProbe>({
defaultRuntime: {
accountId: DEFAULT_ACCOUNT_ID,
running: false,
@@ -605,7 +605,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
}
return { lines, details };
},
buildAccountSnapshot: ({ account, runtime, probe }) => {
resolveAccountSnapshot: ({ account }) => {
const mode = account.config.mode ?? "socket";
const configured =
(mode === "http"
@@ -617,21 +617,17 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
"botTokenStatus",
"appTokenStatus",
])) ?? isSlackPluginAccountConfigured(account);
return buildComputedAccountStatusSnapshot(
{
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured,
runtime,
probe,
},
{
return {
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured,
extra: {
...projectCredentialSnapshotFields(account),
},
);
};
},
},
}),
gateway: {
startAccount: async (ctx) => {
const account = ctx.account;