diff --git a/src/acp/control-plane/manager.core.ts b/src/acp/control-plane/manager.core.ts index b92d3b47f37..a482f16765b 100644 --- a/src/acp/control-plane/manager.core.ts +++ b/src/acp/control-plane/manager.core.ts @@ -122,7 +122,7 @@ function resolveBackgroundTaskTerminalResult(progressSummary: string): { /\b(?:write failed:\s*)?permission denied(?: for (?\S+))?\.?/i, ); if (permissionDeniedMatch) { - const path = permissionDeniedMatch.groups?.path?.trim().replace(/[.,;:!?]+$/, ""); + const path = normalizeText(permissionDeniedMatch.groups?.path)?.replace(/[.,;:!?]+$/, ""); return { terminalOutcome: "blocked", terminalSummary: path ? `Permission denied for ${path}.` : "Permission denied.", @@ -793,7 +793,7 @@ export class AcpSessionManager { if (event.type === "error") { streamError = new AcpRuntimeError( normalizeAcpErrorCode(event.code), - event.message?.trim() || "ACP turn failed before completion.", + normalizeText(event.message) || "ACP turn failed before completion.", ); } else if (event.type === "text_delta" || event.type === "tool_call") { sawTurnOutput = true; @@ -1335,7 +1335,7 @@ export class AcpSessionManager { meta: SessionAcpMeta; }): Promise<{ runtime: AcpRuntime; handle: AcpRuntimeHandle; meta: SessionAcpMeta }> { const agent = - params.meta.agent?.trim() || resolveAcpAgentFromSessionKey(params.sessionKey, "main"); + normalizeText(params.meta.agent) || resolveAcpAgentFromSessionKey(params.sessionKey, "main"); const mode = params.meta.mode; const runtimeOptions = resolveRuntimeOptionsFromMeta(params.meta); const cwd = runtimeOptions.cwd ?? normalizeText(params.meta.cwd); @@ -1538,7 +1538,7 @@ export class AcpSessionManager { return true; } const summaryMatch = status.summary?.match(/\bstatus=([^\s]+)/i); - const summaryStatus = summaryMatch?.[1]?.trim().toLowerCase() ?? ""; + const summaryStatus = normalizeText(summaryMatch?.[1])?.toLowerCase() ?? ""; return summaryStatus === "dead" || summaryStatus === "no-session"; } @@ -1832,8 +1832,9 @@ export class AcpSessionManager { lastActivityAt: Date.now(), ...(base.lastError ? { lastError: base.lastError } : {}), }; - if (params.lastError?.trim()) { - next.lastError = params.lastError.trim(); + const lastError = normalizeText(params.lastError); + if (lastError) { + next.lastError = lastError; } else if (params.clearLastError) { delete next.lastError; } diff --git a/src/auto-reply/reply/groups.ts b/src/auto-reply/reply/groups.ts index 66b5d83f159..5e1e61616bb 100644 --- a/src/auto-reply/reply/groups.ts +++ b/src/auto-reply/reply/groups.ts @@ -1,6 +1,7 @@ import type { OpenClawConfig } from "../../config/config.js"; import { resolveChannelGroupRequireMention } from "../../config/group-policy.js"; import type { GroupKeyResolution, SessionEntry } from "../../config/sessions.js"; +import { normalizeOptionalString } from "../../shared/string-coerce.js"; import { isInternalMessageChannel } from "../../utils/message-channel.js"; import { normalizeGroupActivation } from "../group-activation.js"; import type { TemplateContext } from "../templating.js"; @@ -19,7 +20,7 @@ function resolveGroupId(raw: string | undefined | null): string | undefined { } function resolveLooseChannelId(raw?: string | null): string | null { - const normalized = raw?.trim().toLowerCase(); + const normalized = normalizeOptionalString(raw)?.toLowerCase(); if (!normalized) { return null; } @@ -52,14 +53,15 @@ export async function resolveGroupRequireMention(params: { groupResolution?: GroupKeyResolution; }): Promise { const { cfg, ctx, groupResolution } = params; - const rawChannel = groupResolution?.channel ?? ctx.Provider?.trim(); + const rawChannel = groupResolution?.channel ?? normalizeOptionalString(ctx.Provider); const channel = await resolveRuntimeChannelId(rawChannel); if (!channel) { return true; } const groupId = groupResolution?.id ?? resolveGroupId(ctx.From); - const groupChannel = ctx.GroupChannel?.trim() ?? ctx.GroupSubject?.trim(); - const groupSpace = ctx.GroupSpace?.trim(); + const groupChannel = + normalizeOptionalString(ctx.GroupChannel) ?? normalizeOptionalString(ctx.GroupSubject); + const groupSpace = normalizeOptionalString(ctx.GroupSpace); let requireMention: boolean | undefined; const runtime = await loadGroupsRuntime(); try { @@ -89,7 +91,7 @@ export function defaultGroupActivation(requireMention: boolean): "always" | "men } function resolveProviderLabel(rawProvider: string | undefined): string { - const providerKey = rawProvider?.trim().toLowerCase() ?? ""; + const providerKey = normalizeOptionalString(rawProvider)?.toLowerCase() ?? ""; if (!providerKey) { return "chat"; } @@ -100,8 +102,8 @@ function resolveProviderLabel(rawProvider: string | undefined): string { } export function buildGroupChatContext(params: { sessionCtx: TemplateContext }): string { - const subject = params.sessionCtx.GroupSubject?.trim(); - const members = params.sessionCtx.GroupMembers?.trim(); + const subject = normalizeOptionalString(params.sessionCtx.GroupSubject); + const members = normalizeOptionalString(params.sessionCtx.GroupMembers); const providerLabel = resolveProviderLabel(params.sessionCtx.Provider); const lines: string[] = [];