mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-22 14:41:34 +00:00
refactor: dedupe reply control readers
This commit is contained in:
@@ -6,6 +6,7 @@ import { isCommandFlagEnabled } from "../../config/commands.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { clampInt } from "../../utils.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
import type { ReplyPayload } from "../types.js";
|
||||
@@ -82,8 +83,8 @@ function parseBashRequest(raw: string): BashRequest | null {
|
||||
return { action: "help" };
|
||||
}
|
||||
const tokenMatch = rest.match(/^(\S+)(?:\s+([\s\S]+))?$/);
|
||||
const token = tokenMatch?.[1]?.trim() ?? "";
|
||||
const remainder = tokenMatch?.[2]?.trim() ?? "";
|
||||
const token = normalizeOptionalString(tokenMatch?.[1]) ?? "";
|
||||
const remainder = normalizeOptionalString(tokenMatch?.[2]) ?? "";
|
||||
const lowered = token.toLowerCase();
|
||||
if (lowered === "poll") {
|
||||
return { action: "poll", sessionId: remainder || undefined };
|
||||
@@ -236,7 +237,8 @@ export async function handleBashChatCommand(params: {
|
||||
|
||||
if (request.action === "poll") {
|
||||
const sessionId =
|
||||
request.sessionId?.trim() || (liveJob?.state === "running" ? liveJob.sessionId : "");
|
||||
normalizeOptionalString(request.sessionId) ||
|
||||
(liveJob?.state === "running" ? liveJob.sessionId : "");
|
||||
if (!sessionId) {
|
||||
return { text: "⚙️ No active bash job." };
|
||||
}
|
||||
@@ -279,7 +281,8 @@ export async function handleBashChatCommand(params: {
|
||||
|
||||
if (request.action === "stop") {
|
||||
const sessionId =
|
||||
request.sessionId?.trim() || (liveJob?.state === "running" ? liveJob.sessionId : "");
|
||||
normalizeOptionalString(request.sessionId) ||
|
||||
(liveJob?.state === "running" ? liveJob.sessionId : "");
|
||||
if (!sessionId) {
|
||||
return { text: "⚙️ No active bash job." };
|
||||
}
|
||||
|
||||
@@ -85,10 +85,10 @@ function hasInboundMediaForAcp(ctx: FinalizedMsgContext): boolean {
|
||||
return Boolean(
|
||||
ctx.StickerMediaIncluded ||
|
||||
ctx.Sticker ||
|
||||
ctx.MediaPath?.trim() ||
|
||||
ctx.MediaUrl?.trim() ||
|
||||
ctx.MediaPaths?.some((value) => value?.trim()) ||
|
||||
ctx.MediaUrls?.some((value) => value?.trim()) ||
|
||||
normalizeOptionalString(ctx.MediaPath) ||
|
||||
normalizeOptionalString(ctx.MediaUrl) ||
|
||||
ctx.MediaPaths?.some((value) => normalizeOptionalString(value)) ||
|
||||
ctx.MediaUrls?.some((value) => normalizeOptionalString(value)) ||
|
||||
ctx.MediaTypes?.length,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { CHAT_CHANNEL_ORDER } from "../../channels/registry.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { normalizeAtHashSlug } from "../../shared/string-normalization.js";
|
||||
|
||||
export type ExplicitElevatedAllowField = "id" | "from" | "e164" | "name" | "username" | "tag";
|
||||
@@ -111,7 +112,7 @@ export function matchesFormattedTokens(params: {
|
||||
|
||||
export function buildMutableTokens(value?: string): Set<string> {
|
||||
const tokens = new Set<string>();
|
||||
const trimmed = value?.trim();
|
||||
const trimmed = normalizeOptionalString(value);
|
||||
if (!trimmed) {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { SkillCommandSpec } from "../../agents/skills.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { normalizeAgentId } from "../../routing/session-key.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { shouldHandleTextCommands } from "../commands-text-routing.js";
|
||||
import type { MsgContext, TemplateContext } from "../templating.js";
|
||||
import type { ElevatedLevel, ReasoningLevel, ThinkLevel, VerboseLevel } from "../thinking.js";
|
||||
@@ -80,7 +81,7 @@ function resolveConfiguredDirectiveAliases(params: {
|
||||
return [];
|
||||
}
|
||||
return Object.values(params.cfg.agents?.defaults?.models ?? {})
|
||||
.map((entry) => entry.alias?.trim())
|
||||
.map((entry) => normalizeOptionalString(entry.alias))
|
||||
.filter((alias): alias is string => Boolean(alias))
|
||||
.filter((alias) => !params.reservedCommands.has(alias.toLowerCase()));
|
||||
}
|
||||
@@ -379,7 +380,9 @@ export async function resolveReplyDirectives(params: {
|
||||
sessionCtx.BodyStripped = cleanedBody;
|
||||
|
||||
const messageProviderKey =
|
||||
sessionCtx.Provider?.trim().toLowerCase() ?? ctx.Provider?.trim().toLowerCase() ?? "";
|
||||
normalizeOptionalString(sessionCtx.Provider)?.toLowerCase() ??
|
||||
normalizeOptionalString(ctx.Provider)?.toLowerCase() ??
|
||||
"";
|
||||
const elevated = resolveElevatedPermissions({
|
||||
cfg,
|
||||
agentId,
|
||||
@@ -464,8 +467,8 @@ export async function resolveReplyDirectives(params: {
|
||||
useFastReplyRuntime &&
|
||||
!directives.hasModelDirective &&
|
||||
!hasResolvedHeartbeatModelOverride &&
|
||||
!sessionEntry?.modelOverride?.trim() &&
|
||||
!sessionEntry?.providerOverride?.trim()
|
||||
!normalizeOptionalString(sessionEntry?.modelOverride) &&
|
||||
!normalizeOptionalString(sessionEntry?.providerOverride)
|
||||
? createFastTestModelSelectionState({
|
||||
agentCfg,
|
||||
provider,
|
||||
@@ -522,7 +525,9 @@ export async function resolveReplyDirectives(params: {
|
||||
alias ? `Model switched to ${alias} (${label}).` : `Model switched to ${label}.`;
|
||||
const isModelListAlias =
|
||||
directives.hasModelDirective &&
|
||||
["status", "list"].includes(directives.rawModelDirective?.trim().toLowerCase() ?? "");
|
||||
["status", "list"].includes(
|
||||
normalizeOptionalString(directives.rawModelDirective)?.toLowerCase() ?? "",
|
||||
);
|
||||
const effectiveModelDirective = isModelListAlias ? undefined : directives.rawModelDirective;
|
||||
|
||||
const inlineStatusRequested = hasInlineStatus && allowTextCommands && command.isAuthorizedSender;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { resolvePreferredOpenClawTmpDir } from "../../infra/tmp-openclaw-dir.js"
|
||||
import { resolveChannelRemoteInboundAttachmentRoots } from "../../media/channel-inbound-roots.js";
|
||||
import { isInboundPathAllowed } from "../../media/inbound-path-policy.js";
|
||||
import { getMediaDir, MEDIA_MAX_BYTES } from "../../media/store.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { CONFIG_DIR } from "../../utils.js";
|
||||
import type { MsgContext, TemplateContext } from "../templating.js";
|
||||
|
||||
@@ -156,8 +157,8 @@ function resolveRawPaths(ctx: MsgContext): string[] {
|
||||
const pathsFromArray = Array.isArray(ctx.MediaPaths) ? ctx.MediaPaths : undefined;
|
||||
return pathsFromArray && pathsFromArray.length > 0
|
||||
? pathsFromArray
|
||||
: ctx.MediaPath?.trim()
|
||||
? [ctx.MediaPath.trim()]
|
||||
: normalizeOptionalString(ctx.MediaPath)
|
||||
? [normalizeOptionalString(ctx.MediaPath)!]
|
||||
: [];
|
||||
}
|
||||
|
||||
@@ -243,7 +244,7 @@ function rewriteStagedMediaPaths(params: {
|
||||
hasPathsArray: boolean;
|
||||
}): void {
|
||||
const rewriteIfStaged = (value: string | undefined): string | undefined => {
|
||||
const raw = value?.trim();
|
||||
const raw = normalizeOptionalString(value);
|
||||
if (!raw) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TypingMode } from "../../config/types.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../tokens.js";
|
||||
import type { TypingPolicy } from "../types.js";
|
||||
import type { TypingController } from "./typing.js";
|
||||
@@ -67,7 +68,7 @@ export function createTypingSignaler(params: {
|
||||
let hasRenderableText = false;
|
||||
|
||||
const isRenderableText = (text?: string): boolean => {
|
||||
const trimmed = text?.trim();
|
||||
const trimmed = normalizeOptionalString(text);
|
||||
if (!trimmed) {
|
||||
return false;
|
||||
}
|
||||
@@ -98,7 +99,7 @@ export function createTypingSignaler(params: {
|
||||
const renderable = isRenderableText(text);
|
||||
if (renderable) {
|
||||
hasRenderableText = true;
|
||||
} else if (text?.trim()) {
|
||||
} else if (normalizeOptionalString(text)) {
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createTypingKeepaliveLoop } from "../../channels/typing-lifecycle.js";
|
||||
import { createTypingStartGuard } from "../../channels/typing-start-guard.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { isSilentReplyPrefixText, isSilentReplyText, SILENT_REPLY_TOKEN } from "../tokens.js";
|
||||
|
||||
export type TypingController = {
|
||||
@@ -181,7 +182,7 @@ export function createTypingController(params: {
|
||||
if (sealed) {
|
||||
return;
|
||||
}
|
||||
const trimmed = text?.trim();
|
||||
const trimmed = normalizeOptionalString(text);
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user