refactor: dedupe web provider lower readers

This commit is contained in:
Peter Steinberger
2026-04-07 11:57:18 +01:00
parent d6132e10f4
commit bbe5a4b31a
9 changed files with 33 additions and 29 deletions

View File

@@ -18,6 +18,7 @@ import {
discoverConfigSecretTargetsByIds,
type DiscoveredConfigSecretTarget,
} from "../secrets/target-registry.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
type ResolveCommandSecretsResult = {
@@ -147,8 +148,7 @@ function classifyRuntimeWebTargetPathState(params: {
if (fetch?.enabled === false) {
return "inactive";
}
const configuredProvider =
typeof fetch?.provider === "string" ? fetch.provider.trim().toLowerCase() : "";
const configuredProvider = normalizeLowercaseStringOrEmpty(fetch?.provider);
if (!configuredProvider) {
return "active";
}
@@ -165,8 +165,7 @@ function classifyRuntimeWebTargetPathState(params: {
if (search?.enabled === false) {
return "inactive";
}
const configuredProvider =
typeof search?.provider === "string" ? search.provider.trim().toLowerCase() : "";
const configuredProvider = normalizeLowercaseStringOrEmpty(search?.provider);
if (!configuredProvider) {
return "active";
}
@@ -216,8 +215,7 @@ function describeInactiveRuntimeWebTargetPath(params: {
if (fetch?.enabled === false) {
return "tools.web.fetch is disabled.";
}
const configuredProvider =
typeof fetch?.provider === "string" ? fetch.provider.trim().toLowerCase() : "";
const configuredProvider = normalizeLowercaseStringOrEmpty(fetch?.provider);
if (configuredProvider) {
return `tools.web.fetch.provider is "${configuredProvider}".`;
}
@@ -227,8 +225,7 @@ function describeInactiveRuntimeWebTargetPath(params: {
if (search?.enabled === false) {
return "tools.web.search is disabled.";
}
const configuredProvider =
typeof search?.provider === "string" ? search.provider.trim().toLowerCase() : "";
const configuredProvider = normalizeLowercaseStringOrEmpty(search?.provider);
const configuredPluginId = configuredProvider
? commandSecretGatewayDeps.resolveManifestContractOwnerPluginId({
contract: "webSearchProviders",

View File

@@ -12,6 +12,7 @@ import {
} from "../plugins/manifest-registry.js";
import { resolveOwningPluginIdsForModelRef } from "../plugins/providers.js";
import { resolvePluginSetupAutoEnableReasons } from "../plugins/setup-registry.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import { isRecord } from "../utils.js";
import { isChannelConfigured } from "./channel-configured.js";
import type { OpenClawConfig } from "./config.js";
@@ -226,7 +227,7 @@ function resolvePluginIdForConfiguredWebFetchProvider(
): string | undefined {
return resolveManifestContractOwnerPluginId({
contract: "webFetchProviders",
value: typeof providerId === "string" ? providerId.trim().toLowerCase() : "",
value: normalizeOptionalLowercaseString(providerId) ?? "",
origin: "bundled",
env,
});

View File

@@ -70,9 +70,13 @@ export {
cloneFirstTemplateModel,
matchesExactOrPrefix,
} from "../plugins/provider-model-helpers.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
export function getModelProviderHint(modelId: string): string | null {
const trimmed = modelId.trim().toLowerCase();
const trimmed = normalizeOptionalLowercaseString(modelId);
if (!trimmed) {
return null;
}
const slashIndex = trimmed.indexOf("/");
if (slashIndex <= 0) {
return null;

View File

@@ -9,6 +9,7 @@ import type { OpenClawConfig } from "../config/config.js";
import type { SecretProviderConfig, SecretRef, SecretRefSource } from "../config/types.secrets.js";
import { isSafeExecutableValue } from "../infra/exec-safety.js";
import { normalizeAgentId } from "../routing/session-key.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import { runSecretsApply, type SecretsApplyResult } from "./apply.js";
import { createSecretsConfigIO } from "./config-io.js";
import {
@@ -233,13 +234,10 @@ function hasSourceChoice(
}
function resolveCandidateProviderHint(candidate: ConfigureCandidate): string | undefined {
if (typeof candidate.authProfileProvider === "string" && candidate.authProfileProvider.trim()) {
return candidate.authProfileProvider.trim().toLowerCase();
}
if (typeof candidate.providerId === "string" && candidate.providerId.trim()) {
return candidate.providerId.trim().toLowerCase();
}
return undefined;
return (
normalizeOptionalLowercaseString(candidate.authProfileProvider) ??
normalizeOptionalLowercaseString(candidate.providerId)
);
}
function resolveSuggestedEnvSecretId(candidate: ConfigureCandidate): string | undefined {

View File

@@ -5,6 +5,7 @@ import {
resolveEffectiveMediaEntryCapabilities,
} from "../media-understanding/entry-capabilities.js";
import { buildMediaUnderstandingRegistry } from "../media-understanding/provider-registry.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import { collectTtsApiKeyAssignments } from "./runtime-config-collectors-tts.js";
import { evaluateGatewayAuthSurfaceStates } from "./runtime-gateway-auth-surfaces.js";
import {
@@ -564,7 +565,8 @@ function collectSandboxSshAssignments(params: {
"docker";
const effectiveMode =
(typeof sandbox?.mode === "string" ? sandbox.mode : undefined) ?? defaultsMode ?? "off";
const active = effectiveBackend.trim().toLowerCase() === "ssh" && effectiveMode !== "off";
const active =
normalizeOptionalLowercaseString(effectiveBackend) === "ssh" && effectiveMode !== "off";
for (const key of ["identityData", "certificateData", "knownHostsData"] as const) {
if (ssh && Object.prototype.hasOwnProperty.call(ssh, key)) {
collectSecretInputAssignment({
@@ -590,7 +592,7 @@ function collectSandboxSshAssignments(params: {
}
const defaultsActive =
(defaultsBackend?.trim().toLowerCase() === "ssh" && defaultsMode !== "off") ||
(normalizeOptionalLowercaseString(defaultsBackend) === "ssh" && defaultsMode !== "off") ||
inheritedDefaultsUsage.identityData ||
inheritedDefaultsUsage.certificateData ||
inheritedDefaultsUsage.knownHostsData;

View File

@@ -1,6 +1,7 @@
import type { OpenClawConfig } from "../config/config.js";
import { resolveSecretInputRef } from "../config/types.secrets.js";
import { resolveManifestContractOwnerPluginId } from "../plugins/manifest-registry.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import type {
ResolverContext,
SecretDefaults,
@@ -95,10 +96,10 @@ export function normalizeKnownProvider<TProvider extends { id: string }>(
value: unknown,
providers: TProvider[],
): string | undefined {
if (typeof value !== "string") {
const normalized = normalizeOptionalLowercaseString(value);
if (!normalized) {
return undefined;
}
const normalized = value.trim().toLowerCase();
if (providers.some((provider) => provider.id === normalized)) {
return normalized;
}

View File

@@ -17,6 +17,7 @@ import {
} from "../plugins/web-provider-public-artifacts.explicit.js";
import { sortWebSearchProvidersForAutoDetect } from "../plugins/web-search-providers.shared.js";
import { createLazyRuntimeSurface } from "../shared/lazy-runtime.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
import { normalizeSecretInput } from "../utils/normalize-secret-input.js";
import { secretRefKey } from "./ref-contract.js";
import { resolveSecretRefValues } from "./resolve.js";
@@ -488,8 +489,7 @@ export async function resolveRuntimeWebTools(params: {
diagnostics,
};
}
const rawProvider =
typeof search?.provider === "string" ? search.provider.trim().toLowerCase() : "";
const rawProvider = normalizeLowercaseStringOrEmpty(search?.provider);
const searchMetadata: RuntimeWebSearchMetadata = {
providerSource: "none",
diagnostics: [],
@@ -605,8 +605,7 @@ export async function resolveRuntimeWebTools(params: {
});
}
const rawFetchProvider =
typeof fetch?.provider === "string" ? fetch.provider.trim().toLowerCase() : "";
const rawFetchProvider = normalizeLowercaseStringOrEmpty(fetch?.provider);
const fetchMetadata: RuntimeWebFetchMetadata = {
providerSource: "none",
diagnostics: [],

View File

@@ -8,6 +8,7 @@ import { resolvePluginWebFetchProviders } from "../plugins/web-fetch-providers.r
import { sortWebFetchProvidersForAutoDetect } from "../plugins/web-fetch-providers.shared.js";
import { getActiveRuntimeWebToolsMetadata } from "../secrets/runtime-web-tools-state.js";
import type { RuntimeWebFetchMetadata } from "../secrets/runtime-web-tools.types.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
import {
hasWebProviderEntryCredential,
providerRequiresCredential,
@@ -93,8 +94,8 @@ export function resolveWebFetchProviderId(params: {
}),
);
const raw =
params.fetch && "provider" in params.fetch && typeof params.fetch.provider === "string"
? params.fetch.provider.trim().toLowerCase()
params.fetch && "provider" in params.fetch
? normalizeLowercaseStringOrEmpty(params.fetch.provider)
: "";
if (raw) {

View File

@@ -9,6 +9,7 @@ import { resolveRuntimeWebSearchProviders } from "../plugins/web-search-provider
import { sortWebSearchProvidersForAutoDetect } from "../plugins/web-search-providers.shared.js";
import { getActiveRuntimeWebToolsMetadata } from "../secrets/runtime-web-tools-state.js";
import type { RuntimeWebSearchMetadata } from "../secrets/runtime-web-tools.types.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
import {
hasWebProviderEntryCredential,
providerRequiresCredential,
@@ -110,8 +111,8 @@ export function resolveWebSearchProviderId(params: {
}),
);
const raw =
params.search && "provider" in params.search && typeof params.search.provider === "string"
? params.search.provider.trim().toLowerCase()
params.search && "provider" in params.search
? normalizeLowercaseStringOrEmpty(params.search.provider)
: "";
if (raw) {