mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 01:31:08 +00:00
refactor: dedupe trim reader aliases
This commit is contained in:
@@ -91,10 +91,6 @@ export function _setComfyFetchGuardForTesting(impl: typeof fetchWithSsrFGuard |
|
||||
comfyFetchGuard = impl ?? fetchWithSsrFGuard;
|
||||
}
|
||||
|
||||
function readConfigString(config: ComfyProviderConfig, key: string): string | undefined {
|
||||
return normalizeOptionalString(config[key]);
|
||||
}
|
||||
|
||||
function readConfigBoolean(config: ComfyProviderConfig, key: string): boolean | undefined {
|
||||
const value = config[key];
|
||||
return typeof value === "boolean" ? value : undefined;
|
||||
@@ -554,9 +550,9 @@ export function isComfyCapabilityConfigured(params: {
|
||||
const capabilityConfig = getComfyCapabilityConfig(config, params.capability);
|
||||
const hasWorkflow = Boolean(
|
||||
resolveComfyWorkflowSource(capabilityConfig).workflow ||
|
||||
readConfigString(capabilityConfig, "workflowPath"),
|
||||
normalizeOptionalString(capabilityConfig.workflowPath),
|
||||
);
|
||||
const hasPromptNode = Boolean(readConfigString(capabilityConfig, "promptNodeId"));
|
||||
const hasPromptNode = Boolean(normalizeOptionalString(capabilityConfig.promptNodeId));
|
||||
if (!hasWorkflow || !hasPromptNode) {
|
||||
return false;
|
||||
}
|
||||
@@ -586,11 +582,11 @@ export async function runComfyWorkflow(params: {
|
||||
const workflow = await loadComfyWorkflow(capabilityConfig);
|
||||
const promptNodeId = getRequiredConfigString(capabilityConfig, "promptNodeId");
|
||||
const promptInputName =
|
||||
readConfigString(capabilityConfig, "promptInputName") ?? DEFAULT_PROMPT_INPUT_NAME;
|
||||
const inputImageNodeId = readConfigString(capabilityConfig, "inputImageNodeId");
|
||||
normalizeOptionalString(capabilityConfig.promptInputName) ?? DEFAULT_PROMPT_INPUT_NAME;
|
||||
const inputImageNodeId = normalizeOptionalString(capabilityConfig.inputImageNodeId);
|
||||
const inputImageInputName =
|
||||
readConfigString(capabilityConfig, "inputImageInputName") ?? DEFAULT_INPUT_IMAGE_INPUT_NAME;
|
||||
const outputNodeId = readConfigString(capabilityConfig, "outputNodeId");
|
||||
normalizeOptionalString(capabilityConfig.inputImageInputName) ?? DEFAULT_INPUT_IMAGE_INPUT_NAME;
|
||||
const outputNodeId = normalizeOptionalString(capabilityConfig.outputNodeId);
|
||||
const pollIntervalMs =
|
||||
readConfigInteger(capabilityConfig, "pollIntervalMs") ?? DEFAULT_POLL_INTERVAL_MS;
|
||||
const timeoutMs =
|
||||
@@ -619,7 +615,7 @@ export async function runComfyWorkflow(params: {
|
||||
|
||||
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } =
|
||||
resolveProviderHttpRequestConfig({
|
||||
baseUrl: readConfigString(capabilityConfig, "baseUrl"),
|
||||
baseUrl: normalizeOptionalString(capabilityConfig.baseUrl),
|
||||
defaultBaseUrl:
|
||||
mode === "cloud" ? DEFAULT_COMFY_CLOUD_BASE_URL : DEFAULT_COMFY_LOCAL_BASE_URL,
|
||||
allowPrivateNetwork:
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
createComputedAccountStatusAdapter,
|
||||
createDefaultChannelRuntimeState,
|
||||
} from "openclaw/plugin-sdk/status-helpers";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { mattermostApprovalAuth } from "./approval-auth.js";
|
||||
import {
|
||||
chunkTextForOutbound,
|
||||
@@ -242,25 +243,18 @@ const mattermostMessageActions: ChannelMessageActionAdapter = {
|
||||
},
|
||||
};
|
||||
|
||||
function readTrimmedString(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
return trimmed || undefined;
|
||||
}
|
||||
|
||||
function parseMattermostReactActionParams(params: Record<string, unknown>): {
|
||||
postId: string;
|
||||
emojiName: string;
|
||||
remove: boolean;
|
||||
} {
|
||||
const postId = readTrimmedString(params.messageId) ?? readTrimmedString(params.postId);
|
||||
const postId =
|
||||
normalizeOptionalString(params.messageId) ?? normalizeOptionalString(params.postId);
|
||||
if (!postId) {
|
||||
throw new Error("Mattermost react requires messageId (post id)");
|
||||
}
|
||||
|
||||
const emojiName = readTrimmedString(params.emoji)?.replace(/^:+|:+$/g, "");
|
||||
const emojiName = normalizeOptionalString(params.emoji)?.replace(/^:+|:+$/g, "");
|
||||
if (!emojiName) {
|
||||
throw new Error("Mattermost react requires emoji");
|
||||
}
|
||||
@@ -273,7 +267,7 @@ function parseMattermostReactActionParams(params: Record<string, unknown>): {
|
||||
}
|
||||
|
||||
function readMattermostReplyToId(params: Record<string, unknown>): string | undefined {
|
||||
return readTrimmedString(params.replyToId) ?? readTrimmedString(params.replyTo);
|
||||
return normalizeOptionalString(params.replyToId) ?? normalizeOptionalString(params.replyTo);
|
||||
}
|
||||
|
||||
export const mattermostPlugin: ChannelPlugin<ResolvedMattermostAccount> = createChatChannelPlugin({
|
||||
|
||||
@@ -7,10 +7,6 @@ import type { EnvelopeFormatOptions } from "../envelope.js";
|
||||
import { formatEnvelopeTimestamp } from "../envelope.js";
|
||||
import type { TemplateContext } from "../templating.js";
|
||||
|
||||
function safeTrim(value: unknown): string | undefined {
|
||||
return normalizeOptionalString(value);
|
||||
}
|
||||
|
||||
function formatConversationTimestamp(
|
||||
value: unknown,
|
||||
envelope?: EnvelopeFormatOptions,
|
||||
@@ -22,9 +18,10 @@ function formatConversationTimestamp(
|
||||
}
|
||||
|
||||
function resolveInboundChannel(ctx: TemplateContext): string | undefined {
|
||||
let channelValue = safeTrim(ctx.OriginatingChannel) ?? safeTrim(ctx.Surface);
|
||||
let channelValue =
|
||||
normalizeOptionalString(ctx.OriginatingChannel) ?? normalizeOptionalString(ctx.Surface);
|
||||
if (!channelValue) {
|
||||
const provider = safeTrim(ctx.Provider);
|
||||
const provider = normalizeOptionalString(ctx.Provider);
|
||||
if (provider !== "webchat" && ctx.Surface !== "webchat") {
|
||||
channelValue = provider;
|
||||
}
|
||||
@@ -47,7 +44,7 @@ function resolveInboundFormattingHints(ctx: TemplateContext):
|
||||
getLoadedChannelPlugin(normalizedChannel)?.agentPrompt ??
|
||||
getBundledChannelPlugin(normalizedChannel)?.agentPrompt;
|
||||
return agentPrompt?.inboundFormattingHints?.({
|
||||
accountId: safeTrim(ctx.AccountId) ?? undefined,
|
||||
accountId: normalizeOptionalString(ctx.AccountId) ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,11 +68,11 @@ export function buildInboundMetaSystemPrompt(
|
||||
|
||||
const payload = {
|
||||
schema: "openclaw.inbound_meta.v1",
|
||||
chat_id: safeTrim(ctx.OriginatingTo),
|
||||
account_id: safeTrim(ctx.AccountId),
|
||||
chat_id: normalizeOptionalString(ctx.OriginatingTo),
|
||||
account_id: normalizeOptionalString(ctx.AccountId),
|
||||
channel: channelValue,
|
||||
provider: safeTrim(ctx.Provider),
|
||||
surface: safeTrim(ctx.Surface),
|
||||
provider: normalizeOptionalString(ctx.Provider),
|
||||
surface: normalizeOptionalString(ctx.Surface),
|
||||
chat_type: chatType ?? (isDirect ? "direct" : undefined),
|
||||
response_format:
|
||||
options?.includeFormattingHints === false ? undefined : resolveInboundFormattingHints(ctx),
|
||||
@@ -108,34 +105,34 @@ export function buildInboundUserContextPrefix(
|
||||
);
|
||||
const shouldIncludeConversationInfo = !isDirect || includeDirectConversationInfo;
|
||||
|
||||
const messageId = safeTrim(ctx.MessageSid);
|
||||
const messageIdFull = safeTrim(ctx.MessageSidFull);
|
||||
const messageId = normalizeOptionalString(ctx.MessageSid);
|
||||
const messageIdFull = normalizeOptionalString(ctx.MessageSidFull);
|
||||
const resolvedMessageId = messageId ?? messageIdFull;
|
||||
const timestampStr = formatConversationTimestamp(ctx.Timestamp, envelope);
|
||||
|
||||
const conversationInfo = {
|
||||
message_id: shouldIncludeConversationInfo ? resolvedMessageId : undefined,
|
||||
reply_to_id: shouldIncludeConversationInfo ? safeTrim(ctx.ReplyToId) : undefined,
|
||||
sender_id: shouldIncludeConversationInfo ? safeTrim(ctx.SenderId) : undefined,
|
||||
conversation_label: isDirect ? undefined : safeTrim(ctx.ConversationLabel),
|
||||
reply_to_id: shouldIncludeConversationInfo ? normalizeOptionalString(ctx.ReplyToId) : undefined,
|
||||
sender_id: shouldIncludeConversationInfo ? normalizeOptionalString(ctx.SenderId) : undefined,
|
||||
conversation_label: isDirect ? undefined : normalizeOptionalString(ctx.ConversationLabel),
|
||||
sender: shouldIncludeConversationInfo
|
||||
? (safeTrim(ctx.SenderName) ??
|
||||
safeTrim(ctx.SenderE164) ??
|
||||
safeTrim(ctx.SenderId) ??
|
||||
safeTrim(ctx.SenderUsername))
|
||||
? (normalizeOptionalString(ctx.SenderName) ??
|
||||
normalizeOptionalString(ctx.SenderE164) ??
|
||||
normalizeOptionalString(ctx.SenderId) ??
|
||||
normalizeOptionalString(ctx.SenderUsername))
|
||||
: undefined,
|
||||
timestamp: timestampStr,
|
||||
group_subject: safeTrim(ctx.GroupSubject),
|
||||
group_channel: safeTrim(ctx.GroupChannel),
|
||||
group_space: safeTrim(ctx.GroupSpace),
|
||||
thread_label: safeTrim(ctx.ThreadLabel),
|
||||
group_subject: normalizeOptionalString(ctx.GroupSubject),
|
||||
group_channel: normalizeOptionalString(ctx.GroupChannel),
|
||||
group_space: normalizeOptionalString(ctx.GroupSpace),
|
||||
thread_label: normalizeOptionalString(ctx.ThreadLabel),
|
||||
topic_id: ctx.MessageThreadId != null ? String(ctx.MessageThreadId) : undefined,
|
||||
is_forum: ctx.IsForum === true ? true : undefined,
|
||||
is_group_chat: !isDirect ? true : undefined,
|
||||
was_mentioned: ctx.WasMentioned === true ? true : undefined,
|
||||
has_reply_context: ctx.ReplyToBody ? true : undefined,
|
||||
has_forwarded_context: ctx.ForwardedFrom ? true : undefined,
|
||||
has_thread_starter: safeTrim(ctx.ThreadStarterBody) ? true : undefined,
|
||||
has_thread_starter: normalizeOptionalString(ctx.ThreadStarterBody) ? true : undefined,
|
||||
history_count:
|
||||
Array.isArray(ctx.InboundHistory) && ctx.InboundHistory.length > 0
|
||||
? ctx.InboundHistory.length
|
||||
@@ -154,17 +151,17 @@ export function buildInboundUserContextPrefix(
|
||||
|
||||
const senderInfo = {
|
||||
label: resolveSenderLabel({
|
||||
name: safeTrim(ctx.SenderName),
|
||||
username: safeTrim(ctx.SenderUsername),
|
||||
tag: safeTrim(ctx.SenderTag),
|
||||
e164: safeTrim(ctx.SenderE164),
|
||||
id: safeTrim(ctx.SenderId),
|
||||
name: normalizeOptionalString(ctx.SenderName),
|
||||
username: normalizeOptionalString(ctx.SenderUsername),
|
||||
tag: normalizeOptionalString(ctx.SenderTag),
|
||||
e164: normalizeOptionalString(ctx.SenderE164),
|
||||
id: normalizeOptionalString(ctx.SenderId),
|
||||
}),
|
||||
id: safeTrim(ctx.SenderId),
|
||||
name: safeTrim(ctx.SenderName),
|
||||
username: safeTrim(ctx.SenderUsername),
|
||||
tag: safeTrim(ctx.SenderTag),
|
||||
e164: safeTrim(ctx.SenderE164),
|
||||
id: normalizeOptionalString(ctx.SenderId),
|
||||
name: normalizeOptionalString(ctx.SenderName),
|
||||
username: normalizeOptionalString(ctx.SenderUsername),
|
||||
tag: normalizeOptionalString(ctx.SenderTag),
|
||||
e164: normalizeOptionalString(ctx.SenderE164),
|
||||
};
|
||||
if (senderInfo?.label) {
|
||||
blocks.push(
|
||||
@@ -174,7 +171,7 @@ export function buildInboundUserContextPrefix(
|
||||
);
|
||||
}
|
||||
|
||||
if (safeTrim(ctx.ThreadStarterBody)) {
|
||||
if (normalizeOptionalString(ctx.ThreadStarterBody)) {
|
||||
blocks.push(
|
||||
[
|
||||
"Thread starter (untrusted, for context):",
|
||||
@@ -192,7 +189,7 @@ export function buildInboundUserContextPrefix(
|
||||
"```json",
|
||||
JSON.stringify(
|
||||
{
|
||||
sender_label: safeTrim(ctx.ReplyToSender),
|
||||
sender_label: normalizeOptionalString(ctx.ReplyToSender),
|
||||
is_quote: ctx.ReplyToIsQuote === true ? true : undefined,
|
||||
body: ctx.ReplyToBody,
|
||||
},
|
||||
@@ -211,12 +208,12 @@ export function buildInboundUserContextPrefix(
|
||||
"```json",
|
||||
JSON.stringify(
|
||||
{
|
||||
from: safeTrim(ctx.ForwardedFrom),
|
||||
type: safeTrim(ctx.ForwardedFromType),
|
||||
username: safeTrim(ctx.ForwardedFromUsername),
|
||||
title: safeTrim(ctx.ForwardedFromTitle),
|
||||
signature: safeTrim(ctx.ForwardedFromSignature),
|
||||
chat_type: safeTrim(ctx.ForwardedFromChatType),
|
||||
from: normalizeOptionalString(ctx.ForwardedFrom),
|
||||
type: normalizeOptionalString(ctx.ForwardedFromType),
|
||||
username: normalizeOptionalString(ctx.ForwardedFromUsername),
|
||||
title: normalizeOptionalString(ctx.ForwardedFromTitle),
|
||||
signature: normalizeOptionalString(ctx.ForwardedFromSignature),
|
||||
chat_type: normalizeOptionalString(ctx.ForwardedFromChatType),
|
||||
date_ms: typeof ctx.ForwardedDate === "number" ? ctx.ForwardedDate : undefined,
|
||||
},
|
||||
null,
|
||||
|
||||
@@ -17,10 +17,6 @@ const CREDENTIAL_STATUS_KEYS = [
|
||||
|
||||
type CredentialStatusKey = (typeof CREDENTIAL_STATUS_KEYS)[number];
|
||||
|
||||
function readTrimmedString(record: Record<string, unknown>, key: string): string | undefined {
|
||||
return normalizeOptionalString(record[key]);
|
||||
}
|
||||
|
||||
function readBoolean(record: Record<string, unknown>, key: string): boolean | undefined {
|
||||
return typeof record[key] === "boolean" ? record[key] : undefined;
|
||||
}
|
||||
@@ -130,20 +126,16 @@ export function projectCredentialSnapshotFields(
|
||||
if (!record) {
|
||||
return {};
|
||||
}
|
||||
const tokenSource = normalizeOptionalString(record.tokenSource);
|
||||
const botTokenSource = normalizeOptionalString(record.botTokenSource);
|
||||
const appTokenSource = normalizeOptionalString(record.appTokenSource);
|
||||
const signingSecretSource = normalizeOptionalString(record.signingSecretSource);
|
||||
|
||||
return {
|
||||
...(readTrimmedString(record, "tokenSource")
|
||||
? { tokenSource: readTrimmedString(record, "tokenSource") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "botTokenSource")
|
||||
? { botTokenSource: readTrimmedString(record, "botTokenSource") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "appTokenSource")
|
||||
? { appTokenSource: readTrimmedString(record, "appTokenSource") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "signingSecretSource")
|
||||
? { signingSecretSource: readTrimmedString(record, "signingSecretSource") }
|
||||
: {}),
|
||||
...(tokenSource ? { tokenSource } : {}),
|
||||
...(botTokenSource ? { botTokenSource } : {}),
|
||||
...(appTokenSource ? { appTokenSource } : {}),
|
||||
...(signingSecretSource ? { signingSecretSource } : {}),
|
||||
...(readCredentialStatus(record, "tokenStatus")
|
||||
? { tokenStatus: readCredentialStatus(record, "tokenStatus") }
|
||||
: {}),
|
||||
@@ -169,9 +161,16 @@ export function projectSafeChannelAccountSnapshotFields(
|
||||
if (!record) {
|
||||
return {};
|
||||
}
|
||||
const name = normalizeOptionalString(record.name);
|
||||
const healthState = normalizeOptionalString(record.healthState);
|
||||
const mode = normalizeOptionalString(record.mode);
|
||||
const dmPolicy = normalizeOptionalString(record.dmPolicy);
|
||||
const baseUrl = normalizeOptionalString(record.baseUrl);
|
||||
const cliPath = normalizeOptionalString(record.cliPath);
|
||||
const dbPath = normalizeOptionalString(record.dbPath);
|
||||
|
||||
return {
|
||||
...(readTrimmedString(record, "name") ? { name: readTrimmedString(record, "name") } : {}),
|
||||
...(name ? { name } : {}),
|
||||
...(readBoolean(record, "linked") !== undefined
|
||||
? { linked: readBoolean(record, "linked") }
|
||||
: {}),
|
||||
@@ -187,27 +186,19 @@ export function projectSafeChannelAccountSnapshotFields(
|
||||
...(readNumber(record, "lastInboundAt") !== undefined
|
||||
? { lastInboundAt: readNumber(record, "lastInboundAt") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "healthState")
|
||||
? { healthState: readTrimmedString(record, "healthState") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "mode") ? { mode: readTrimmedString(record, "mode") } : {}),
|
||||
...(readTrimmedString(record, "dmPolicy")
|
||||
? { dmPolicy: readTrimmedString(record, "dmPolicy") }
|
||||
: {}),
|
||||
...(healthState ? { healthState } : {}),
|
||||
...(mode ? { mode } : {}),
|
||||
...(dmPolicy ? { dmPolicy } : {}),
|
||||
...(readStringArray(record, "allowFrom")
|
||||
? { allowFrom: readStringArray(record, "allowFrom") }
|
||||
: {}),
|
||||
...projectCredentialSnapshotFields(account),
|
||||
...(readTrimmedString(record, "baseUrl")
|
||||
? { baseUrl: stripUrlUserInfo(readTrimmedString(record, "baseUrl")!) }
|
||||
: {}),
|
||||
...(baseUrl ? { baseUrl: stripUrlUserInfo(baseUrl) } : {}),
|
||||
...(readBoolean(record, "allowUnmentionedGroups") !== undefined
|
||||
? { allowUnmentionedGroups: readBoolean(record, "allowUnmentionedGroups") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "cliPath")
|
||||
? { cliPath: readTrimmedString(record, "cliPath") }
|
||||
: {}),
|
||||
...(readTrimmedString(record, "dbPath") ? { dbPath: readTrimmedString(record, "dbPath") } : {}),
|
||||
...(cliPath ? { cliPath } : {}),
|
||||
...(dbPath ? { dbPath } : {}),
|
||||
...(readNumber(record, "port") !== undefined ? { port: readNumber(record, "port") } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,16 +75,16 @@ export function applyExistingCronSchedulePatch(
|
||||
}
|
||||
|
||||
function normalizeScheduleOptions(options: ScheduleOptionInput): NormalizedScheduleOptions {
|
||||
const staggerRaw = readTrimmedString(options.stagger);
|
||||
const staggerRaw = normalizeOptionalString(options.stagger) ?? "";
|
||||
const useExact = Boolean(options.exact);
|
||||
if (staggerRaw && useExact) {
|
||||
throw new Error("Choose either --stagger or --exact, not both");
|
||||
}
|
||||
return {
|
||||
at: readTrimmedString(options.at),
|
||||
every: readTrimmedString(options.every),
|
||||
cronExpr: readTrimmedString(options.cron),
|
||||
tz: readOptionalString(options.tz),
|
||||
at: normalizeOptionalString(options.at) ?? "",
|
||||
every: normalizeOptionalString(options.every) ?? "",
|
||||
cronExpr: normalizeOptionalString(options.cron) ?? "",
|
||||
tz: normalizeOptionalString(options.tz),
|
||||
requestedStaggerMs: parseCronStaggerMs({ staggerRaw, useExact }),
|
||||
};
|
||||
}
|
||||
@@ -125,11 +125,3 @@ function resolveDirectSchedule(options: NormalizedScheduleOptions): CronSchedule
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function readOptionalString(value: unknown): string | undefined {
|
||||
return normalizeOptionalString(value);
|
||||
}
|
||||
|
||||
function readTrimmedString(value: unknown): string {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import os from "node:os";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type OsSummary = {
|
||||
platform: NodeJS.Platform;
|
||||
@@ -8,13 +9,9 @@ export type OsSummary = {
|
||||
label: string;
|
||||
};
|
||||
|
||||
function safeTrim(value: unknown): string {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
function macosVersion(): string {
|
||||
const res = spawnSync("sw_vers", ["-productVersion"], { encoding: "utf-8" });
|
||||
const out = safeTrim(res.stdout);
|
||||
const out = normalizeOptionalString(res.stdout) ?? "";
|
||||
return out || os.release();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,8 @@ export type InteractiveReply = {
|
||||
blocks: InteractiveReplyBlock[];
|
||||
};
|
||||
|
||||
function readTrimmedString(value: unknown): string | undefined {
|
||||
return normalizeOptionalString(value);
|
||||
}
|
||||
|
||||
function normalizeButtonStyle(value: unknown): InteractiveButtonStyle | undefined {
|
||||
const style = readTrimmedString(value)?.toLowerCase();
|
||||
const style = normalizeOptionalString(value)?.toLowerCase();
|
||||
return style === "primary" || style === "secondary" || style === "success" || style === "danger"
|
||||
? style
|
||||
: undefined;
|
||||
@@ -54,11 +50,11 @@ function normalizeInteractiveButton(raw: unknown): InteractiveReplyButton | unde
|
||||
return undefined;
|
||||
}
|
||||
const record = raw as Record<string, unknown>;
|
||||
const label = readTrimmedString(record.label) ?? readTrimmedString(record.text);
|
||||
const label = normalizeOptionalString(record.label) ?? normalizeOptionalString(record.text);
|
||||
const value =
|
||||
readTrimmedString(record.value) ??
|
||||
readTrimmedString(record.callbackData) ??
|
||||
readTrimmedString(record.callback_data);
|
||||
normalizeOptionalString(record.value) ??
|
||||
normalizeOptionalString(record.callbackData) ??
|
||||
normalizeOptionalString(record.callback_data);
|
||||
if (!label || !value) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -74,8 +70,8 @@ function normalizeInteractiveOption(raw: unknown): InteractiveReplyOption | unde
|
||||
return undefined;
|
||||
}
|
||||
const record = raw as Record<string, unknown>;
|
||||
const label = readTrimmedString(record.label) ?? readTrimmedString(record.text);
|
||||
const value = readTrimmedString(record.value);
|
||||
const label = normalizeOptionalString(record.label) ?? normalizeOptionalString(record.text);
|
||||
const value = normalizeOptionalString(record.value);
|
||||
if (!label || !value) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -87,9 +83,9 @@ function normalizeInteractiveBlock(raw: unknown): InteractiveReplyBlock | undefi
|
||||
return undefined;
|
||||
}
|
||||
const record = raw as Record<string, unknown>;
|
||||
const type = readTrimmedString(record.type)?.toLowerCase();
|
||||
const type = normalizeOptionalString(record.type)?.toLowerCase();
|
||||
if (type === "text") {
|
||||
const text = readTrimmedString(record.text);
|
||||
const text = normalizeOptionalString(record.text);
|
||||
return text ? { type: "text", text } : undefined;
|
||||
}
|
||||
if (type === "buttons") {
|
||||
@@ -109,7 +105,7 @@ function normalizeInteractiveBlock(raw: unknown): InteractiveReplyBlock | undefi
|
||||
return options.length > 0
|
||||
? {
|
||||
type: "select",
|
||||
placeholder: readTrimmedString(record.placeholder),
|
||||
placeholder: normalizeOptionalString(record.placeholder),
|
||||
options,
|
||||
}
|
||||
: undefined;
|
||||
@@ -148,10 +144,12 @@ export function hasReplyContent(params: {
|
||||
hasChannelData?: boolean;
|
||||
extraContent?: boolean;
|
||||
}): boolean {
|
||||
const text = normalizeOptionalString(params.text);
|
||||
const mediaUrl = normalizeOptionalString(params.mediaUrl);
|
||||
return Boolean(
|
||||
params.text?.trim() ||
|
||||
params.mediaUrl?.trim() ||
|
||||
params.mediaUrls?.some((entry) => Boolean(entry?.trim())) ||
|
||||
text ||
|
||||
mediaUrl ||
|
||||
params.mediaUrls?.some((entry) => Boolean(normalizeOptionalString(entry))) ||
|
||||
hasInteractiveReplyBlocks(params.interactive) ||
|
||||
params.hasChannelData ||
|
||||
params.extraContent,
|
||||
@@ -186,7 +184,7 @@ export function resolveInteractiveTextFallback(params: {
|
||||
text?: string;
|
||||
interactive?: InteractiveReply;
|
||||
}): string | undefined {
|
||||
const text = readTrimmedString(params.text);
|
||||
const text = normalizeOptionalString(params.text);
|
||||
if (text) {
|
||||
return params.text;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,8 @@ import { getBootstrapChannelPlugin } from "../channels/plugins/bootstrap-registr
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
function normalizeChannelId(value?: string | null): string | undefined {
|
||||
return normalizeOptionalString(value)?.toLowerCase();
|
||||
}
|
||||
|
||||
function findChannelMessagingAdapter(channelId?: string | null) {
|
||||
const normalized = normalizeChannelId(channelId);
|
||||
const normalized = normalizeOptionalString(channelId)?.toLowerCase();
|
||||
if (!normalized) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user