refactor: dedupe agent runtime readers

This commit is contained in:
Peter Steinberger
2026-04-07 07:33:24 +01:00
parent 28d478dc52
commit 768e606f96
9 changed files with 22 additions and 12 deletions

View File

@@ -825,7 +825,7 @@ async function bindPreparedAcpThread(params: {
let sessionEntry = params.initializedRuntime.sessionEntry;
if (params.initializedRuntime.sessionId && params.preparedBinding.placement === "child") {
const boundThreadId = String(binding.conversation.conversationId).trim() || undefined;
const boundThreadId = normalizeOptionalString(String(binding.conversation.conversationId));
if (boundThreadId) {
sessionEntry = await persistAcpSpawnSessionFileBestEffort({
sessionId: params.initializedRuntime.sessionId,
@@ -854,10 +854,12 @@ function resolveAcpSpawnBootstrapDeliveryPlan(params: {
// Child-thread ACP spawns deliver bootstrap output to the new thread; current-conversation
// binds deliver back to the originating target.
const boundThreadIdRaw = params.binding?.conversation.conversationId;
const boundThreadId = boundThreadIdRaw ? String(boundThreadIdRaw).trim() || undefined : undefined;
const boundThreadId = boundThreadIdRaw
? normalizeOptionalString(String(boundThreadIdRaw))
: undefined;
const fallbackThreadIdRaw = params.requester.origin?.threadId;
const fallbackThreadId =
fallbackThreadIdRaw != null ? String(fallbackThreadIdRaw).trim() || undefined : undefined;
fallbackThreadIdRaw != null ? normalizeOptionalString(String(fallbackThreadIdRaw)) : undefined;
const deliveryThreadId = boundThreadId ?? fallbackThreadId;
const requesterConversationId = resolveConversationIdForThreadBinding({
channel: params.requester.origin?.channel,

View File

@@ -1,4 +1,5 @@
import type { OpenClawConfig, HumanDelayConfig, IdentityConfig } from "../config/config.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { resolveAgentConfig } from "./agent-scope.js";
const DEFAULT_ACK_REACTION = "👀";
@@ -58,7 +59,7 @@ export function resolveIdentityNamePrefix(
/** Returns just the identity name (without brackets) for template context. */
export function resolveIdentityName(cfg: OpenClawConfig, agentId: string): string | undefined {
return resolveAgentIdentity(cfg, agentId)?.name?.trim() || undefined;
return normalizeOptionalString(resolveAgentIdentity(cfg, agentId)?.name);
}
export function resolveMessagePrefix(

View File

@@ -7,6 +7,7 @@ import type { OpenClawConfig } from "../config/config.js";
import { logWarn } from "../logger.js";
import { resolveGlobalSingleton } from "../shared/global-singleton.js";
import { redactSensitiveUrlLikeString } from "../shared/net/redact-sensitive-url.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { loadEmbeddedPiMcpConfig } from "./embedded-pi-mcp.js";
import { isMcpConfigRecord } from "./mcp-config-shared.js";
import { resolveMcpTransport } from "./mcp-transport.js";
@@ -206,7 +207,7 @@ export function createSessionMcpRuntime(params: {
safeServerName,
toolName,
title: tool.title,
description: tool.description?.trim() || undefined,
description: normalizeOptionalString(tool.description),
inputSchema: tool.inputSchema,
fallbackDescription: `Provided by bundle MCP server "${serverName}" (${resolved.description}).`,
});

View File

@@ -1,6 +1,7 @@
import { readLoggingConfig } from "../logging/config.js";
import { redactIdentifier } from "../logging/redact-identifier.js";
import { getDefaultRedactPatterns, redactSensitiveText } from "../logging/redact.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { sanitizeForConsole } from "./console-sanitize.js";
import { getApiErrorPayloadFingerprint, parseApiErrorInfo } from "./pi-embedded-helpers.js";
import { stableStringify } from "./stable-stringify.js";
@@ -76,7 +77,7 @@ function extractRequestId(text: string | undefined): string | undefined {
return undefined;
}
const match = text.match(REQUEST_ID_RE);
return match?.[1]?.trim() || undefined;
return normalizeOptionalString(match?.[1]);
}
function buildObservationFingerprint(params: {

View File

@@ -151,7 +151,7 @@ export async function ensureSandboxBrowser(params: {
const containerName = name.slice(0, 63);
const state = await dockerContainerState(containerName);
const browserImage = params.cfg.browser.image ?? DEFAULT_SANDBOX_BROWSER_IMAGE;
const cdpSourceRange = params.cfg.browser.cdpSourceRange?.trim() || undefined;
const cdpSourceRange = normalizeOptionalString(params.cfg.browser.cdpSourceRange);
const browserDockerCfg = resolveSandboxBrowserDockerCreateConfig({
docker: params.cfg.docker,
browser: { ...params.cfg.browser, image: browserImage },

View File

@@ -5,6 +5,7 @@ import { callGateway } from "../../gateway/call.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { normalizeAgentId, resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
import { SESSION_LABEL_MAX_LENGTH } from "../../sessions/session-label.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import {
type GatewayMessageChannel,
INTERNAL_MESSAGE_CHANNEL,
@@ -100,8 +101,8 @@ export function createSessionsSendTool(opts?: {
});
const sessionKeyParam = readStringParam(params, "sessionKey");
const labelParam = readStringParam(params, "label")?.trim() || undefined;
const labelAgentIdParam = readStringParam(params, "agentId")?.trim() || undefined;
const labelParam = normalizeOptionalString(readStringParam(params, "label"));
const labelAgentIdParam = normalizeOptionalString(readStringParam(params, "agentId"));
if (sessionKeyParam && labelParam) {
return jsonResult({
runId: crypto.randomUUID(),

View File

@@ -12,6 +12,7 @@ import { formatErrorMessage } from "../../infra/errors.js";
import type { OutboundDeliveryResult } from "../../infra/outbound/deliver.js";
import { normalizeTargetForProvider } from "../../infra/outbound/target-normalization.js";
import { logWarn, logError } from "../../logger.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { CronJob, CronRunTelemetry } from "../types.js";
import type { DeliveryTargetResolution } from "./delivery-target.js";
import { pickSummaryFromOutput } from "./helpers.js";
@@ -258,7 +259,8 @@ async function queueCronAwarenessSystemEvent(params: {
outputText?: string;
synthesizedText?: string;
}): Promise<void> {
const text = params.outputText?.trim() || params.synthesizedText?.trim() || undefined;
const text =
normalizeOptionalString(params.outputText) ?? normalizeOptionalString(params.synthesizedText);
if (!text) {
return;
}

View File

@@ -1,6 +1,7 @@
import { hasOutboundReplyContent } from "openclaw/plugin-sdk/reply-payload";
import { DEFAULT_HEARTBEAT_ACK_MAX_CHARS } from "../../auto-reply/heartbeat.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { truncateUtf16Safe } from "../../utils.js";
import { shouldSkipHeartbeatOnlyDelivery } from "../heartbeat-policy.js";
@@ -128,7 +129,7 @@ export function resolveCronPayloadOutcome(params: {
const firstText = params.payloads[0]?.text ?? "";
const summary = pickSummaryFromPayloads(params.payloads) ?? pickSummaryFromOutput(firstText);
const outputText = pickLastNonEmptyTextFromPayloads(params.payloads);
const synthesizedText = outputText?.trim() || summary?.trim() || undefined;
const synthesizedText = normalizeOptionalString(outputText) ?? normalizeOptionalString(summary);
const deliveryPayload = pickLastDeliverablePayload(params.payloads);
const selectedDeliveryPayloads = pickDeliverablePayloads(params.payloads);
const resolvedDeliveryPayloads =

View File

@@ -6,6 +6,7 @@ import {
normalizeMainKey,
parseAgentSessionKey,
} from "../routing/session-key.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { ChatLog } from "./components/chat-log.js";
import type { GatewayAgentsList, GatewayChatClient } from "./gateway-chat.js";
import { asString, extractTextFromMessage, isCommandMessage } from "./tui-formatters.js";
@@ -71,7 +72,7 @@ export function createSessionActions(context: SessionActionContext) {
state.sessionScope = result.scope ?? state.sessionScope;
state.agents = result.agents.map((agent) => ({
id: normalizeAgentId(agent.id),
name: agent.name?.trim() || undefined,
name: normalizeOptionalString(agent.name),
}));
agentNames.clear();
for (const agent of state.agents) {