refactor: dedupe outbound helper readers

This commit is contained in:
Peter Steinberger
2026-04-07 08:28:08 +01:00
parent 02c08b3929
commit 5eb6921a18
5 changed files with 25 additions and 15 deletions

View File

@@ -1,9 +1,10 @@
import { normalizeOptionalString } from "../../../shared/string-coerce.js";
import { isRecord } from "../../../utils.js";
import type { ChannelAccountSnapshot, ChannelStatusIssue } from "../types.js";
export { isRecord };
export function asString(value: unknown): string | undefined {
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
return typeof value === "string" ? normalizeOptionalString(value) : undefined;
}
export function formatMatchMetadata(params: {

View File

@@ -1,8 +1,10 @@
import { normalizeOptionalString } from "../shared/string-coerce.js";
const INVALID_REQUEST = "INVALID_REQUEST";
const APPROVAL_NOT_FOUND = "APPROVAL_NOT_FOUND";
function readErrorCode(value: unknown): string | null {
return typeof value === "string" && value.trim() ? value : null;
return typeof value === "string" ? (normalizeOptionalString(value) ?? null) : null;
}
function readApprovalNotFoundDetailsReason(value: unknown): string | null {
@@ -10,7 +12,7 @@ function readApprovalNotFoundDetailsReason(value: unknown): string | null {
return null;
}
const reason = (value as { reason?: unknown }).reason;
return typeof reason === "string" && reason.trim() ? reason : null;
return typeof reason === "string" ? (normalizeOptionalString(reason) ?? null) : null;
}
export function isApprovalNotFoundError(err: unknown): boolean {

View File

@@ -22,6 +22,7 @@ import { hasPollCreationParams } from "../../poll-params.js";
import { resolvePollMaxSelections } from "../../polls.js";
import { buildChannelAccountBindings } from "../../routing/bindings.js";
import { normalizeAgentId } from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { type GatewayClientMode, type GatewayClientName } from "../../utils/message-channel.js";
import { formatErrorMessage } from "../errors.js";
import { throwIfAborted } from "./abort.js";
@@ -145,7 +146,8 @@ function collectActionMediaSourceHints(params: Record<string, unknown>): string[
const sources: string[] = [];
for (const key of ["media", "mediaUrl", "path", "filePath", "fileUrl"] as const) {
const value = params[key];
if (typeof value === "string" && value.trim()) {
const normalized = typeof value === "string" ? normalizeOptionalString(value) : undefined;
if (normalized) {
sources.push(value);
}
}
@@ -445,7 +447,7 @@ async function handleSendAction(ctx: ResolvedActionContext): Promise<MessageActi
const mergedMediaUrls: string[] = [];
const seenMedia = new Set<string>();
const pushMedia = (value?: string | null) => {
const trimmed = value?.trim();
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
return;
}

View File

@@ -2,6 +2,7 @@ import type { ChannelStatusAdapter } from "../channels/plugins/types.adapters.js
import type { ChannelAccountSnapshot } from "../channels/plugins/types.core.js";
import type { ChannelStatusIssue } from "../channels/plugins/types.js";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
export type { ChannelAccountSnapshot } from "../channels/plugins/types.core.js";
export type { ChannelStatusIssue } from "../channels/plugins/types.js";
export { isRecord } from "../channels/plugins/status-issues/shared.js";
@@ -325,7 +326,10 @@ export function createDependentCredentialStatusIssueCollector(options: {
}) {
const isDependencyConfigured =
options.isDependencyConfigured ??
((value: unknown) => typeof value === "string" && value.trim().length > 0 && value !== "none");
((value: unknown) => {
const normalized = typeof value === "string" ? normalizeOptionalString(value) : undefined;
return Boolean(normalized && normalized !== "none");
});
return (accounts: ConfigIssueAccount[]): ChannelStatusIssue[] =>
accounts.flatMap((account) => {

View File

@@ -1,3 +1,5 @@
import { normalizeOptionalString } from "../shared/string-coerce.js";
type ToolResultCounts = {
total: number;
errors: number;
@@ -7,17 +9,16 @@ const TOOL_CALL_TYPES = new Set(["tool_use", "toolcall", "tool_call"]);
const TOOL_RESULT_TYPES = new Set(["tool_result", "tool_result_error"]);
const normalizeType = (value: unknown): string => {
if (typeof value !== "string") {
return "";
}
return value.trim().toLowerCase();
return typeof value === "string" ? (normalizeOptionalString(value)?.toLowerCase() ?? "") : "";
};
export const extractToolCallNames = (message: Record<string, unknown>): string[] => {
const names = new Set<string>();
const toolNameRaw = message.toolName ?? message.tool_name;
if (typeof toolNameRaw === "string" && toolNameRaw.trim()) {
names.add(toolNameRaw.trim());
const toolName =
typeof toolNameRaw === "string" ? normalizeOptionalString(toolNameRaw) : undefined;
if (toolName) {
names.add(toolName);
}
const content = message.content;
@@ -34,9 +35,9 @@ export const extractToolCallNames = (message: Record<string, unknown>): string[]
if (!TOOL_CALL_TYPES.has(type)) {
continue;
}
const name = block.name;
if (typeof name === "string" && name.trim()) {
names.add(name.trim());
const name = typeof block.name === "string" ? normalizeOptionalString(block.name) : undefined;
if (name) {
names.add(name);
}
}