mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-15 19:21:08 +00:00
refactor: dedupe agent tool lowercase helpers
This commit is contained in:
@@ -11,7 +11,11 @@ import {
|
||||
parseAgentSessionKey,
|
||||
resolveAgentIdFromSessionKey,
|
||||
} from "../routing/session-key.js";
|
||||
import { readStringValue, resolvePrimaryStringValue } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
readStringValue,
|
||||
resolvePrimaryStringValue,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { resolveEffectiveAgentSkillFilter } from "./skills/agent-filter.js";
|
||||
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
|
||||
@@ -105,11 +109,10 @@ export function resolveSessionAgentIds(params: {
|
||||
sessionAgentId: string;
|
||||
} {
|
||||
const defaultAgentId = resolveDefaultAgentId(params.config ?? {});
|
||||
const explicitAgentIdRaw =
|
||||
typeof params.agentId === "string" ? params.agentId.trim().toLowerCase() : "";
|
||||
const explicitAgentIdRaw = normalizeLowercaseStringOrEmpty(params.agentId);
|
||||
const explicitAgentId = explicitAgentIdRaw ? normalizeAgentId(explicitAgentIdRaw) : null;
|
||||
const sessionKey = params.sessionKey?.trim();
|
||||
const normalizedSessionKey = sessionKey ? sessionKey.toLowerCase() : undefined;
|
||||
const normalizedSessionKey = sessionKey ? normalizeLowercaseStringOrEmpty(sessionKey) : undefined;
|
||||
const parsed = normalizedSessionKey ? parseAgentSessionKey(normalizedSessionKey) : null;
|
||||
const sessionAgentId =
|
||||
explicitAgentId ?? (parsed?.agentId ? normalizeAgentId(parsed.agentId) : defaultAgentId);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { DEFAULT_IDENTITY_FILENAME } from "./workspace.js";
|
||||
|
||||
export type AgentIdentityFile = {
|
||||
@@ -26,8 +27,7 @@ function normalizeIdentityValue(value: string): string {
|
||||
normalized = normalized.slice(1, -1).trim();
|
||||
}
|
||||
normalized = normalized.replace(/[\u2013\u2014]/g, "-");
|
||||
normalized = normalized.replace(/\s+/g, " ").toLowerCase();
|
||||
return normalized;
|
||||
return normalizeLowercaseStringOrEmpty(normalized.replace(/\s+/g, " "));
|
||||
}
|
||||
|
||||
function isIdentityPlaceholder(value: string): boolean {
|
||||
@@ -44,7 +44,9 @@ export function parseIdentityMarkdown(content: string): AgentIdentityFile {
|
||||
if (colonIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, "").trim().toLowerCase();
|
||||
const label = normalizeLowercaseStringOrEmpty(
|
||||
cleaned.slice(0, colonIndex).replace(/[*_]/g, ""),
|
||||
);
|
||||
const value = cleaned
|
||||
.slice(colonIndex + 1)
|
||||
.replace(/^[*_]+|[*_]+$/g, "")
|
||||
|
||||
@@ -20,7 +20,7 @@ import type { ExecApprovalDecision } from "../infra/exec-approvals.js";
|
||||
import { splitMediaFromOutput } from "../media/parse.js";
|
||||
import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
|
||||
import type { PluginHookAfterToolCallEvent } from "../plugins/types.js";
|
||||
import { readStringValue } from "../shared/string-coerce.js";
|
||||
import { normalizeOptionalLowercaseString, readStringValue } from "../shared/string-coerce.js";
|
||||
import type { ApplyPatchSummary } from "./apply-patch.js";
|
||||
import type { ExecToolDetails } from "./bash-tools.exec-types.js";
|
||||
import { parseExecApprovalResultText } from "./exec-approval-result.js";
|
||||
@@ -63,7 +63,7 @@ function isCronAddAction(args: unknown): boolean {
|
||||
return false;
|
||||
}
|
||||
const action = (args as Record<string, unknown>).action;
|
||||
return typeof action === "string" && action.trim().toLowerCase() === "add";
|
||||
return normalizeOptionalLowercaseString(action) === "add";
|
||||
}
|
||||
|
||||
function buildToolCallSummary(toolName: string, args: unknown, meta?: string): ToolCallSummary {
|
||||
@@ -180,7 +180,7 @@ function buildPatchSummaryText(summary: ApplyPatchSummary): string {
|
||||
}
|
||||
|
||||
function extendExecMeta(toolName: string, args: unknown, meta?: string): string | undefined {
|
||||
const normalized = toolName.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(toolName);
|
||||
if (normalized !== "exec" && normalized !== "bash") {
|
||||
return meta;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ function normalizeToolErrorText(text: string): string | undefined {
|
||||
}
|
||||
|
||||
function isErrorLikeStatus(status: string): boolean {
|
||||
const normalized = status.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(status);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveChannelGroupToolsPolicy } from "../config/group-policy.js";
|
||||
import type { AgentToolsConfig } from "../config/types.tools.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { normalizeMessageChannel } from "../utils/message-channel.js";
|
||||
import { resolveAgentConfig, resolveAgentIdFromSessionKey } from "./agent-scope.js";
|
||||
import type { AnyAgentTool } from "./pi-tools.types.js";
|
||||
@@ -128,7 +132,7 @@ type ToolPolicyConfig = {
|
||||
};
|
||||
|
||||
function normalizeProviderKey(value: string): string {
|
||||
return value.trim().toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(value);
|
||||
}
|
||||
|
||||
function resolveGroupContextFromSessionKey(sessionKey?: string | null): {
|
||||
@@ -167,7 +171,7 @@ function resolveGroupContextFromSessionKey(sessionKey?: string | null): {
|
||||
if (!groupId) {
|
||||
return {};
|
||||
}
|
||||
return { channel: channel.trim().toLowerCase(), groupId };
|
||||
return { channel: normalizeLowercaseStringOrEmpty(channel), groupId };
|
||||
}
|
||||
|
||||
function resolveProviderToolPolicy(params: {
|
||||
@@ -195,7 +199,7 @@ function resolveProviderToolPolicy(params: {
|
||||
}
|
||||
|
||||
const normalizedProvider = normalizeProviderKey(provider);
|
||||
const rawModelId = params.modelId?.trim().toLowerCase();
|
||||
const rawModelId = normalizeOptionalLowercaseString(params.modelId);
|
||||
const fullModelId =
|
||||
rawModelId && !rawModelId.includes("/") ? `${normalizedProvider}/${rawModelId}` : rawModelId;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
|
||||
import { isSubagentSessionKey, parseAgentSessionKey } from "../routing/session-key.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import { getSubagentDepthFromSessionStore } from "./subagent-depth.js";
|
||||
import { normalizeSubagentSessionKey } from "./subagent-session-key.js";
|
||||
|
||||
@@ -19,18 +20,12 @@ type SessionCapabilityEntry = {
|
||||
};
|
||||
|
||||
function normalizeSubagentRole(value: unknown): SubagentSessionRole | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const trimmed = value.trim().toLowerCase();
|
||||
const trimmed = normalizeOptionalLowercaseString(value);
|
||||
return SUBAGENT_SESSION_ROLES.find((entry) => entry === trimmed);
|
||||
}
|
||||
|
||||
function normalizeSubagentControlScope(value: unknown): SubagentControlScope | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const trimmed = value.trim().toLowerCase();
|
||||
const trimmed = normalizeOptionalLowercaseString(value);
|
||||
return SUBAGENT_CONTROL_SCOPES.find((entry) => entry === trimmed);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { resolveExecDetail } from "./tool-display-exec.js";
|
||||
import { asRecord } from "./tool-display-record.js";
|
||||
|
||||
@@ -165,7 +168,7 @@ export function formatDetailKey(raw: string, overrides: Record<string, string> =
|
||||
}
|
||||
const cleaned = last.replace(/_/g, " ").replace(/-/g, " ");
|
||||
const spaced = cleaned.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
|
||||
return spaced.trim().toLowerCase() || last.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(spaced) || normalizeLowercaseStringOrEmpty(last);
|
||||
}
|
||||
|
||||
export function resolvePathArg(args: unknown): string | undefined {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
type PreambleResult = {
|
||||
command: string;
|
||||
chdirPath?: string;
|
||||
@@ -82,7 +84,7 @@ export function binaryName(token: string | undefined): string | undefined {
|
||||
}
|
||||
const cleaned = stripOuterQuotes(token) ?? token;
|
||||
const segment = cleaned.split(/[/]/).at(-1) ?? cleaned;
|
||||
return segment.trim().toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(segment);
|
||||
}
|
||||
|
||||
export function optionValue(words: string[], names: string[]): string | undefined {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { getImageMetadata } from "../../media/image-ops.js";
|
||||
import { saveMediaBuffer } from "../../media/store.js";
|
||||
import { loadWebMedia } from "../../media/web-media.js";
|
||||
import { getProviderEnvVars } from "../../secrets/provider-env-vars.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../../utils.js";
|
||||
import { normalizeProviderId } from "../provider-id.js";
|
||||
import { ToolInputError, readNumberParam, readStringParam } from "./common.js";
|
||||
@@ -213,7 +214,7 @@ function resolveAction(args: Record<string, unknown>): "generate" | "list" {
|
||||
if (!raw) {
|
||||
return "generate";
|
||||
}
|
||||
const normalized = raw.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(raw);
|
||||
if (normalized === "generate" || normalized === "list") {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
MusicGenerationSourceImage,
|
||||
} from "../../music-generation/types.js";
|
||||
import { readSnakeCaseParamRaw } from "../../param-key.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../../utils.js";
|
||||
import type { DeliveryContext } from "../../utils/delivery-context.js";
|
||||
import {
|
||||
@@ -144,7 +145,7 @@ function resolveAction(args: Record<string, unknown>): "generate" | "list" | "st
|
||||
if (!raw) {
|
||||
return "generate";
|
||||
}
|
||||
const normalized = raw.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(raw);
|
||||
if (normalized === "generate" || normalized === "list" || normalized === "status") {
|
||||
return normalized;
|
||||
}
|
||||
@@ -157,7 +158,7 @@ function readBooleanParam(params: Record<string, unknown>, key: string): boolean
|
||||
return raw;
|
||||
}
|
||||
if (typeof raw === "string") {
|
||||
const normalized = raw.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(raw);
|
||||
if (normalized === "true") {
|
||||
return true;
|
||||
}
|
||||
@@ -169,7 +170,9 @@ function readBooleanParam(params: Record<string, unknown>, key: string): boolean
|
||||
}
|
||||
|
||||
function normalizeOutputFormat(raw: string | undefined): MusicGenerationOutputFormat | undefined {
|
||||
const normalized = raw?.trim().toLowerCase() as MusicGenerationOutputFormat | undefined;
|
||||
const normalized = normalizeOptionalLowercaseString(raw) as
|
||||
| MusicGenerationOutputFormat
|
||||
| undefined;
|
||||
if (!normalized) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import crypto from "node:crypto";
|
||||
import { parseTimeoutMs } from "../../cli/parse-timeout.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { jsonResult, readStringParam } from "./common.js";
|
||||
import type { GatewayCallOptions } from "./gateway.js";
|
||||
import { callGatewayTool } from "./gateway.js";
|
||||
@@ -53,10 +54,7 @@ export async function executeNodeCommandAction(params: {
|
||||
case "notifications_action": {
|
||||
const node = readStringParam(params.input, "node", { required: true });
|
||||
const notificationKey = readStringParam(params.input, "notificationKey", { required: true });
|
||||
const notificationAction =
|
||||
typeof params.input.notificationAction === "string"
|
||||
? params.input.notificationAction.trim().toLowerCase()
|
||||
: "";
|
||||
const notificationAction = normalizeLowercaseStringOrEmpty(params.input.notificationAction);
|
||||
if (
|
||||
notificationAction !== "open" &&
|
||||
notificationAction !== "dismiss" &&
|
||||
@@ -118,7 +116,7 @@ export async function executeNodeCommandAction(params: {
|
||||
const node = readStringParam(params.input, "node", { required: true });
|
||||
const nodeId = await resolveNodeId(params.gatewayOpts, node);
|
||||
const invokeCommand = readStringParam(params.input, "invokeCommand", { required: true });
|
||||
const invokeCommandNormalized = invokeCommand.trim().toLowerCase();
|
||||
const invokeCommandNormalized = normalizeLowercaseStringOrEmpty(invokeCommand);
|
||||
if (BLOCKED_INVOKE_COMMANDS.has(invokeCommandNormalized)) {
|
||||
throw new Error(
|
||||
`invokeCommand "${invokeCommand}" is reserved for shell execution; use exec with host=node instead`,
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "../../config/sessions.js";
|
||||
import { callGateway } from "../../gateway/call.js";
|
||||
import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
|
||||
import { readStringValue } from "../../shared/string-coerce.js";
|
||||
import { normalizeOptionalLowercaseString, readStringValue } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
describeSessionsListTool,
|
||||
SESSIONS_LIST_TOOL_DISPLAY_SUMMARY,
|
||||
@@ -75,9 +75,9 @@ export function createSessionsListTool(opts?: {
|
||||
sandboxed: opts?.sandboxed === true,
|
||||
});
|
||||
|
||||
const kindsRaw = readStringArrayParam(params, "kinds")?.map((value) =>
|
||||
value.trim().toLowerCase(),
|
||||
);
|
||||
const kindsRaw = readStringArrayParam(params, "kinds")
|
||||
?.map((value) => normalizeOptionalLowercaseString(value))
|
||||
.filter(Boolean);
|
||||
const allowedKindsList = (kindsRaw ?? []).filter((value) =>
|
||||
["main", "group", "cron", "hook", "node", "other"].includes(value),
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { saveMediaBuffer } from "../../media/store.js";
|
||||
import { loadWebMedia } from "../../media/web-media.js";
|
||||
import { readSnakeCaseParamRaw } from "../../param-key.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../../utils.js";
|
||||
import type { DeliveryContext } from "../../utils/delivery-context.js";
|
||||
import {
|
||||
@@ -163,7 +164,7 @@ function resolveAction(args: Record<string, unknown>): "generate" | "list" | "st
|
||||
if (!raw) {
|
||||
return "generate";
|
||||
}
|
||||
const normalized = raw.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(raw);
|
||||
if (normalized === "generate" || normalized === "list" || normalized === "status") {
|
||||
return normalized;
|
||||
}
|
||||
@@ -205,7 +206,7 @@ function readBooleanParam(params: Record<string, unknown>, key: string): boolean
|
||||
return raw;
|
||||
}
|
||||
if (typeof raw === "string") {
|
||||
const normalized = raw.trim().toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(raw);
|
||||
if (normalized === "true") {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
|
||||
export type CacheEntry<T> = {
|
||||
value: T;
|
||||
expiresAt: number;
|
||||
@@ -20,7 +22,7 @@ export function resolveCacheTtlMs(value: unknown, fallbackMinutes: number): numb
|
||||
}
|
||||
|
||||
export function normalizeCacheKey(value: string): string {
|
||||
return value.trim().toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(value);
|
||||
}
|
||||
|
||||
export function readCache<T>(
|
||||
|
||||
Reference in New Issue
Block a user