refactor: dedupe browser string readers

This commit is contained in:
Peter Steinberger
2026-04-07 04:53:31 +01:00
parent 05e89ff117
commit 4dbe8f9f66
10 changed files with 41 additions and 36 deletions

View File

@@ -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<typeof browserAct>[1],
): Parameters<typeof browserAct>[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<AgentToolResult<unknown>> {
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",

View File

@@ -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<string, unknown>) {
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({

View File

@@ -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,
});
}

View File

@@ -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;

View File

@@ -1,3 +1,5 @@
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
type BrowserRequestProfileParams = {
query?: Record<string, unknown>;
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);
}

View File

@@ -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"

View File

@@ -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,

View File

@@ -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 };
};

View File

@@ -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,
};

View File

@@ -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<string, ExistingSessionProfile>();
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),
});
}
}