mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 21:23:23 +00:00
refactor: dedupe agent lowercase helpers
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
type SimpleStreamOptions,
|
||||
type ThinkingLevel,
|
||||
} from "@mariozechner/pi-ai";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import {
|
||||
applyAnthropicPayloadPolicyToParams,
|
||||
resolveAnthropicPayloadPolicy,
|
||||
@@ -154,13 +155,15 @@ function isAnthropicOAuthToken(apiKey: string): boolean {
|
||||
}
|
||||
|
||||
function toClaudeCodeName(name: string): string {
|
||||
return CLAUDE_CODE_TOOL_LOOKUP.get(name.toLowerCase()) ?? name;
|
||||
return CLAUDE_CODE_TOOL_LOOKUP.get(normalizeLowercaseStringOrEmpty(name)) ?? name;
|
||||
}
|
||||
|
||||
function fromClaudeCodeName(name: string, tools: Context["tools"] | undefined): string {
|
||||
if (tools && tools.length > 0) {
|
||||
const lowerName = name.toLowerCase();
|
||||
const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
|
||||
const lowerName = normalizeLowercaseStringOrEmpty(name);
|
||||
const matchedTool = tools.find(
|
||||
(tool) => normalizeLowercaseStringOrEmpty(tool.name) === lowerName,
|
||||
);
|
||||
if (matchedTool) {
|
||||
return matchedTool.name;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
type BundleMcpServerConfig,
|
||||
} from "../../plugins/bundle-mcp.js";
|
||||
import type { CliBundleMcpMode } from "../../plugins/types.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
|
||||
type PreparedCliBundleMcpConfig = {
|
||||
backend: CliBackendConfig;
|
||||
@@ -142,7 +145,7 @@ function normalizeCodexServerConfig(server: BundleMcpServerConfig): Record<strin
|
||||
staticHeaders[name] = value;
|
||||
continue;
|
||||
}
|
||||
if (decoded.bearer && name.toLowerCase() === "authorization") {
|
||||
if (decoded.bearer && normalizeOptionalLowercaseString(name) === "authorization") {
|
||||
next.bearer_token_env_var = decoded.envVar;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@ import type { CliBackendConfig } from "../../config/types.js";
|
||||
import { resolvePreferredOpenClawTmpDir } from "../../infra/tmp-openclaw-dir.js";
|
||||
import { MAX_IMAGE_BYTES } from "../../media/constants.js";
|
||||
import { extensionForMime } from "../../media/mime.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
import { buildTtsSystemPromptHint } from "../../tts/tts.js";
|
||||
import { buildModelAliasLines } from "../model-alias-lines.js";
|
||||
import { resolveDefaultModelForAgent } from "../model-selection.js";
|
||||
@@ -126,7 +129,7 @@ export function normalizeCliModel(modelId: string, backend: CliBackendConfig): s
|
||||
if (direct) {
|
||||
return direct;
|
||||
}
|
||||
const lower = trimmed.toLowerCase();
|
||||
const lower = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
const mapped = backend.modelAliases?.[lower];
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import type { AssistantMessage, Message, Tool } from "@mariozechner/pi-ai";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import {
|
||||
LIVE_CACHE_REGRESSION_BASELINE,
|
||||
type LiveCacheFloor,
|
||||
@@ -217,8 +218,10 @@ async function completeCacheProbe(params: {
|
||||
timeoutMs,
|
||||
);
|
||||
const text = extractAssistantText(response);
|
||||
const responseTextLower = normalizeLowercaseStringOrEmpty(text);
|
||||
const suffixLower = normalizeLowercaseStringOrEmpty(params.suffix);
|
||||
assert(
|
||||
text.toLowerCase().includes(params.suffix.toLowerCase()),
|
||||
responseTextLower.includes(suffixLower),
|
||||
`expected response to contain ${params.suffix}, got ${JSON.stringify(text)}`,
|
||||
);
|
||||
const usage = normalizeCacheUsage(response.usage);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveOwningPluginIdsForProvider } from "../plugins/providers.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { normalizeProviderId } from "./provider-id.js";
|
||||
|
||||
type ModelTarget = {
|
||||
@@ -33,14 +36,11 @@ function parseModelTarget(raw: string): ModelTarget | null {
|
||||
if (slash === -1) {
|
||||
return {
|
||||
raw: trimmed,
|
||||
modelId: trimmed.toLowerCase(),
|
||||
modelId: normalizeLowercaseStringOrEmpty(trimmed),
|
||||
};
|
||||
}
|
||||
const provider = normalizeProviderId(trimmed.slice(0, slash));
|
||||
const modelId = trimmed
|
||||
.slice(slash + 1)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
const modelId = normalizeLowercaseStringOrEmpty(trimmed.slice(slash + 1));
|
||||
if (!provider || !modelId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
shouldDeferProviderSyntheticProfileAuthWithPlugin,
|
||||
} from "../plugins/provider-runtime.js";
|
||||
import { resolveOwningPluginIdsForProvider } from "../plugins/providers.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import { normalizeOptionalSecretInput } from "../utils/normalize-secret-input.js";
|
||||
import {
|
||||
type AuthProfileStore,
|
||||
@@ -717,7 +718,7 @@ export function applyAuthHeaderOverride<T extends Model<Api>>(
|
||||
const headers: Record<string, string> = {};
|
||||
if (model.headers) {
|
||||
for (const [key, value] of Object.entries(model.headers)) {
|
||||
if (key.toLowerCase() !== "authorization") {
|
||||
if (normalizeOptionalLowercaseString(key) !== "authorization") {
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ export function inferUniqueProviderFromConfiguredModels(params: {
|
||||
if (!parsed) {
|
||||
continue;
|
||||
}
|
||||
if (parsed.model === model || parsed.model.toLowerCase() === normalized) {
|
||||
if (parsed.model === model || normalizeLowercaseStringOrEmpty(parsed.model) === normalized) {
|
||||
addProvider(parsed.provider);
|
||||
if (providers.size > 1) {
|
||||
return undefined;
|
||||
@@ -218,7 +218,7 @@ export function inferUniqueProviderFromConfiguredModels(params: {
|
||||
if (!modelId) {
|
||||
continue;
|
||||
}
|
||||
if (modelId === model || modelId.toLowerCase() === normalized) {
|
||||
if (modelId === model || normalizeLowercaseStringOrEmpty(modelId) === normalized) {
|
||||
addProvider(providerId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
encodeAssistantTextSignature,
|
||||
normalizeAssistantPhase,
|
||||
} from "../shared/chat-message-content.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { resolveOpenAIStrictToolSetting } from "./openai-tool-schema.js";
|
||||
import {
|
||||
getOpenAIWebSocketErrorDetails,
|
||||
@@ -347,7 +348,7 @@ function isOpenAIApiBaseUrl(baseUrl?: string): boolean {
|
||||
const url = new URL(trimmed);
|
||||
return (
|
||||
url.protocol === "https:" &&
|
||||
url.hostname.toLowerCase() === "api.openai.com" &&
|
||||
normalizeLowercaseStringOrEmpty(url.hostname) === "api.openai.com" &&
|
||||
/^\/v1\/?$/u.test(url.pathname)
|
||||
);
|
||||
} catch {
|
||||
@@ -369,7 +370,7 @@ function isAzureOpenAIBaseUrl(baseUrl?: string): boolean {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return new URL(trimmed).hostname.toLowerCase().endsWith(".openai.azure.com");
|
||||
return normalizeLowercaseStringOrEmpty(new URL(trimmed).hostname).endsWith(".openai.azure.com");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -671,13 +671,15 @@ function isProvider(provider: string | undefined, match: string): boolean {
|
||||
|
||||
function isAnthropicGenericUnknownError(raw: string, provider?: string): boolean {
|
||||
return (
|
||||
isProvider(provider, "anthropic") && raw.toLowerCase().includes("an unknown error occurred")
|
||||
isProvider(provider, "anthropic") &&
|
||||
(normalizeOptionalLowercaseString(raw)?.includes("an unknown error occurred") ?? false)
|
||||
);
|
||||
}
|
||||
|
||||
function isOpenRouterProviderReturnedError(raw: string, provider?: string): boolean {
|
||||
return (
|
||||
isProvider(provider, "openrouter") && raw.toLowerCase().includes("provider returned error")
|
||||
isProvider(provider, "openrouter") &&
|
||||
(normalizeOptionalLowercaseString(raw)?.includes("provider returned error") ?? false)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { normalizeProviderId } from "../provider-id.js";
|
||||
|
||||
const THREAD_SUFFIX_REGEX = /^(.*)(?::(?:thread|topic):\d+)$/i;
|
||||
@@ -57,7 +58,7 @@ export function getHistoryLimitFromSessionKey(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const kind = providerParts[1]?.toLowerCase();
|
||||
const kind = normalizeOptionalLowercaseString(providerParts[1]);
|
||||
const userIdRaw = providerParts.slice(2).join(":");
|
||||
const userId = stripThreadSuffix(userIdRaw);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ function normalizeOpenAIServiceTier(value: unknown): OpenAIServiceTier | undefin
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = readStringValue(value)?.toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(value);
|
||||
if (
|
||||
normalized === "auto" ||
|
||||
normalized === "default" ||
|
||||
@@ -110,7 +110,7 @@ function normalizeOpenAITextVerbosity(value: unknown): OpenAITextVerbosity | und
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = readStringValue(value)?.toLowerCase();
|
||||
const normalized = normalizeOptionalLowercaseString(value);
|
||||
if (normalized === "low" || normalized === "medium" || normalized === "high") {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { AgentMessage, StreamFn } from "@mariozechner/pi-agent-core";
|
||||
import { streamSimple } from "@mariozechner/pi-ai";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../../shared/string-coerce.js";
|
||||
import { validateAnthropicTurns, validateGeminiTurns } from "../../pi-embedded-helpers.js";
|
||||
import { sanitizeToolUseResultPairing } from "../../session-transcript-repair.js";
|
||||
import { normalizeToolName } from "../../tool-policy.js";
|
||||
@@ -12,10 +13,10 @@ function resolveCaseInsensitiveAllowedToolName(
|
||||
if (!allowedToolNames || allowedToolNames.size === 0) {
|
||||
return null;
|
||||
}
|
||||
const folded = rawName.toLowerCase();
|
||||
const folded = normalizeLowercaseStringOrEmpty(rawName);
|
||||
let caseInsensitiveMatch: string | null = null;
|
||||
for (const name of allowedToolNames) {
|
||||
if (name.toLowerCase() !== folded) {
|
||||
if (normalizeLowercaseStringOrEmpty(name) !== folded) {
|
||||
continue;
|
||||
}
|
||||
if (caseInsensitiveMatch && caseInsensitiveMatch !== name) {
|
||||
|
||||
@@ -44,7 +44,7 @@ const RECOVERABLE_TOOL_ERROR_KEYWORDS = [
|
||||
] as const;
|
||||
|
||||
function isRecoverableToolError(error: string | undefined): boolean {
|
||||
const errorLower = (error ?? "").toLowerCase();
|
||||
const errorLower = normalizeOptionalLowercaseString(error) ?? "";
|
||||
return RECOVERABLE_TOOL_ERROR_KEYWORDS.some((keyword) => errorLower.includes(keyword));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ModelCompatConfig } from "../config/types.models.js";
|
||||
import { stripUnsupportedSchemaKeywords } from "../plugin-sdk/provider-tools.js";
|
||||
import { resolveUnsupportedToolSchemaKeywords } from "../plugins/provider-model-compat.js";
|
||||
import { copyPluginToolMeta } from "../plugins/tools.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { copyChannelAgentToolMeta } from "./channel-tools.js";
|
||||
import type { AnyAgentTool } from "./pi-tools.types.js";
|
||||
import { cleanSchemaForGemini } from "./schema/clean-for-gemini.js";
|
||||
@@ -145,10 +146,10 @@ export function normalizeToolParameterSchema(
|
||||
// - xAI rejects validation-constraint keywords (minLength, maxLength, etc.) outright.
|
||||
//
|
||||
// Normalize once here so callers can always pass `tools` through unchanged.
|
||||
const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
|
||||
const isGeminiProvider =
|
||||
options?.modelProvider?.toLowerCase().includes("google") ||
|
||||
options?.modelProvider?.toLowerCase().includes("gemini");
|
||||
const isAnthropicProvider = options?.modelProvider?.toLowerCase().includes("anthropic");
|
||||
normalizedProvider.includes("google") || normalizedProvider.includes("gemini");
|
||||
const isAnthropicProvider = normalizedProvider.includes("anthropic");
|
||||
const unsupportedToolSchemaKeywords = resolveUnsupportedToolSchemaKeywords(options?.modelCompat);
|
||||
|
||||
function applyProviderCleaning(s: unknown): unknown {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||
import { normalizeOptionalString, readStringValue } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
readStringValue,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { extractToolCallsFromAssistant, extractToolResultId } from "./tool-call-id.js";
|
||||
|
||||
const TOOL_CALL_NAME_MAX_CHARS = 64;
|
||||
@@ -50,7 +54,7 @@ function normalizeAllowedToolNames(allowedToolNames?: Iterable<string>): Set<str
|
||||
}
|
||||
const trimmed = name.trim();
|
||||
if (trimmed) {
|
||||
normalized.add(trimmed.toLowerCase());
|
||||
normalized.add(normalizeLowercaseStringOrEmpty(trimmed));
|
||||
}
|
||||
}
|
||||
return normalized.size > 0 ? normalized : null;
|
||||
@@ -70,7 +74,7 @@ function hasToolCallName(block: RawToolCallBlock, allowedToolNames: Set<string>
|
||||
if (!allowedToolNames) {
|
||||
return true;
|
||||
}
|
||||
return allowedToolNames.has(trimmed.toLowerCase());
|
||||
return allowedToolNames.has(normalizeLowercaseStringOrEmpty(trimmed));
|
||||
}
|
||||
|
||||
function redactSessionsSpawnAttachmentsArgs(value: unknown): unknown {
|
||||
@@ -103,7 +107,7 @@ function sanitizeToolCallBlock(block: RawToolCallBlock): RawToolCallBlock {
|
||||
const normalizedName = hasTrimmedName ? trimmedName : undefined;
|
||||
const nameChanged = hasTrimmedName && rawName !== trimmedName;
|
||||
|
||||
const isSessionsSpawn = normalizedName?.toLowerCase() === "sessions_spawn";
|
||||
const isSessionsSpawn = normalizeLowercaseStringOrEmpty(normalizedName) === "sessions_spawn";
|
||||
|
||||
if (!isSessionsSpawn) {
|
||||
if (!nameChanged) {
|
||||
@@ -264,7 +268,7 @@ export function repairToolCallInputs(
|
||||
typeof (block as { name?: unknown }).name === "string"
|
||||
? (block as { name: string }).name.trim()
|
||||
: undefined;
|
||||
if (blockName?.toLowerCase() === "sessions_spawn") {
|
||||
if (normalizeLowercaseStringOrEmpty(blockName) === "sessions_spawn") {
|
||||
const sanitized = sanitizeToolCallBlock(block);
|
||||
if (sanitized !== block) {
|
||||
changed = true;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { resolveStorePath } from "../config/sessions/paths.js";
|
||||
import { loadSessionStore } from "../config/sessions/store-load.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import { parseAgentSessionKey, type ParsedAgentSessionKey } from "../routing/session-key.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import {
|
||||
formatDurationCompact,
|
||||
formatTokenUsageDisplay,
|
||||
@@ -234,7 +235,7 @@ export function buildSubagentList(params: {
|
||||
const runtime = formatDurationCompact(runtimeMs) ?? "n/a";
|
||||
const label = truncateLine(resolveSubagentLabel(entry), 48);
|
||||
const task = truncateLine(entry.task.trim(), params.taskMaxChars ?? 72);
|
||||
const line = `${index}. ${label} (${resolveModelDisplay(sessionEntry, entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${task.toLowerCase() !== label.toLowerCase() ? ` - ${task}` : ""}`;
|
||||
const line = `${index}. ${label} (${resolveModelDisplay(sessionEntry, entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${normalizeLowercaseStringOrEmpty(task) !== normalizeLowercaseStringOrEmpty(label) ? ` - ${task}` : ""}`;
|
||||
const view: SubagentListItem = {
|
||||
index,
|
||||
line,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
type SessionEntry,
|
||||
} from "../config/sessions.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { type SubagentRunOutcome } from "./subagent-announce.js";
|
||||
import { SUBAGENT_ENDED_REASON_ERROR } from "./subagent-lifecycle-events.js";
|
||||
import { runOutcomesEqual } from "./subagent-registry-completion.js";
|
||||
@@ -76,9 +77,9 @@ function findSessionEntryByKey(store: Record<string, SessionEntry>, sessionKey:
|
||||
if (direct) {
|
||||
return direct;
|
||||
}
|
||||
const normalized = sessionKey.toLowerCase();
|
||||
const normalized = normalizeLowercaseStringOrEmpty(sessionKey);
|
||||
for (const [key, entry] of Object.entries(store)) {
|
||||
if (key.toLowerCase() === normalized) {
|
||||
if (normalizeLowercaseStringOrEmpty(key) === normalized) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { getPluginToolMeta } from "../plugins/tools.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { resolveAgentDir, resolveAgentWorkspaceDir, resolveSessionAgentId } from "./agent-scope.js";
|
||||
import { getChannelAgentToolMeta } from "./channel-tools.js";
|
||||
import { resolveModel } from "./pi-embedded-runner/model.js";
|
||||
@@ -63,7 +64,10 @@ export type ResolveEffectiveToolInventoryParams = {
|
||||
|
||||
function resolveEffectiveToolLabel(tool: AnyAgentTool): string {
|
||||
const rawLabel = typeof tool.label === "string" ? tool.label.trim() : "";
|
||||
if (rawLabel && rawLabel.toLowerCase() !== tool.name.toLowerCase()) {
|
||||
if (
|
||||
rawLabel &&
|
||||
normalizeLowercaseStringOrEmpty(rawLabel) !== normalizeLowercaseStringOrEmpty(tool.name)
|
||||
) {
|
||||
return rawLabel;
|
||||
}
|
||||
return resolveToolDisplay({ name: tool.name }).title;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { parseNodeList, parsePairingList } from "../../shared/node-list-parse.js";
|
||||
import type { NodeListNode } from "../../shared/node-list-types.js";
|
||||
import { resolveNodeFromNodeList, resolveNodeIdFromNodeList } from "../../shared/node-resolve.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { callGatewayTool, type GatewayCallOptions } from "./gateway.js";
|
||||
|
||||
export type { NodeListNode };
|
||||
@@ -72,7 +73,7 @@ async function loadNodes(opts: GatewayCallOptions): Promise<NodeListNode[]> {
|
||||
|
||||
function isLocalMacNode(node: NodeListNode): boolean {
|
||||
return (
|
||||
node.platform?.toLowerCase().startsWith("mac") === true &&
|
||||
normalizeOptionalLowercaseString(node.platform)?.startsWith("mac") === true &&
|
||||
typeof node.nodeId === "string" &&
|
||||
node.nodeId.startsWith("mac-")
|
||||
);
|
||||
|
||||
@@ -3,7 +3,10 @@ import { Type } from "@sinclair/typebox";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { extractPdfContent, type PdfExtractedContent } from "../../media/pdf-extract.js";
|
||||
import { loadWebMediaRaw } from "../../media/web-media.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../../utils.js";
|
||||
import { type ImageModelConfig } from "./image-tool.helpers.js";
|
||||
import {
|
||||
@@ -393,7 +396,7 @@ export function createPdfTool(options?: {
|
||||
|
||||
if (media.kind !== "document") {
|
||||
// Check MIME type more specifically
|
||||
const ct = (media.contentType ?? "").toLowerCase();
|
||||
const ct = normalizeLowercaseStringOrEmpty(media.contentType);
|
||||
if (!ct.includes("pdf") && !ct.includes("application/pdf")) {
|
||||
throw new Error(`Expected PDF but got ${media.contentType ?? media.kind}: ${pdfRaw}`);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
resolveAgentIdFromSessionKey,
|
||||
} from "../../routing/session-key.js";
|
||||
import { applyModelOverrideToSessionEntry } from "../../sessions/model-overrides.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { buildTaskStatusSnapshotForRelatedSessionKeyForOwner } from "../../tasks/task-owner-access.js";
|
||||
import { formatTaskStatusDetail, formatTaskStatusTitle } from "../../tasks/task-status.js";
|
||||
import { loadModelCatalog } from "../model-catalog.js";
|
||||
@@ -170,7 +171,7 @@ async function resolveModelOverride(params: {
|
||||
if (!raw) {
|
||||
return { kind: "reset" };
|
||||
}
|
||||
if (raw.toLowerCase() === "default") {
|
||||
if (normalizeOptionalLowercaseString(raw) === "default") {
|
||||
return { kind: "reset" };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
|
||||
// CSS property values that indicate an element is hidden
|
||||
const HIDDEN_STYLE_PATTERNS: Array<[string, RegExp]> = [
|
||||
["display", /^\s*none\s*$/i],
|
||||
@@ -94,7 +96,10 @@ function shouldRemoveElement(element: Element): boolean {
|
||||
}
|
||||
|
||||
// input type=hidden
|
||||
if (tagName === "input" && element.getAttribute("type")?.toLowerCase() === "hidden") {
|
||||
if (
|
||||
tagName === "input" &&
|
||||
normalizeOptionalLowercaseString(element.getAttribute("type")) === "hidden"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import { SsrFBlockedError, type LookupFn } from "../../infra/net/ssrf.js";
|
||||
import { logDebug } from "../../logger.js";
|
||||
import type { RuntimeWebFetchMetadata } from "../../secrets/runtime-web-tools.types.js";
|
||||
import { wrapExternalContent, wrapWebContent } from "../../security/external-content.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
import { isRecord } from "../../utils.js";
|
||||
import { resolveWebFetchDefinition } from "../../web-fetch/runtime.js";
|
||||
import { resolveWebProviderConfig } from "../../web/provider-runtime-shared.js";
|
||||
@@ -141,7 +144,7 @@ function formatWebFetchErrorDetail(params: {
|
||||
return "";
|
||||
}
|
||||
let text = detail;
|
||||
const contentTypeLower = contentType?.toLowerCase();
|
||||
const contentTypeLower = normalizeOptionalLowercaseString(contentType);
|
||||
if (contentTypeLower?.includes("text/html") || looksLikeHtml(detail)) {
|
||||
const rendered = htmlToMarkdown(detail);
|
||||
const withTitle = rendered.title ? `${rendered.title}\n${rendered.text}` : rendered.text;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { normalizeResolvedSecretInputString } from "../../config/types.secrets.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { normalizeSecretInput } from "../../utils/normalize-secret-input.js";
|
||||
import { withTrustedWebToolsEndpoint } from "./web-guarded-fetch.js";
|
||||
import {
|
||||
@@ -250,7 +251,7 @@ export function normalizeFreshness(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lower = trimmed.toLowerCase();
|
||||
const lower = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
if (BRAVE_FRESHNESS_SHORTCUTS.has(lower)) {
|
||||
return provider === "brave" ? lower : FRESHNESS_TO_RECENCY[lower];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { OpenClawConfig } from "../config/config.js";
|
||||
import { shouldPreserveThinkingBlocks } from "../plugins/provider-replay-helpers.js";
|
||||
import { resolveProviderRuntimePlugin } from "../plugins/provider-runtime.js";
|
||||
import type { ProviderReplayPolicy, ProviderRuntimeModel } from "../plugins/types.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { normalizeProviderId } from "./model-selection.js";
|
||||
import { isGoogleModelApi } from "./pi-embedded-helpers/google.js";
|
||||
import type { ToolCallIdMode } from "./tool-call-id.js";
|
||||
@@ -76,7 +77,7 @@ function buildUnownedProviderTransportReplayFallback(params: {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const modelId = params.modelId?.toLowerCase() ?? "";
|
||||
const modelId = normalizeLowercaseStringOrEmpty(params.modelId);
|
||||
return {
|
||||
...(isGoogle || isAnthropic ? { sanitizeMode: "full" as const } : {}),
|
||||
...(isGoogle || isAnthropic || requiresOpenAiCompatibleToolIdSanitization
|
||||
|
||||
@@ -6,7 +6,7 @@ import { openBoundaryFile } from "../infra/boundary-file-read.js";
|
||||
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import { isCronSessionKey, isSubagentSessionKey } from "../routing/session-key.js";
|
||||
import { readStringValue } from "../shared/string-coerce.js";
|
||||
import { normalizeOptionalLowercaseString, readStringValue } from "../shared/string-coerce.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { resolveWorkspaceTemplateDir } from "./workspace-templates.js";
|
||||
|
||||
@@ -16,7 +16,7 @@ export function resolveDefaultAgentWorkspaceDir(
|
||||
): string {
|
||||
const home = resolveRequiredHomeDir(env, homedir);
|
||||
const profile = env.OPENCLAW_PROFILE?.trim();
|
||||
if (profile && profile.toLowerCase() !== "default") {
|
||||
if (profile && normalizeOptionalLowercaseString(profile) !== "default") {
|
||||
return path.join(home, ".openclaw", `workspace-${profile}`);
|
||||
}
|
||||
return path.join(home, ".openclaw", "workspace");
|
||||
|
||||
Reference in New Issue
Block a user