openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
461 lines (460 loc) • 16.4 kB
JavaScript
import { t as createLazyImportLoader } from "./lazy-promise-BONnzNfb.js";
import { p as normalizeUniqueStringEntries } from "./string-normalization-WNUDCpXX.js";
import { d as normalizeSecretInputString, o as coerceSecretRef } from "./types.secrets-_0JOMGE5.js";
import { i as resolveSecretRefString } from "./resolve-DPFnV1p0.js";
import "./agent-scope-MrLta7Pq.js";
import { a as resolveAgentDir, c as resolveDefaultAgentId, o as resolveAgentWorkspaceDir } from "./agent-scope-config-CgCYpZfK.js";
import { n as resolveDefaultAgentWorkspaceDir } from "./workspace-default-B3AjhIK3.js";
import { r as DEFAULT_PROVIDER } from "./defaults-mDjiWzE5.js";
import { n as ensureAuthProfileStore } from "./store-C8spD0DG.js";
import { l as resolveSessionTranscriptsDirForAgent, o as resolveSessionTranscriptPath } from "./paths-NEwU8m3X.js";
import { i as resolveAuthProfileDisplayLabel } from "./auth-profiles-84rzaGag.js";
import { o as externalCliDiscoveryScoped } from "./external-cli-discovery-Cr-vJMRB.js";
import { n as listProfilesForProvider } from "./profile-list-DI8_o0Rw.js";
import { i as resolveAuthProfileOrder, r as resolveAuthProfileEligibility } from "./order-CdBVYd7c.js";
import { c as parseModelRef, n as findNormalizedProviderValue, o as normalizeProviderId } from "./model-selection-normalize-roKDxQ9_.js";
import "./model-selection-CA_65iXi.js";
import { t as resolveEnvApiKey } from "./model-auth-env-O5hF4UJr.js";
import { n as loadModelCatalog } from "./model-catalog-0-HKr2yW.js";
import { u as hasUsableCustomProviderApiKey } from "./model-auth-DVfmdW0b.js";
import "./workspace-B0bmoo98.js";
import { a as describeFailoverError } from "./failover-error-DAwMDmz6.js";
import { i as formatMs } from "./shared-B3B7qn2l.js";
import { f as redactSecrets } from "./format-Bar-LTbU.js";
import fs from "node:fs/promises";
import crypto from "node:crypto";
//#region src/commands/models/list.probe.ts
/** Auth probe planning and execution helpers for model diagnostics. */
const PROBE_PROMPT = "Reply with OK. Do not use tools.";
const embeddedRunnerModuleLoader = createLazyImportLoader(() => import("./embedded-agent-By7LMHwp.js"));
function loadEmbeddedRunnerModule() {
return embeddedRunnerModuleLoader.load();
}
/** Maps runtime failover reasons into stable auth probe status buckets. */
function mapFailoverReasonToProbeStatus(reason) {
if (!reason) return "unknown";
if (reason === "auth" || reason === "auth_permanent") return "auth";
if (reason === "rate_limit" || reason === "overloaded") return "rate_limit";
if (reason === "billing") return "billing";
if (reason === "timeout") return "timeout";
if (reason === "model_not_found") return "format";
if (reason === "format") return "format";
return "unknown";
}
function buildCandidateMap(modelCandidates) {
const map = /* @__PURE__ */ new Map();
for (const raw of modelCandidates) {
const parsed = parseModelRef(raw ?? "", DEFAULT_PROVIDER);
if (!parsed) continue;
const list = map.get(parsed.provider) ?? [];
if (!list.includes(parsed.model)) list.push(parsed.model);
map.set(parsed.provider, list);
}
return map;
}
function catalogProbePriority(provider, modelId) {
const id = modelId.trim().toLowerCase();
if (provider !== "anthropic") return 50;
if (/^claude-haiku-4-5-\d{8}$/.test(id)) return 0;
if (id === "claude-haiku-4-5") return 1;
if (id === "claude-sonnet-4-6" || id.startsWith("claude-sonnet-4-6-")) return 2;
if (id.startsWith("claude-sonnet-4-")) return 3;
if (id.startsWith("claude-3-")) return 100;
return 50;
}
function selectProbeModel(params) {
const { provider, candidates, catalog } = params;
const direct = candidates.get(provider);
if (direct && direct.length > 0) return {
provider,
model: direct[0]
};
const fromCatalog = catalog.map((entry, index) => ({
entry,
index
})).filter(({ entry }) => normalizeProviderId(entry.provider) === provider).toSorted((left, right) => {
return catalogProbePriority(provider, left.entry.id) - catalogProbePriority(provider, right.entry.id) || left.index - right.index;
})[0]?.entry;
if (fromCatalog) return {
provider,
model: fromCatalog.id
};
return null;
}
function mapEligibilityReasonToProbeReasonCode(reasonCode) {
if (reasonCode === "missing_credential") return "missing_credential";
if (reasonCode === "expired") return "expired";
if (reasonCode === "invalid_expires") return "invalid_expires";
if (reasonCode === "unresolved_ref") return "unresolved_ref";
return "ineligible_profile";
}
function formatMissingCredentialProbeError(reasonCode) {
const legacyLine = "Auth profile credentials are missing or expired.";
if (reasonCode === "expired") return `${legacyLine}\n↳ Auth reason [expired]: token credentials are expired.`;
if (reasonCode === "invalid_expires") return `${legacyLine}\n↳ Auth reason [invalid_expires]: token expires must be a positive Unix ms timestamp.`;
if (reasonCode === "missing_credential") return `${legacyLine}\n↳ Auth reason [missing_credential]: no inline credential or SecretRef is configured.`;
if (reasonCode === "unresolved_ref") return `${legacyLine}\n↳ Auth reason [unresolved_ref]: configured SecretRef could not be resolved.`;
return `${legacyLine}\n↳ Auth reason [ineligible_profile]: profile is incompatible with provider config.`;
}
function resolveProbeSecretRef(profile, cfg) {
const defaults = cfg.secrets?.defaults;
if (profile.type === "api_key") {
if (normalizeSecretInputString(profile.key) !== void 0) return null;
return coerceSecretRef(profile.keyRef, defaults);
}
if (profile.type === "token") {
if (normalizeSecretInputString(profile.token) !== void 0) return null;
return coerceSecretRef(profile.tokenRef, defaults);
}
return null;
}
function formatUnresolvedRefProbeError(refLabel) {
return `Auth profile credentials are missing or expired.\n↳ Auth reason [unresolved_ref]: could not resolve SecretRef "${refLabel}".`;
}
async function maybeResolveUnresolvedRefIssue(params) {
if (!params.profile) return null;
const ref = resolveProbeSecretRef(params.profile, params.cfg);
if (!ref) return null;
try {
await resolveSecretRefString(ref, {
config: params.cfg,
env: process.env,
cache: params.cache
});
return null;
} catch {
return {
reasonCode: "unresolved_ref",
error: formatUnresolvedRefProbeError(`${ref.source}:${ref.provider}:${ref.id}`)
};
}
}
/** Builds probe targets plus preflight failures for missing/invalid credentials. */
async function buildProbeTargets(params) {
const { cfg, agentDir, providers, modelCandidates, options, workspaceDir } = params;
const store = ensureAuthProfileStore(agentDir, { externalCli: externalCliDiscoveryScoped({
config: cfg,
allowKeychainPrompt: false,
providerIds: providers,
profileIds: options.profileIds
}) });
const providerFilter = options.provider?.trim();
const providerFilterKey = providerFilter ? normalizeProviderId(providerFilter) : null;
const profileFilter = new Set(normalizeUniqueStringEntries(options.profileIds));
const refResolveCache = {};
const catalog = await loadModelCatalog({ config: cfg });
const candidates = buildCandidateMap(modelCandidates);
const targets = [];
const results = [];
for (const provider of providers) {
const providerKey = normalizeProviderId(provider);
if (providerFilterKey && providerKey !== providerFilterKey) continue;
const model = selectProbeModel({
provider: providerKey,
candidates,
catalog
});
const profileIds = listProfilesForProvider(store, providerKey);
const explicitOrder = (() => {
return findNormalizedProviderValue(store.order, providerKey) ?? findNormalizedProviderValue(cfg?.auth?.order, providerKey);
})();
const allowedProfiles = explicitOrder && explicitOrder.length > 0 ? new Set(resolveAuthProfileOrder({
cfg,
store,
provider: providerKey
})) : null;
const filteredProfiles = profileFilter.size ? profileIds.filter((id) => profileFilter.has(id)) : profileIds;
if (filteredProfiles.length > 0) {
for (const profileId of filteredProfiles) {
const profile = store.profiles[profileId];
const mode = profile?.type;
const label = resolveAuthProfileDisplayLabel({
cfg,
store,
profileId
});
if (explicitOrder && !explicitOrder.includes(profileId)) {
results.push({
provider: providerKey,
profileId,
model: model ? `${model.provider}/${model.model}` : void 0,
label,
source: "profile",
mode,
status: "unknown",
reasonCode: "excluded_by_auth_order",
error: "Excluded by auth.order for this provider."
});
continue;
}
if (allowedProfiles && !allowedProfiles.has(profileId)) {
const reasonCode = mapEligibilityReasonToProbeReasonCode(resolveAuthProfileEligibility({
cfg,
store,
provider: providerKey,
profileId
}).reasonCode);
results.push({
provider: providerKey,
model: model ? `${model.provider}/${model.model}` : void 0,
profileId,
label,
source: "profile",
mode,
status: "unknown",
reasonCode,
error: formatMissingCredentialProbeError(reasonCode)
});
continue;
}
const unresolvedRefIssue = await maybeResolveUnresolvedRefIssue({
cfg,
profile,
cache: refResolveCache
});
if (unresolvedRefIssue) {
results.push({
provider: providerKey,
model: model ? `${model.provider}/${model.model}` : void 0,
profileId,
label,
source: "profile",
mode,
status: "unknown",
reasonCode: unresolvedRefIssue.reasonCode,
error: unresolvedRefIssue.error
});
continue;
}
if (!model) {
results.push({
provider: providerKey,
model: void 0,
profileId,
label,
source: "profile",
mode,
status: "no_model",
reasonCode: "no_model",
error: "No model available for probe"
});
continue;
}
targets.push({
provider: providerKey,
model,
profileId,
label,
source: "profile",
mode
});
}
continue;
}
if (profileFilter.size > 0) continue;
const envKey = resolveEnvApiKey(providerKey, process.env, {
config: cfg,
workspaceDir
});
const hasUsableModelsJsonKey = hasUsableCustomProviderApiKey(cfg, providerKey);
if (!envKey && !hasUsableModelsJsonKey) continue;
const label = envKey ? "env" : "models.json";
const source = envKey ? "env" : "models.json";
const mode = envKey?.source.includes("OAUTH_TOKEN") ? "oauth" : "api_key";
if (!model) {
results.push({
provider: providerKey,
model: void 0,
label,
source,
mode,
status: "no_model",
reasonCode: "no_model",
error: "No model available for probe"
});
continue;
}
targets.push({
provider: providerKey,
model,
label,
source,
mode
});
}
return {
targets,
results
};
}
async function probeTarget(params) {
const { cfg, agentId, agentDir, workspaceDir, sessionDir, target, timeoutMs, maxTokens } = params;
if (!target.model) return {
provider: target.provider,
model: void 0,
profileId: target.profileId,
label: target.label,
source: target.source,
mode: target.mode,
status: "no_model",
reasonCode: "no_model",
error: "No model available for probe"
};
const model = target.model;
const sessionId = `probe-${target.provider}-${crypto.randomUUID()}`;
const sessionFile = resolveSessionTranscriptPath(sessionId, agentId);
await fs.mkdir(sessionDir, { recursive: true });
const start = Date.now();
const buildResult = (status, error) => ({
provider: target.provider,
model: `${model.provider}/${model.model}`,
profileId: target.profileId,
label: target.label,
source: target.source,
mode: target.mode,
status,
...error ? { error } : {},
latencyMs: Date.now() - start
});
try {
const { runEmbeddedAgent } = await loadEmbeddedRunnerModule();
await runEmbeddedAgent({
sessionId,
sessionFile,
agentId,
workspaceDir,
agentDir,
config: cfg,
prompt: PROBE_PROMPT,
provider: target.model.provider,
model: target.model.model,
authProfileId: target.profileId,
authProfileIdSource: target.profileId ? "user" : void 0,
timeoutMs,
runId: `probe-${crypto.randomUUID()}`,
lane: `auth-probe:${target.provider}:${target.profileId ?? target.source}`,
thinkLevel: "off",
reasoningLevel: "off",
verboseLevel: "off",
streamParams: { maxTokens },
disableTools: true,
modelRun: true,
cleanupBundleMcpOnRunEnd: true
});
return buildResult("ok");
} catch (err) {
const described = describeFailoverError(err);
return buildResult(mapFailoverReasonToProbeStatus(described.reason), redactSecrets(described.message));
}
}
async function runTargetsWithConcurrency(params) {
const { cfg, targets, timeoutMs, maxTokens, onProgress } = params;
const concurrency = Math.max(1, Math.min(targets.length || 1, params.concurrency));
const agentId = params.agentId ?? resolveDefaultAgentId(cfg);
const agentDir = params.agentDir ?? resolveAgentDir(cfg, agentId);
const workspaceDir = params.workspaceDir ?? resolveAgentWorkspaceDir(cfg, agentId) ?? resolveDefaultAgentWorkspaceDir();
const sessionDir = resolveSessionTranscriptsDirForAgent(agentId);
await fs.mkdir(workspaceDir, { recursive: true });
let completed = 0;
const results = Array.from({ length: targets.length });
let cursor = 0;
const worker = async () => {
while (true) {
const index = cursor;
cursor += 1;
if (index >= targets.length) return;
const target = targets[index];
onProgress?.({
completed,
total: targets.length,
label: `Probing ${target.provider}${target.profileId ? ` (${target.label})` : ""}`
});
results[index] = await probeTarget({
cfg,
agentId,
agentDir,
workspaceDir,
sessionDir,
target,
timeoutMs,
maxTokens
});
completed += 1;
onProgress?.({
completed,
total: targets.length
});
}
};
await Promise.all(Array.from({ length: concurrency }, () => worker()));
return results.filter((entry) => Boolean(entry));
}
/** Runs all auth probes with bounded concurrency and returns a summary. */
async function runAuthProbes(params) {
const startedAt = Date.now();
const plan = await buildProbeTargets({
cfg: params.cfg,
agentDir: params.agentDir,
workspaceDir: params.workspaceDir,
providers: params.providers,
modelCandidates: params.modelCandidates,
options: params.options
});
const totalTargets = plan.targets.length;
params.onProgress?.({
completed: 0,
total: totalTargets
});
const results = totalTargets ? await runTargetsWithConcurrency({
cfg: params.cfg,
agentId: params.agentId,
agentDir: params.agentDir,
workspaceDir: params.workspaceDir,
targets: plan.targets,
timeoutMs: params.options.timeoutMs,
maxTokens: params.options.maxTokens,
concurrency: params.options.concurrency,
onProgress: params.onProgress
}) : [];
const finishedAt = Date.now();
return {
startedAt,
finishedAt,
durationMs: finishedAt - startedAt,
totalTargets,
options: params.options,
results: [...plan.results, ...results]
};
}
/** Formats probe latency for table output. */
function formatProbeLatency(latencyMs) {
if (!latencyMs && latencyMs !== 0) return "-";
return formatMs(latencyMs);
}
/** Groups probe results by provider. */
function groupProbeResults(results) {
const map = /* @__PURE__ */ new Map();
for (const result of results) {
const list = map.get(result.provider) ?? [];
list.push(result);
map.set(result.provider, list);
}
return map;
}
/** Sorts probe results by provider and display label. */
function sortProbeResults(results) {
return results.slice().toSorted((a, b) => {
const provider = a.provider.localeCompare(b.provider);
if (provider !== 0) return provider;
const aLabel = a.label || a.profileId || "";
const bLabel = b.label || b.profileId || "";
return aLabel.localeCompare(bLabel);
});
}
/** Produces the terse completion line for auth probe output. */
function describeProbeSummary(summary) {
if (summary.totalTargets === 0) return "No probe targets.";
return `Probed ${summary.totalTargets} target${summary.totalTargets === 1 ? "" : "s"} in ${formatMs(summary.durationMs)}`;
}
//#endregion
export { buildProbeTargets, describeProbeSummary, formatProbeLatency, groupProbeResults, mapFailoverReasonToProbeStatus, runAuthProbes, sortProbeResults };