import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { resolveProviderIdForAuth } from "../provider-auth-aliases.js"; import { findNormalizedProviderValue, normalizeProviderId } from "../provider-id.js"; import {
evaluateStoredCredentialEligibility,
type AuthCredentialReasonCode,
} from "./credential-state.js"; import { dedupeProfileIds, listProfilesForProvider } from "./profile-list.js"; import type { AuthProfileStore } from "./types.js"; import {
clearExpiredCooldowns,
isProfileInCooldown,
resolveProfileUnusableUntil,
} from "./usage-state.js";
// Repair config/store profile-id drift from older setup flows: // if configured profile ids no longer exist in auth-profiles.json, scan the // provider's stored credentials and use any valid entries. const allBaseProfilesMissing = baseOrder.every((profileId) => !store.profiles[profileId]); if (filtered.length === 0 && explicitProfiles.length > 0 && allBaseProfilesMissing) { const storeProfiles = listProfilesForProvider(store, provider);
filtered = storeProfiles.filter(isValidProfile);
}
const deduped = dedupeProfileIds(filtered);
// If user specified explicit order (store override or config), respect it // exactly, but still apply cooldown sorting to avoid repeatedly selecting // known-bad/rate-limited keys as the first candidate. if (explicitOrder && explicitOrder.length > 0) { // ...but still respect cooldown tracking to avoid repeatedly selecting a // known-bad/rate-limited key as the first candidate. const available: string[] = []; const inCooldown: Array<{ profileId: string; cooldownUntil: number }> = [];
for (const profileId of deduped) { if (isProfileInCooldown(store, profileId)) { const cooldownUntil =
resolveProfileUnusableUntil(store.usageStats?.[profileId] ?? {}) ?? now;
inCooldown.push({ profileId, cooldownUntil });
} else {
available.push(profileId);
}
}
// Still put preferredProfile first if specified if (preferredProfile && ordered.includes(preferredProfile)) { return [preferredProfile, ...ordered.filter((e) => e !== preferredProfile)];
} return ordered;
}
// Otherwise, use round-robin: sort by lastUsed (oldest first) // preferredProfile goes first if specified (for explicit user choice) // lastGood is NOT prioritized - that would defeat round-robin const sorted = orderProfilesByMode(deduped, store);
if (preferredProfile && sorted.includes(preferredProfile)) { return [preferredProfile, ...sorted.filter((e) => e !== preferredProfile)];
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.