mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-21 13:44:03 +00:00
refactor: dedupe reply helper readers
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
setConfigOverride,
|
||||
unsetConfigOverride,
|
||||
} from "../../config/runtime-overrides.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { isInternalMessageChannel } from "../../utils/message-channel.js";
|
||||
import { resolveChannelAccountId } from "./channel-context.js";
|
||||
import {
|
||||
@@ -115,7 +116,7 @@ export const handleConfigCommand: CommandHandler = async (params, allowTextComma
|
||||
const parsedBase = structuredClone(snapshot.parsed as Record<string, unknown>);
|
||||
|
||||
if (configCommand.action === "show") {
|
||||
const pathRaw = configCommand.path?.trim();
|
||||
const pathRaw = normalizeOptionalString(configCommand.path);
|
||||
if (pathRaw) {
|
||||
const parsedPath = parseConfigPath(pathRaw);
|
||||
if (!parsedPath.ok || !parsedPath.path) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { getChannelPlugin } from "../../channels/plugins/index.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import type { ReplyPayload } from "../types.js";
|
||||
import { rejectUnauthorizedCommand } from "./command-gates.js";
|
||||
import type { CommandHandler } from "./commands-types.js";
|
||||
@@ -62,7 +63,7 @@ export async function buildModelsProviderData(
|
||||
};
|
||||
|
||||
const addRawModelRef = (raw?: string) => {
|
||||
const trimmed = raw?.trim();
|
||||
const trimmed = normalizeOptionalString(raw);
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
@@ -143,7 +144,7 @@ function parseModelsArgs(raw: string): {
|
||||
}
|
||||
|
||||
const tokens = trimmed.split(/\s+/g).filter(Boolean);
|
||||
const provider = tokens[0]?.trim();
|
||||
const provider = normalizeOptionalString(tokens[0]);
|
||||
|
||||
let page = 1;
|
||||
let all = false;
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
resolveUsageProviderId,
|
||||
} from "../../infra/provider-usage.js";
|
||||
import type { MediaUnderstandingDecision } from "../../media-understanding/types.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
listTasksForAgentIdForStatus,
|
||||
listTasksForSessionKeyForStatus,
|
||||
@@ -59,7 +60,7 @@ function shouldLoadUsageSummary(params: {
|
||||
if (!USAGE_OAUTH_ONLY_PROVIDERS.has(params.provider)) {
|
||||
return true;
|
||||
}
|
||||
const auth = params.selectedModelAuth?.trim().toLowerCase();
|
||||
const auth = normalizeOptionalString(params.selectedModelAuth)?.toLowerCase();
|
||||
return Boolean(auth?.startsWith("oauth") || auth?.startsWith("token"));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { countPendingDescendantRunsFromRuns } from "../../../agents/subagent-reg
|
||||
import { getSubagentRunsSnapshotForRead } from "../../../agents/subagent-registry-state.js";
|
||||
import { getChannelPlugin, normalizeChannelId } from "../../../channels/plugins/index.js";
|
||||
import { getSessionBindingService } from "../../../infra/outbound/session-binding-service.js";
|
||||
import { normalizeOptionalString } from "../../../shared/string-coerce.js";
|
||||
import type { CommandHandlerResult } from "../commands-types.js";
|
||||
import { formatRunLabel, sortSubagentRuns } from "../subagents-utils.js";
|
||||
import {
|
||||
@@ -118,10 +119,7 @@ export function handleSubagentsAgentsAction(ctx: SubagentsCommandContext): Comma
|
||||
if (requesterBindings.length > 0) {
|
||||
lines.push("", "acp/session bindings:", "-----");
|
||||
for (const binding of requesterBindings) {
|
||||
const label =
|
||||
typeof binding.metadata?.label === "string" && binding.metadata.label.trim()
|
||||
? binding.metadata.label.trim()
|
||||
: binding.targetSessionKey;
|
||||
const label = normalizeOptionalString(binding.metadata?.label) ?? binding.targetSessionKey;
|
||||
lines.push(
|
||||
`- ${label} (${formatConversationBindingText({
|
||||
conversationId: binding.conversation.conversationId,
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
normalizeProviderId,
|
||||
} from "../../agents/model-selection.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
|
||||
export type ModelPickerCatalogEntry = {
|
||||
provider: string;
|
||||
@@ -57,7 +58,7 @@ export function buildModelPickerItems(catalog: ModelPickerCatalogEntry[]): Model
|
||||
|
||||
for (const entry of catalog) {
|
||||
const provider = normalizeProviderId(entry.provider);
|
||||
const model = entry.id?.trim();
|
||||
const model = normalizeOptionalString(entry.id);
|
||||
if (!provider || !model) {
|
||||
continue;
|
||||
}
|
||||
@@ -93,8 +94,8 @@ export function resolveProviderEndpointLabel(
|
||||
{ baseUrl?: string; api?: string } | undefined
|
||||
>;
|
||||
const entry = findNormalizedProviderValue(providers, normalized);
|
||||
const endpoint = entry?.baseUrl?.trim();
|
||||
const api = entry?.api?.trim();
|
||||
const endpoint = normalizeOptionalString(entry?.baseUrl);
|
||||
const api = normalizeOptionalString(entry?.api);
|
||||
return {
|
||||
endpoint: endpoint || undefined,
|
||||
api: api || undefined,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { AcpTurnAttachment } from "../../acp/control-plane/manager.types.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import type { FinalizedMsgContext } from "../templating.js";
|
||||
|
||||
let dispatchAcpMediaRuntimePromise: Promise<
|
||||
@@ -32,7 +33,7 @@ export async function resolveAcpAttachments(params: {
|
||||
const mediaAttachments = runtime
|
||||
.normalizeAttachments(params.ctx)
|
||||
.map((attachment) =>
|
||||
attachment.path?.trim() ? { ...attachment, url: undefined } : attachment,
|
||||
normalizeOptionalString(attachment.path) ? { ...attachment, url: undefined } : attachment,
|
||||
);
|
||||
const cache = new runtime.MediaAttachmentCache(mediaAttachments, {
|
||||
localPathRoots: runtime.resolveMediaAttachmentLocalRoots({
|
||||
@@ -46,7 +47,7 @@ export async function resolveAcpAttachments(params: {
|
||||
if (!mediaType.startsWith("image/")) {
|
||||
continue;
|
||||
}
|
||||
if (!attachment.path?.trim()) {
|
||||
if (!normalizeOptionalString(attachment.path)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { normalizeChatType } from "../../channels/chat-type.js";
|
||||
import { resolveConversationLabel } from "../../channels/conversation-label.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import type { FinalizedMsgContext, MsgContext } from "../templating.js";
|
||||
import { normalizeInboundTextNewlines, sanitizeInboundSystemTags } from "./inbound-text.js";
|
||||
|
||||
@@ -81,9 +82,9 @@ export function finalizeInboundContext<T extends Record<string, unknown>>(
|
||||
normalizeInboundTextNewlines(bodyForCommandsSource),
|
||||
);
|
||||
|
||||
const explicitLabel = normalized.ConversationLabel?.trim();
|
||||
const explicitLabel = normalizeOptionalString(normalized.ConversationLabel);
|
||||
if (opts.forceConversationLabel || !explicitLabel) {
|
||||
const resolved = resolveConversationLabel(normalized)?.trim();
|
||||
const resolved = normalizeOptionalString(resolveConversationLabel(normalized));
|
||||
if (resolved) {
|
||||
normalized.ConversationLabel = resolved;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,19 @@ import type { ChannelId } from "../../channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { compileConfigRegexes, type ConfigRegexRejectReason } from "../../security/config-regex.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { escapeRegExp } from "../../utils.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
|
||||
function deriveMentionPatterns(identity?: { name?: string; emoji?: string }) {
|
||||
const patterns: string[] = [];
|
||||
const name = identity?.name?.trim();
|
||||
const name = normalizeOptionalString(identity?.name);
|
||||
if (name) {
|
||||
const parts = name.split(/\s+/).filter(Boolean).map(escapeRegExp);
|
||||
const re = parts.length ? parts.join(String.raw`\s+`) : escapeRegExp(name);
|
||||
patterns.push(String.raw`\b@?${re}\b`);
|
||||
}
|
||||
const emoji = identity?.emoji?.trim();
|
||||
const emoji = normalizeOptionalString(identity?.emoji);
|
||||
if (emoji) {
|
||||
patterns.push(escapeRegExp(emoji));
|
||||
}
|
||||
@@ -200,7 +201,7 @@ export function stripMentions(
|
||||
let result = text;
|
||||
const providerId =
|
||||
(ctx.Provider ? normalizeChannelId(ctx.Provider) : null) ??
|
||||
(ctx.Provider?.trim().toLowerCase() as ChannelId | undefined) ??
|
||||
(normalizeOptionalString(ctx.Provider)?.toLowerCase() as ChannelId | undefined) ??
|
||||
null;
|
||||
const providerMentions = providerId ? getChannelPlugin(providerId)?.mentions : undefined;
|
||||
const configRegexes = compileMentionPatternsCached({
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
toInternalMessagePreprocessedContext,
|
||||
toInternalMessageTranscribedContext,
|
||||
} from "../../hooks/message-hook-mappers.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import type { FinalizedMsgContext } from "../templating.js";
|
||||
|
||||
export function emitPreAgentMessageHooks(params: {
|
||||
@@ -16,7 +17,7 @@ export function emitPreAgentMessageHooks(params: {
|
||||
if (params.isFastTestEnv) {
|
||||
return;
|
||||
}
|
||||
const sessionKey = params.ctx.SessionKey?.trim();
|
||||
const sessionKey = normalizeOptionalString(params.ctx.SessionKey);
|
||||
if (!sessionKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { sanitizeUserFacingText } from "../../agents/pi-embedded-helpers.js";
|
||||
import { hasReplyPayloadContent } from "../../interactive/payload.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { stripHeartbeatToken } from "../heartbeat.js";
|
||||
import {
|
||||
HEARTBEAT_TOKEN,
|
||||
@@ -43,7 +44,7 @@ export function normalizeReplyPayload(
|
||||
trimText: true,
|
||||
},
|
||||
);
|
||||
const trimmed = payload.text?.trim() ?? "";
|
||||
const trimmed = normalizeOptionalString(payload.text) ?? "";
|
||||
if (!hasContent(trimmed)) {
|
||||
opts.onSkip?.("empty");
|
||||
return null;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import type { OriginatingChannelType } from "../templating.js";
|
||||
|
||||
function normalizeProviderValue(value?: string): string | undefined {
|
||||
const normalized = value?.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalString(value)?.toLowerCase();
|
||||
return normalized || undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
|
||||
export type PluginsCommand =
|
||||
| { action: "list" }
|
||||
| { action: "inspect"; name?: string }
|
||||
@@ -12,13 +14,13 @@ export function parsePluginsCommand(raw: string): PluginsCommand | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tail = match[1]?.trim() ?? "";
|
||||
const tail = normalizeOptionalString(match?.[1]) ?? "";
|
||||
if (!tail) {
|
||||
return { action: "list" };
|
||||
}
|
||||
|
||||
const [rawAction, ...rest] = tail.split(/\s+/);
|
||||
const action = rawAction?.trim().toLowerCase();
|
||||
const action = normalizeOptionalString(rawAction)?.toLowerCase();
|
||||
const name = rest.join(" ").trim();
|
||||
|
||||
if (action === "list") {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { resolveAgentConfig } from "../../agents/agent-scope.js";
|
||||
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
|
||||
import type { AgentElevatedAllowFromConfig, OpenClawConfig } from "../../config/config.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { normalizeStringEntries } from "../../shared/string-normalization.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
import {
|
||||
@@ -77,21 +78,21 @@ function isApprovedElevatedSender(params: {
|
||||
const senderFromTokens = new Set<string>();
|
||||
const senderE164Tokens = new Set<string>();
|
||||
|
||||
if (params.ctx.SenderId?.trim()) {
|
||||
if (normalizeOptionalString(params.ctx.SenderId)) {
|
||||
addFormattedTokens({
|
||||
formatAllowFrom: params.formatAllowFrom,
|
||||
values: [params.ctx.SenderId, stripSenderPrefix(params.ctx.SenderId)].filter(Boolean),
|
||||
tokens: senderIdTokens,
|
||||
});
|
||||
}
|
||||
if (params.ctx.From?.trim()) {
|
||||
if (normalizeOptionalString(params.ctx.From)) {
|
||||
addFormattedTokens({
|
||||
formatAllowFrom: params.formatAllowFrom,
|
||||
values: [params.ctx.From, stripSenderPrefix(params.ctx.From)].filter(Boolean),
|
||||
tokens: senderFromTokens,
|
||||
});
|
||||
}
|
||||
if (params.ctx.SenderE164?.trim()) {
|
||||
if (normalizeOptionalString(params.ctx.SenderE164)) {
|
||||
addFormattedTokens({
|
||||
formatAllowFrom: params.formatAllowFrom,
|
||||
values: [params.ctx.SenderE164],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { buildAgentMainSessionKey } from "../../routing/session-key.js";
|
||||
import { parseAgentSessionKey } from "../../sessions/session-key-utils.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
deliveryContextFromSession,
|
||||
deliveryContextKey,
|
||||
@@ -23,7 +24,7 @@ function resolveSessionKeyChannelHint(sessionKey?: string): string | undefined {
|
||||
if (!parsed?.rest) {
|
||||
return undefined;
|
||||
}
|
||||
const head = parsed.rest.split(":")[0]?.trim().toLowerCase();
|
||||
const head = normalizeOptionalString(parsed.rest.split(":")[0])?.toLowerCase();
|
||||
if (!head || head === "main" || head === "cron" || head === "subagent" || head === "acp") {
|
||||
return undefined;
|
||||
}
|
||||
@@ -42,7 +43,7 @@ const DIRECT_SESSION_MARKERS = new Set(["direct", "dm"]);
|
||||
const THREAD_SESSION_MARKERS = new Set(["thread", "topic"]);
|
||||
|
||||
function hasStrictDirectSessionTail(parts: string[], markerIndex: number): boolean {
|
||||
const peerId = parts[markerIndex + 1]?.trim();
|
||||
const peerId = normalizeOptionalString(parts[markerIndex + 1]);
|
||||
if (!peerId) {
|
||||
return false;
|
||||
}
|
||||
@@ -50,7 +51,11 @@ function hasStrictDirectSessionTail(parts: string[], markerIndex: number): boole
|
||||
if (tail.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return tail.length === 2 && THREAD_SESSION_MARKERS.has(tail[0] ?? "") && Boolean(tail[1]?.trim());
|
||||
return (
|
||||
tail.length === 2 &&
|
||||
THREAD_SESSION_MARKERS.has(tail[0] ?? "") &&
|
||||
Boolean(normalizeOptionalString(tail[1]))
|
||||
);
|
||||
}
|
||||
|
||||
function isDirectSessionKey(sessionKey?: string): boolean {
|
||||
@@ -73,7 +78,7 @@ function isDirectSessionKey(sessionKey?: string): boolean {
|
||||
if (DIRECT_SESSION_MARKERS.has(parts[1] ?? "")) {
|
||||
return hasStrictDirectSessionTail(parts, 1);
|
||||
}
|
||||
return Boolean(parts[1]?.trim()) && DIRECT_SESSION_MARKERS.has(parts[2] ?? "")
|
||||
return Boolean(normalizeOptionalString(parts[1])) && DIRECT_SESSION_MARKERS.has(parts[2] ?? "")
|
||||
? hasStrictDirectSessionTail(parts, 2)
|
||||
: false;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
resolveTimezone,
|
||||
} from "../../infra/format-time/format-datetime.ts";
|
||||
import { drainSystemEventEntries } from "../../infra/system-events.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
|
||||
/** Drain queued system events, format as `System:` lines, return the block (or undefined). */
|
||||
export async function drainFormattedSystemEvents(params: {
|
||||
@@ -39,7 +40,7 @@ export async function drainFormattedSystemEvents(params: {
|
||||
};
|
||||
|
||||
const resolveSystemEventTimezone = (cfg: OpenClawConfig) => {
|
||||
const raw = cfg.agents?.defaults?.envelopeTimezone?.trim();
|
||||
const raw = normalizeOptionalString(cfg.agents?.defaults?.envelopeTimezone);
|
||||
if (!raw) {
|
||||
return { mode: "local" as const };
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { logVerbose } from "../../globals.js";
|
||||
import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
|
||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||
import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { buildSessionEndHookPayload, buildSessionStartHookPayload } from "./session-hooks.js";
|
||||
export { drainFormattedSystemEvents } from "./session-system-events.js";
|
||||
|
||||
@@ -329,7 +330,7 @@ function rewriteSessionFileForNewSessionId(params: {
|
||||
previousSessionId: string;
|
||||
nextSessionId: string;
|
||||
}): string | undefined {
|
||||
const trimmed = params.sessionFile?.trim();
|
||||
const trimmed = normalizeOptionalString(params.sessionFile);
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user