refactor: dedupe channel extension readers

This commit is contained in:
Peter Steinberger
2026-04-07 07:45:05 +01:00
parent c19f322ff9
commit ce19b6bf6a
18 changed files with 75 additions and 49 deletions

View File

@@ -7,6 +7,7 @@ import {
createChannelNativeOriginTargetResolver,
} from "openclaw/plugin-sdk/approval-native-runtime";
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { listSlackAccountIds } from "./accounts.js";
import { isSlackApprovalAuthorizedSender } from "./approval-auth.js";
import {
@@ -138,7 +139,8 @@ export const slackApprovalCapability = createApproverRestrictedNativeApprovalCap
resolveSlackExecApprovalTarget({ cfg, accountId }),
requireMatchingTurnSourceChannel: true,
resolveSuppressionAccountId: ({ target, request }) =>
target.accountId?.trim() || request.request.turnSourceAccountId?.trim() || undefined,
normalizeOptionalString(target.accountId) ??
normalizeOptionalString(request.request.turnSourceAccountId),
resolveOriginTarget: resolveSlackOriginTarget,
resolveApproverDmTargets: resolveSlackApproverDmTargets,
notifyOriginWhenDmOnly: true,

View File

@@ -28,6 +28,7 @@ import {
createDefaultChannelRuntimeState,
} from "openclaw/plugin-sdk/status-helpers";
import { resolveTargetsWithOptionalToken } from "openclaw/plugin-sdk/target-resolver-runtime";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import {
resolveDefaultSlackAccountId,
resolveSlackAccount,
@@ -97,8 +98,8 @@ function getTokenForOperation(
account: ResolvedSlackAccount,
operation: "read" | "write",
): string | undefined {
const userToken = account.config.userToken?.trim() || undefined;
const botToken = account.botToken?.trim();
const userToken = normalizeOptionalString(account.config.userToken);
const botToken = normalizeOptionalString(account.botToken);
const allowUserWrites = account.config.userTokenReadOnly === false;
if (operation === "read") {
return userToken ?? botToken;

View File

@@ -25,6 +25,7 @@ import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { resolveSlackReplyToMode, type ResolvedSlackAccount } from "../../accounts.js";
import { reactSlackMessage } from "../../actions.js";
import { hasSlackThreadParticipation } from "../../sent-thread-cache.js";
@@ -395,14 +396,14 @@ export async function prepareSlackMessage(params: {
),
];
let resolvedSenderName = message.username?.trim() || undefined;
let resolvedSenderName = normalizeOptionalString(message.username);
const resolveSenderName = async (): Promise<string> => {
if (resolvedSenderName) {
return resolvedSenderName;
}
if (message.user) {
const sender = await ctx.resolveUserName(message.user);
const normalized = sender?.name?.trim();
const normalized = normalizeOptionalString(sender?.name);
if (normalized) {
resolvedSenderName = normalized;
return resolvedSenderName;

View File

@@ -17,6 +17,7 @@ import {
sendPayloadMediaSequenceAndFinalize,
sendTextMediaPayload,
} from "openclaw/plugin-sdk/reply-payload";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { resolveSlackAccount } from "./accounts.js";
import { parseSlackBlocksInput } from "./blocks-input.js";
import { buildSlackInteractiveBlocks, type SlackBlock } from "./blocks-render.js";
@@ -48,9 +49,9 @@ function resolveSlackSendIdentity(identity?: OutboundIdentity): SlackSendIdentit
if (!identity) {
return undefined;
}
const username = identity.name?.trim() || undefined;
const iconUrl = identity.avatarUrl?.trim() || undefined;
const rawEmoji = identity.emoji?.trim();
const username = normalizeOptionalString(identity.name);
const iconUrl = normalizeOptionalString(identity.avatarUrl);
const rawEmoji = normalizeOptionalString(identity.emoji);
const iconEmoji = !iconUrl && rawEmoji && /^:[^:\s]+:$/.test(rawEmoji) ? rawEmoji : undefined;
if (!username && !iconUrl && !iconEmoji) {
return undefined;

View File

@@ -1,4 +1,5 @@
import type { WebClient } from "@slack/web-api";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { createSlackWebClient } from "./client.js";
import {
collectSlackCursorItems,
@@ -74,8 +75,8 @@ async function listSlackUsers(client: WebClient): Promise<SlackUserLookup[]> {
collectPageItems: (res) =>
(res.members ?? [])
.map((member) => {
const id = member.id?.trim();
const name = member.name?.trim();
const id = normalizeOptionalString(member.id);
const name = normalizeOptionalString(member.name);
if (!id || !name) {
return null;
}
@@ -83,9 +84,11 @@ async function listSlackUsers(client: WebClient): Promise<SlackUserLookup[]> {
return {
id,
name,
displayName: profile.display_name?.trim() || undefined,
realName: profile.real_name?.trim() || member.real_name?.trim() || undefined,
email: profile.email?.trim()?.toLowerCase() || undefined,
displayName: normalizeOptionalString(profile.display_name),
realName:
normalizeOptionalString(profile.real_name) ??
normalizeOptionalString(member.real_name),
email: normalizeOptionalString(profile.email)?.toLowerCase(),
deleted: Boolean(member.deleted),
isBot: Boolean(member.is_bot),
isAppUser: Boolean(member.is_app_user),

View File

@@ -16,6 +16,7 @@ import {
type OpenClawConfig,
} from "openclaw/plugin-sdk/setup-runtime";
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { inspectSlackAccount } from "./account-inspect.js";
import { resolveSlackAccount } from "./accounts.js";
import {
@@ -97,10 +98,10 @@ function createSlackTokenCredential(params: {
return {
accountConfigured: Boolean(resolvedValue) || hasConfiguredSecretInput(configuredValue),
hasConfiguredValue: hasConfiguredSecretInput(configuredValue),
resolvedValue: resolvedValue?.trim() || undefined,
resolvedValue: normalizeOptionalString(resolvedValue),
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env[params.preferredEnvVar]?.trim()
? normalizeOptionalString(process.env[params.preferredEnvVar])
: undefined,
};
},

View File

@@ -3,6 +3,7 @@ import type {
ChannelThreadingToolContext,
} from "openclaw/plugin-sdk/channel-contract";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { resolveSlackAccount, resolveSlackReplyToMode } from "./accounts.js";
export function buildSlackThreadingToolContext(params: {
@@ -24,7 +25,7 @@ export function buildSlackThreadingToolContext(params: {
// to NativeChannelId (the raw Slack channel id, e.g. "D…").
const currentChannelId = params.context.To?.startsWith("channel:")
? params.context.To.slice("channel:".length)
: params.context.NativeChannelId?.trim() || undefined;
: normalizeOptionalString(params.context.NativeChannelId);
return {
currentChannelId,
currentThreadTs: threadId != null ? String(threadId) : undefined,