mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
refactor: dedupe channel helper readers
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type ChatType = "direct" | "group" | "channel";
|
||||
|
||||
export function normalizeChatType(raw?: string): ChatType | undefined {
|
||||
const value = raw?.trim().toLowerCase();
|
||||
const value = normalizeOptionalString(raw)?.toLowerCase();
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { listChannelCatalogEntries } from "../plugins/channel-catalog-registry.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type ChatChannelId = string;
|
||||
|
||||
@@ -9,8 +10,7 @@ type BundledChatChannelEntry = {
|
||||
};
|
||||
|
||||
function normalizeChannelKey(raw?: string | null): string | undefined {
|
||||
const normalized = raw?.trim().toLowerCase();
|
||||
return normalized || undefined;
|
||||
return normalizeOptionalString(raw)?.toLowerCase();
|
||||
}
|
||||
|
||||
function listBundledChatChannelEntries(): BundledChatChannelEntry[] {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
type InboundDebounceCreateParams,
|
||||
} from "../auto-reply/inbound-debounce.js";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export function shouldDebounceTextInbound(params: {
|
||||
text: string | null | undefined;
|
||||
@@ -20,7 +21,7 @@ export function shouldDebounceTextInbound(params: {
|
||||
if (params.hasMedia) {
|
||||
return false;
|
||||
}
|
||||
const text = params.text?.trim() ?? "";
|
||||
const text = normalizeOptionalString(params.text) ?? "";
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getActivePluginChannelRegistry, getActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { getChatChannelMeta, listChatChannels, type ChatChannelMeta } from "./chat-meta.js";
|
||||
import {
|
||||
CHANNEL_IDS,
|
||||
@@ -31,14 +32,12 @@ function findRegisteredChannelPluginEntry(
|
||||
normalizedKey: string,
|
||||
): RegisteredChannelPluginEntry | undefined {
|
||||
return listRegisteredChannelPluginEntries().find((entry) => {
|
||||
const id = String(entry.plugin.id ?? "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
const id = normalizeOptionalString(String(entry.plugin.id ?? ""))?.toLowerCase() ?? "";
|
||||
if (id && id === normalizedKey) {
|
||||
return true;
|
||||
}
|
||||
return (entry.plugin.meta?.aliases ?? []).some(
|
||||
(alias) => alias.trim().toLowerCase() === normalizedKey,
|
||||
(alias) => normalizeOptionalString(alias)?.toLowerCase() === normalizedKey,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -56,8 +55,7 @@ function findRegisteredChannelPluginEntryById(
|
||||
}
|
||||
|
||||
const normalizeChannelKey = (raw?: string | null): string | undefined => {
|
||||
const normalized = raw?.trim().toLowerCase();
|
||||
return normalized || undefined;
|
||||
return normalizeOptionalString(raw)?.toLowerCase();
|
||||
};
|
||||
export {
|
||||
CHAT_CHANNEL_ALIASES,
|
||||
@@ -87,7 +85,7 @@ export function normalizeAnyChannelId(raw?: string | null): ChannelId | null {
|
||||
|
||||
export function listRegisteredChannelPluginIds(): ChannelId[] {
|
||||
return listRegisteredChannelPluginEntries().flatMap((entry) => {
|
||||
const id = entry.plugin.id?.trim();
|
||||
const id = normalizeOptionalString(entry.plugin.id);
|
||||
return id ? [id as ChannelId] : [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { MsgContext } from "../auto-reply/templating.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { normalizeChatType } from "./chat-type.js";
|
||||
|
||||
export function validateSenderIdentity(ctx: MsgContext): string[] {
|
||||
@@ -7,10 +8,10 @@ export function validateSenderIdentity(ctx: MsgContext): string[] {
|
||||
const chatType = normalizeChatType(ctx.ChatType);
|
||||
const isDirect = chatType === "direct";
|
||||
|
||||
const senderId = ctx.SenderId?.trim() || "";
|
||||
const senderName = ctx.SenderName?.trim() || "";
|
||||
const senderUsername = ctx.SenderUsername?.trim() || "";
|
||||
const senderE164 = ctx.SenderE164?.trim() || "";
|
||||
const senderId = normalizeOptionalString(ctx.SenderId) || "";
|
||||
const senderName = normalizeOptionalString(ctx.SenderName) || "";
|
||||
const senderUsername = normalizeOptionalString(ctx.SenderUsername) || "";
|
||||
const senderE164 = normalizeOptionalString(ctx.SenderE164) || "";
|
||||
|
||||
if (!isDirect) {
|
||||
if (!senderId && !senderName && !senderUsername && !senderE164) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type SenderLabelParams = {
|
||||
name?: string;
|
||||
username?: string;
|
||||
@@ -7,8 +9,7 @@ export type SenderLabelParams = {
|
||||
};
|
||||
|
||||
function normalize(value?: string): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
return normalizeOptionalString(value);
|
||||
}
|
||||
|
||||
function normalizeSenderLabelParams(params: SenderLabelParams) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
/**
|
||||
* Channel-agnostic status reaction controller.
|
||||
* Provides a unified interface for displaying agent status via message reactions.
|
||||
@@ -102,7 +104,7 @@ export function resolveToolEmoji(
|
||||
toolName: string | undefined,
|
||||
emojis: Required<StatusReactionEmojis>,
|
||||
): string {
|
||||
const normalized = toolName?.trim().toLowerCase() ?? "";
|
||||
const normalized = normalizeOptionalString(toolName)?.toLowerCase() ?? "";
|
||||
if (!normalized) {
|
||||
return emojis.tool;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export function resolveThreadBindingConversationIdFromBindingId(params: {
|
||||
accountId: string;
|
||||
bindingId?: string;
|
||||
}): string | undefined {
|
||||
const bindingId = params.bindingId?.trim();
|
||||
const bindingId = normalizeOptionalString(params.bindingId);
|
||||
if (!bindingId) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -10,6 +12,6 @@ export function resolveThreadBindingConversationIdFromBindingId(params: {
|
||||
if (!bindingId.startsWith(prefix)) {
|
||||
return undefined;
|
||||
}
|
||||
const conversationId = bindingId.slice(prefix.length).trim();
|
||||
const conversationId = normalizeOptionalString(bindingId.slice(prefix.length));
|
||||
return conversationId || undefined;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { prefixSystemMessage } from "../infra/system-message.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
const DEFAULT_THREAD_BINDING_FAREWELL_TEXT =
|
||||
"Session ended. Messages here will no longer be routed.";
|
||||
@@ -32,8 +33,8 @@ export function resolveThreadBindingThreadName(params: {
|
||||
agentId?: string;
|
||||
label?: string;
|
||||
}): string {
|
||||
const label = params.label?.trim();
|
||||
const base = label || params.agentId?.trim() || "agent";
|
||||
const label = normalizeOptionalString(params.label);
|
||||
const base = label || normalizeOptionalString(params.agentId) || "agent";
|
||||
const raw = `🤖 ${base}`.replace(/\s+/g, " ").trim();
|
||||
return raw.slice(0, 100);
|
||||
}
|
||||
@@ -46,12 +47,12 @@ export function resolveThreadBindingIntroText(params: {
|
||||
sessionCwd?: string;
|
||||
sessionDetails?: string[];
|
||||
}): string {
|
||||
const label = params.label?.trim();
|
||||
const base = label || params.agentId?.trim() || "agent";
|
||||
const label = normalizeOptionalString(params.label);
|
||||
const base = label || normalizeOptionalString(params.agentId) || "agent";
|
||||
const normalized = base.replace(/\s+/g, " ").trim().slice(0, 100) || "agent";
|
||||
const idleTimeoutMs = normalizeThreadBindingDurationMs(params.idleTimeoutMs);
|
||||
const maxAgeMs = normalizeThreadBindingDurationMs(params.maxAgeMs);
|
||||
const cwd = params.sessionCwd?.trim();
|
||||
const cwd = normalizeOptionalString(params.sessionCwd);
|
||||
const details = (params.sessionDetails ?? [])
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => entry.length > 0);
|
||||
@@ -86,7 +87,7 @@ export function resolveThreadBindingFarewellText(params: {
|
||||
idleTimeoutMs: number;
|
||||
maxAgeMs: number;
|
||||
}): string {
|
||||
const custom = params.farewellText?.trim();
|
||||
const custom = normalizeOptionalString(params.farewellText);
|
||||
if (custom) {
|
||||
return prefixSystemMessage(custom);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { normalizeChatType } from "../channels/chat-type.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { SessionChatType, SessionEntry } from "../config/sessions.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type SessionSendPolicyDecision = "allow" | "deny";
|
||||
|
||||
export function normalizeSendPolicy(raw?: string | null): SessionSendPolicyDecision | undefined {
|
||||
const value = raw?.trim().toLowerCase();
|
||||
const value = normalizeOptionalString(raw)?.toLowerCase();
|
||||
if (value === "allow") {
|
||||
return "allow";
|
||||
}
|
||||
@@ -16,7 +17,7 @@ export function normalizeSendPolicy(raw?: string | null): SessionSendPolicyDecis
|
||||
}
|
||||
|
||||
function normalizeMatchValue(raw?: string | null) {
|
||||
const value = raw?.trim().toLowerCase();
|
||||
const value = normalizeOptionalString(raw)?.toLowerCase();
|
||||
return value ? value : undefined;
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ function deriveChannelFromKey(key?: string) {
|
||||
}
|
||||
|
||||
function deriveChatTypeFromKey(key?: string): SessionChatType | undefined {
|
||||
const normalizedKey = stripAgentSessionKeyPrefix(key)?.trim().toLowerCase();
|
||||
const normalizedKey = normalizeOptionalString(stripAgentSessionKeyPrefix(key))?.toLowerCase();
|
||||
if (!normalizedKey) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type ParsedAgentSessionKey = {
|
||||
agentId: string;
|
||||
rest: string;
|
||||
@@ -22,7 +24,7 @@ export type RawSessionConversationRef = {
|
||||
export function parseAgentSessionKey(
|
||||
sessionKey: string | undefined | null,
|
||||
): ParsedAgentSessionKey | null {
|
||||
const raw = (sessionKey ?? "").trim().toLowerCase();
|
||||
const raw = normalizeOptionalString(sessionKey)?.toLowerCase();
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
@@ -33,7 +35,7 @@ export function parseAgentSessionKey(
|
||||
if (parts[0] !== "agent") {
|
||||
return null;
|
||||
}
|
||||
const agentId = parts[1]?.trim();
|
||||
const agentId = normalizeOptionalString(parts[1]);
|
||||
const rest = parts.slice(2).join(":");
|
||||
if (!agentId || !rest) {
|
||||
return null;
|
||||
@@ -58,7 +60,7 @@ export function isCronSessionKey(sessionKey: string | undefined | null): boolean
|
||||
}
|
||||
|
||||
export function isSubagentSessionKey(sessionKey: string | undefined | null): boolean {
|
||||
const raw = (sessionKey ?? "").trim();
|
||||
const raw = normalizeOptionalString(sessionKey);
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
@@ -70,7 +72,7 @@ export function isSubagentSessionKey(sessionKey: string | undefined | null): boo
|
||||
}
|
||||
|
||||
export function getSubagentDepth(sessionKey: string | undefined | null): number {
|
||||
const raw = (sessionKey ?? "").trim().toLowerCase();
|
||||
const raw = normalizeOptionalString(sessionKey)?.toLowerCase();
|
||||
if (!raw) {
|
||||
return 0;
|
||||
}
|
||||
@@ -78,7 +80,7 @@ export function getSubagentDepth(sessionKey: string | undefined | null): number
|
||||
}
|
||||
|
||||
export function isAcpSessionKey(sessionKey: string | undefined | null): boolean {
|
||||
const raw = (sessionKey ?? "").trim();
|
||||
const raw = normalizeOptionalString(sessionKey);
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
@@ -91,14 +93,13 @@ export function isAcpSessionKey(sessionKey: string | undefined | null): boolean
|
||||
}
|
||||
|
||||
function normalizeSessionConversationChannel(value: string | undefined | null): string | undefined {
|
||||
const trimmed = (value ?? "").trim().toLowerCase();
|
||||
return trimmed || undefined;
|
||||
return normalizeOptionalString(value)?.toLowerCase();
|
||||
}
|
||||
|
||||
export function parseThreadSessionSuffix(
|
||||
sessionKey: string | undefined | null,
|
||||
): ParsedThreadSessionSuffix {
|
||||
const raw = (sessionKey ?? "").trim();
|
||||
const raw = normalizeOptionalString(sessionKey);
|
||||
if (!raw) {
|
||||
return { baseSessionKey: undefined, threadId: undefined };
|
||||
}
|
||||
@@ -111,7 +112,7 @@ export function parseThreadSessionSuffix(
|
||||
|
||||
const baseSessionKey = markerIndex === -1 ? raw : raw.slice(0, markerIndex);
|
||||
const threadIdRaw = markerIndex === -1 ? undefined : raw.slice(markerIndex + marker.length);
|
||||
const threadId = threadIdRaw?.trim() || undefined;
|
||||
const threadId = normalizeOptionalString(threadIdRaw);
|
||||
|
||||
return { baseSessionKey, threadId };
|
||||
}
|
||||
@@ -119,30 +120,27 @@ export function parseThreadSessionSuffix(
|
||||
export function parseRawSessionConversationRef(
|
||||
sessionKey: string | undefined | null,
|
||||
): RawSessionConversationRef | null {
|
||||
const raw = (sessionKey ?? "").trim();
|
||||
const raw = normalizeOptionalString(sessionKey);
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawParts = raw.split(":").filter(Boolean);
|
||||
const bodyStartIndex =
|
||||
rawParts.length >= 3 && rawParts[0]?.trim().toLowerCase() === "agent" ? 2 : 0;
|
||||
rawParts.length >= 3 && normalizeOptionalString(rawParts[0])?.toLowerCase() === "agent" ? 2 : 0;
|
||||
const parts = rawParts.slice(bodyStartIndex);
|
||||
if (parts.length < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const channel = normalizeSessionConversationChannel(parts[0]);
|
||||
const kind = parts[1]?.trim().toLowerCase();
|
||||
const kind = normalizeOptionalString(parts[1])?.toLowerCase();
|
||||
if (!channel || (kind !== "group" && kind !== "channel")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawId = parts.slice(2).join(":").trim();
|
||||
const prefix = rawParts
|
||||
.slice(0, bodyStartIndex + 2)
|
||||
.join(":")
|
||||
.trim();
|
||||
const rawId = normalizeOptionalString(parts.slice(2).join(":"));
|
||||
const prefix = normalizeOptionalString(rawParts.slice(0, bodyStartIndex + 2).join(":"));
|
||||
if (!rawId || !prefix) {
|
||||
return null;
|
||||
}
|
||||
@@ -157,7 +155,7 @@ export function resolveThreadParentSessionKey(
|
||||
if (!threadId) {
|
||||
return null;
|
||||
}
|
||||
const parent = baseSessionKey?.trim();
|
||||
const parent = normalizeOptionalString(baseSessionKey);
|
||||
if (!parent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type SessionTranscriptUpdate = {
|
||||
sessionFile: string;
|
||||
sessionKey?: string;
|
||||
@@ -26,18 +28,18 @@ export function emitSessionTranscriptUpdate(update: string | SessionTranscriptUp
|
||||
message: update.message,
|
||||
messageId: update.messageId,
|
||||
};
|
||||
const trimmed = normalized.sessionFile.trim();
|
||||
const trimmed = normalizeOptionalString(normalized.sessionFile);
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
const nextUpdate: SessionTranscriptUpdate = {
|
||||
sessionFile: trimmed,
|
||||
...(typeof normalized.sessionKey === "string" && normalized.sessionKey.trim()
|
||||
? { sessionKey: normalized.sessionKey.trim() }
|
||||
...(normalizeOptionalString(normalized.sessionKey)
|
||||
? { sessionKey: normalizeOptionalString(normalized.sessionKey) }
|
||||
: {}),
|
||||
...(normalized.message !== undefined ? { message: normalized.message } : {}),
|
||||
...(typeof normalized.messageId === "string" && normalized.messageId.trim()
|
||||
? { messageId: normalized.messageId.trim() }
|
||||
...(normalizeOptionalString(normalized.messageId)
|
||||
? { messageId: normalizeOptionalString(normalized.messageId) }
|
||||
: {}),
|
||||
};
|
||||
for (const listener of SESSION_TRANSCRIPT_LISTENERS) {
|
||||
|
||||
Reference in New Issue
Block a user