diff --git a/extensions/browser/src/browser-tool.actions.ts b/extensions/browser/src/browser-tool.actions.ts index bbd92145c04..dba6595f823 100644 --- a/extensions/browser/src/browser-tool.actions.ts +++ b/extensions/browser/src/browser-tool.actions.ts @@ -1,4 +1,5 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; +import { normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime"; import { DEFAULT_AI_SNAPSHOT_MAX_CHARS, browserAct, @@ -106,7 +107,7 @@ function formatConsoleToolResult(result: { content: [{ type: "text" as const, text: wrapped.wrappedText }], details: { ...wrapped.safeDetails, - targetId: typeof result.targetId === "string" ? result.targetId : undefined, + targetId: readStringValue(result.targetId), messageCount: Array.isArray(result.messages) ? result.messages.length : undefined, }, }; @@ -133,7 +134,7 @@ function isChromeStaleTargetError(profile: string | undefined, err: unknown): bo function stripTargetIdFromActRequest( request: Parameters[1], ): Parameters[1] | null { - const targetId = typeof request.targetId === "string" ? request.targetId.trim() : undefined; + const targetId = normalizeOptionalString(request.targetId); if (!targetId) { return null; } @@ -194,7 +195,7 @@ export async function executeSnapshotAction(params: { const refs: "aria" | "role" | undefined = input.refs === "aria" || input.refs === "role" ? input.refs : undefined; const hasMaxChars = Object.hasOwn(input, "maxChars"); - const targetId = typeof input.targetId === "string" ? input.targetId.trim() : undefined; + const targetId = normalizeOptionalString(input.targetId); const limit = typeof input.limit === "number" && Number.isFinite(input.limit) ? input.limit : undefined; const maxChars = @@ -205,8 +206,8 @@ export async function executeSnapshotAction(params: { const compact = typeof input.compact === "boolean" ? input.compact : undefined; const depth = typeof input.depth === "number" && Number.isFinite(input.depth) ? input.depth : undefined; - const selector = typeof input.selector === "string" ? input.selector.trim() : undefined; - const frame = typeof input.frame === "string" ? input.frame.trim() : undefined; + const selector = normalizeOptionalString(input.selector); + const frame = normalizeOptionalString(input.frame); const resolvedMaxChars = format === "ai" ? hasMaxChars @@ -314,8 +315,8 @@ export async function executeConsoleAction(params: { proxyRequest: BrowserProxyRequest | null; }): Promise> { const { input, baseUrl, profile, proxyRequest } = params; - const level = typeof input.level === "string" ? input.level.trim() : undefined; - const targetId = typeof input.targetId === "string" ? input.targetId.trim() : undefined; + const level = normalizeOptionalString(input.level); + const targetId = normalizeOptionalString(input.targetId); if (proxyRequest) { const result = (await proxyRequest({ method: "GET", diff --git a/extensions/browser/src/browser-tool.ts b/extensions/browser/src/browser-tool.ts index cf0792fe316..0768763ea34 100644 --- a/extensions/browser/src/browser-tool.ts +++ b/extensions/browser/src/browser-tool.ts @@ -1,4 +1,5 @@ import crypto from "node:crypto"; +import { normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime"; import { executeActAction, executeConsoleAction, @@ -114,7 +115,7 @@ export const __testing = { }; function readOptionalTargetAndTimeout(params: Record) { - const targetId = typeof params.targetId === "string" ? params.targetId.trim() : undefined; + const targetId = normalizeOptionalString(params.targetId); const timeoutMs = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) ? params.timeoutMs @@ -647,7 +648,7 @@ export function createBrowserTool(opts?: { proxyRequest, }); case "pdf": { - const targetId = typeof params.targetId === "string" ? params.targetId.trim() : undefined; + const targetId = normalizeOptionalString(params.targetId); const result = proxyRequest ? ((await proxyRequest({ method: "POST", @@ -709,7 +710,7 @@ export function createBrowserTool(opts?: { } case "dialog": { const accept = Boolean(params.accept); - const promptText = typeof params.promptText === "string" ? params.promptText : undefined; + const promptText = readStringValue(params.promptText); const { targetId, timeoutMs } = readOptionalTargetAndTimeout(params); if (proxyRequest) { const result = await proxyRequest({ diff --git a/extensions/browser/src/browser/chrome-mcp.ts b/extensions/browser/src/browser/chrome-mcp.ts index 97b6246d1dc..5d8b765deed 100644 --- a/extensions/browser/src/browser/chrome-mcp.ts +++ b/extensions/browser/src/browser/chrome-mcp.ts @@ -4,6 +4,7 @@ import os from "node:os"; import path from "node:path"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; +import { readStringValue } from "openclaw/plugin-sdk/text-runtime"; import { asRecord } from "../record-shared.js"; import type { ChromeMcpSnapshotNode } from "./chrome-mcp.snapshot.js"; import type { BrowserTab } from "./client.js"; @@ -58,7 +59,7 @@ function asPages(value: unknown): ChromeMcpStructuredPage[] { } out.push({ id: record.id, - url: typeof record.url === "string" ? record.url : undefined, + url: readStringValue(record.url), selected: record.selected === true, }); } diff --git a/extensions/browser/src/browser/pw-tools-core.storage.ts b/extensions/browser/src/browser/pw-tools-core.storage.ts index 8126d66fa71..3ba77bf9735 100644 --- a/extensions/browser/src/browser/pw-tools-core.storage.ts +++ b/extensions/browser/src/browser/pw-tools-core.storage.ts @@ -1,3 +1,4 @@ +import { readStringValue } from "openclaw/plugin-sdk/text-runtime"; import { ensurePageState, getPageForTargetId } from "./pw-session.js"; export async function cookiesGetViaPlaywright(opts: { @@ -63,7 +64,7 @@ export async function storageGetViaPlaywright(opts: { const page = await getPageForTargetId(opts); ensurePageState(page); const kind = opts.kind; - const key = typeof opts.key === "string" ? opts.key : undefined; + const key = readStringValue(opts.key); const values = await page.evaluate( ({ kind: kind2, key: key2 }) => { const store = kind2 === "session" ? window.sessionStorage : window.localStorage; diff --git a/extensions/browser/src/browser/request-policy.ts b/extensions/browser/src/browser/request-policy.ts index 6288c6b11a6..532e129a543 100644 --- a/extensions/browser/src/browser/request-policy.ts +++ b/extensions/browser/src/browser/request-policy.ts @@ -1,3 +1,5 @@ +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; + type BrowserRequestProfileParams = { query?: Record; body?: unknown; @@ -30,20 +32,16 @@ export function isPersistentBrowserProfileMutation(method: string, path: string) export function resolveRequestedBrowserProfile( params: BrowserRequestProfileParams, ): string | undefined { - const queryProfile = - typeof params.query?.profile === "string" ? params.query.profile.trim() : undefined; + const queryProfile = normalizeOptionalString(params.query?.profile); if (queryProfile) { return queryProfile; } if (params.body && typeof params.body === "object") { const bodyProfile = - "profile" in params.body && typeof params.body.profile === "string" - ? params.body.profile.trim() - : undefined; + "profile" in params.body ? normalizeOptionalString(params.body.profile) : undefined; if (bodyProfile) { return bodyProfile; } } - const explicitProfile = typeof params.profile === "string" ? params.profile.trim() : undefined; - return explicitProfile || undefined; + return normalizeOptionalString(params.profile); } diff --git a/extensions/browser/src/browser/routes/agent.snapshot.plan.ts b/extensions/browser/src/browser/routes/agent.snapshot.plan.ts index 6c913400d90..3ca6c57d4ba 100644 --- a/extensions/browser/src/browser/routes/agent.snapshot.plan.ts +++ b/extensions/browser/src/browser/routes/agent.snapshot.plan.ts @@ -1,3 +1,4 @@ +import { readStringValue } from "openclaw/plugin-sdk/text-runtime"; import type { ResolvedBrowserProfile } from "../config.js"; import { DEFAULT_AI_SNAPSHOT_EFFICIENT_DEPTH, @@ -41,14 +42,13 @@ export function resolveSnapshotPlan(params: { explicitFormat, mode, }); - const limitRaw = typeof params.query.limit === "string" ? Number(params.query.limit) : undefined; + const limitRaw = readStringValue(params.query.limit); const hasMaxChars = Object.hasOwn(params.query, "maxChars"); - const maxCharsRaw = - typeof params.query.maxChars === "string" ? Number(params.query.maxChars) : undefined; - const limit = Number.isFinite(limitRaw) ? limitRaw : undefined; + const maxCharsRaw = readStringValue(params.query.maxChars); + const limit = Number.isFinite(Number(limitRaw)) ? Number(limitRaw) : undefined; const maxChars = - typeof maxCharsRaw === "number" && Number.isFinite(maxCharsRaw) && maxCharsRaw > 0 - ? Math.floor(maxCharsRaw) + Number.isFinite(Number(maxCharsRaw)) && Number(maxCharsRaw) > 0 + ? Math.floor(Number(maxCharsRaw)) : undefined; const resolvedMaxChars = format === "ai" diff --git a/extensions/browser/src/browser/routes/agent.storage.ts b/extensions/browser/src/browser/routes/agent.storage.ts index 86830ab27ce..0a7de56aa8f 100644 --- a/extensions/browser/src/browser/routes/agent.storage.ts +++ b/extensions/browser/src/browser/routes/agent.storage.ts @@ -1,3 +1,4 @@ +import { readStringValue } from "openclaw/plugin-sdk/text-runtime"; import type { BrowserRouteContext } from "../server-context.js"; import { readBody, @@ -292,7 +293,7 @@ export function registerBrowserAgentStorageRoutes( const targetId = resolveTargetIdFromBody(body); const clear = toBoolean(body.clear) ?? false; const username = toStringOrEmpty(body.username) || undefined; - const password = typeof body.password === "string" ? body.password : undefined; + const password = readStringValue(body.password); await withPlaywrightRouteContext({ req, diff --git a/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts b/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts index b570abfb02e..ed131b83082 100644 --- a/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts +++ b/extensions/browser/src/cli/browser-cli-actions-input/register.files-downloads.ts @@ -1,4 +1,5 @@ import type { Command } from "commander"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { callBrowserRequest, type BrowserParentOpts } from "../browser-cli-shared.js"; import { danger, @@ -57,8 +58,7 @@ export function registerBrowserFilesAndDownloadsCommands( ) { const resolveTimeoutAndTarget = (opts: { timeoutMs?: unknown; targetId?: unknown }) => { const timeoutMs = Number.isFinite(opts.timeoutMs) ? Number(opts.timeoutMs) : undefined; - const targetId = - typeof opts.targetId === "string" ? opts.targetId.trim() || undefined : undefined; + const targetId = normalizeOptionalString(opts.targetId); return { timeoutMs, targetId }; }; diff --git a/extensions/browser/src/cli/browser-cli-debug.ts b/extensions/browser/src/cli/browser-cli-debug.ts index 7438480bdfa..d1dadb3df66 100644 --- a/extensions/browser/src/cli/browser-cli-debug.ts +++ b/extensions/browser/src/cli/browser-cli-debug.ts @@ -1,4 +1,5 @@ import type { Command } from "commander"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { runCommandWithRuntime } from "../core-api.js"; import { callBrowserRequest, type BrowserParentOpts } from "./browser-cli-shared.js"; import { danger, defaultRuntime, shortenHomePath } from "./core-api.js"; @@ -59,8 +60,8 @@ function resolveDebugQuery(params: { filter?: unknown; }) { return { - targetId: typeof params.targetId === "string" ? params.targetId.trim() || undefined : undefined, - filter: typeof params.filter === "string" ? params.filter.trim() || undefined : undefined, + targetId: normalizeOptionalString(params.targetId), + filter: normalizeOptionalString(params.filter), clear: Boolean(params.clear), profile: params.profile, }; diff --git a/extensions/browser/src/doctor-browser.ts b/extensions/browser/src/doctor-browser.ts index 798f939ee61..ccef7b6021b 100644 --- a/extensions/browser/src/doctor-browser.ts +++ b/extensions/browser/src/doctor-browser.ts @@ -1,4 +1,5 @@ import { note } from "openclaw/plugin-sdk/browser-setup-tools"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { parseBrowserMajorVersion, readBrowserVersion, @@ -26,8 +27,7 @@ function collectChromeMcpProfiles(cfg: OpenClawConfig): ExistingSessionProfile[] } const profiles = new Map(); - const defaultProfile = - typeof browser.defaultProfile === "string" ? browser.defaultProfile.trim() : ""; + const defaultProfile = normalizeOptionalString(browser.defaultProfile) ?? ""; if (defaultProfile === "user") { profiles.set("user", { name: "user" }); } @@ -39,11 +39,12 @@ function collectChromeMcpProfiles(cfg: OpenClawConfig): ExistingSessionProfile[] for (const [profileName, rawProfile] of Object.entries(configuredProfiles)) { const profile = asRecord(rawProfile); - const driver = typeof profile?.driver === "string" ? profile.driver.trim() : ""; + const driver = normalizeOptionalString(profile?.driver) ?? ""; if (driver === "existing-session") { - const userDataDir = - typeof profile?.userDataDir === "string" ? profile.userDataDir.trim() : undefined; - profiles.set(profileName, { name: profileName, userDataDir: userDataDir || undefined }); + profiles.set(profileName, { + name: profileName, + userDataDir: normalizeOptionalString(profile?.userDataDir), + }); } }